【问题标题】:LR(k) to LR(1) grammar conversionLR(k) 到 LR(1) 语法转换
【发布时间】:2013-12-19 14:01:50
【问题描述】:
我对来自维基百科的以下quote 感到困惑:
换句话说,如果一种语言足够合理,可以允许
高效的一次性解析器,它可以用 LR(k) 文法来描述。
这种语法总是可以机械地转化为
等效(但更大)LR(1)语法。所以一个 LR(1) 解析方法是,
理论上,强大到足以处理任何合理的语言。在
实践中,许多编程语言的自然语法是
接近 LR(1)。[需要引用]
这意味着解析器生成器,如bison,非常强大(因为它可以处理LR(k) 语法),如果能够将LR(k) 语法转换为LR(1) 语法。是否存在一些这样的例子,或者如何做到这一点的秘诀?我想知道这一点,因为我的语法中有移位/减少冲突,但我认为这是因为它是 LR(2) 语法并且想将其转换为 LR(1) 语法。附带问题:C++ 是一种不合理的语言,因为我读过,bison 生成的解析器无法解析它。
【问题讨论】:
标签:
parsing
compiler-construction
bison
lr
【解决方案1】:
有关为LR(k) 语法查找覆盖LR(1) 语法的通用算法的参考,请参阅Real-world LR(k > 1) grammars?
通用算法产生相当大的文法;事实上,我很确定生成的 PDA 与LR(k) PDA 的大小相同。但是,在特定情况下,可以提出更简单的解决方案。不过,一般原则适用:您需要通过无条件转移来推迟转移/减少决策,直到可以使用单个前瞻令牌做出决策。
一个例子:Is C#'s lambda expression grammar LALR(1)?
如果不了解您的语法的更多细节,我真的无能为力。
对于 C++,难以解析的是预处理器和解析(和词法分析)模板实例化中的一些极端情况。表达式的解析取决于符号的“种类”(而不是类型)(在符号出现的上下文中)这一事实使得使用野牛进行精确解析变得复杂。 [1] “不合理”是我不习惯做出的价值判断;当然,如果使用不同的语法,工具支持(如准确的语法着色器和制表符完成器)会很简单,但有证据表明编写(甚至阅读)好的 C++ 代码并不难。
注意事项:
[1] 也适用于 C 的经典棘手解析是 (a)*b,如果 a 表示类型,则它是取消引用的强制转换,否则表示乘法。如果您要在上下文中编写它:c/(a)*b,很明显,在不知道它是铸件还是产品的情况下无法构造 AST,因为这会影响 AST 的形状,
一个更具体的 C++ 问题是:x<y>(z)(或 x<y<z>>(3))根据 x 是否命名模板而不同地解析(并且可以说是标记化)。