我对来自维基百科的以下quote感到困惑:
换句话说,如果一种语言足够合理,可以允许 有效的一次通过解析器,它可以用LR(k)语法描述。 而且这种语法总是可以机械地转化为一种语法 等效(但更大)LR(1)语法。所以LR(1)解析方法是, 从理论上讲,它足以处理任何合理的语言。在 实践,许多编程语言的自然语法是 接近LR(1)。[需要引证]
这意味着解析器生成器(如bison
)非常强大(因为它可以处理LR(k)
语法),如果能够将LR(k)
语法转换为{LR(1)
语法1}}语法。有一些这方面的例子,或者如何做到这一点的方法?我想知道这个,因为我的语法中有一个shift / reduce冲突,但我认为这是因为它是一个LR(2)
语法,并希望将它转换为LR(1)
语法。旁边的问题:C++
是一种不合理的语言,因为我读过,bison
- 生成的解析器无法解析它。
答案 0 :(得分:1)
有关通用算法的参考资料,以查找LR(1)
语法的覆盖LR(k)
语法,请参阅Real-world LR(k > 1) grammars?
通用算法产生相当大的语法;事实上,我很确定生成的PDA与LR(k)
PDA的大小相同。但是,在特定情况下,可以提出更简单的解决方案。但是,一般原则适用:您需要通过无条件转移来推迟转移/减少决策,直到可以使用单个先行令牌做出决定。
一个例子:Is C#'s lambda expression grammar LALR(1)?
在不了解有关语法的更多细节的情况下,我无法提供更多帮助。
关于C ++,使解析变得棘手的事情是预处理器和解析(和lexing)模板实例化的一些极端情况。表达式的解析依赖于符号的“种类”(不是类型)(在符号出现的上下文中)这一事实使得对野牛的精确解析变得复杂。 [1]“不合理”是一种我不太习惯的价值判断;当然,工具支持(如准确的语法着色器和制表符完成程序)使用不同的语法会很简单,但有证据表明编写(甚至读取)优秀的C ++代码并不困难。
注意:
[1]经典棘手的解析,也适用于C,是(a)*b
,如果a
代表一种类型,它是一个解除引用的强制转换,否则是乘法。如果您要在上下文中编写它:c/(a)*b
,很明显,如果不知道它是演员表还是产品,就无法构建AST,因为这会影响AST的形状,
更具C ++特色的问题是:x<y>(z)
(或x<y<z>>(3)
)根据x
是否为模板命名而对其进行不同的分析(并且可以说是标记)。