我有一个用柠檬写的小语法,它导致了解析冲突。
这是导致冲突的语法部分:
selection_statement ::= KWD_IF LPAREN expression RPAREN statement.
selection_statement ::= KWD_IF LPAREN expression RPAREN statement KWD_ELSE statement.
我已经看到了这个答案,但它仅适用于野牛/yacc,我不知道如何在柠檬中复制它。
解决此解析冲突的最佳方法是什么?
提前谢谢。
Lemon 以与 Bison 相似但不完全相同的方式实现优先级规则,该功能可用于解决您遇到的"悬空其他"移位/减少冲突,因为它通常应用于野牛。
柠檬和野牛优先声明之间有两个主要区别:
-
野牛提供
%precedence
作为%left
、%right
和%nonassoc
的替代品。但是,%nonassoc
通常可以在%precedence
更合适的任何地方使用。 -
在 Bison 中,您可以使用
%prec TERMINAL
显式声明生产的优先级。在Lemon中,您可以通过在生产后放置[TERMINAL]
来做同样的事情。(这在上面链接的手册的优先规则部分中进行了说明。
此外,Bison允许您对终端使用双引号字符串,这是Lemon中不可用的功能。
综上所述,您可以将Bison解决方案适应柠檬,如下所示:
/* LEMON (non-terminals abbreviated) */ /* Bison (from linked answer) */
%nonassoc KWD_IF %nonassoc "then"
%nonassoc KWD_ELSE %nonassoc "else"
%% %%
sel: KWD_IF LPAREN exp RPAREN stm. [KWD_ELSE] stm: "if" "(" exp ")" stm %prec "then"
| KWD_IF LPAREN exp RPAREN stm KWD_ELSE stm. | "if" "(" exp ")" stm "else" stm
也可以使语法明确,但这需要做更多的工作。在链接的维基百科条目中有一个关于悬空的例子。
编写的语法模棱两可且不正确,因为您实际上不想允许在另一个 ELSE 前面没有 ELSE 的选择语句。 在这种情况下,else 应绑定到内部选择语句。
你可以这样修复它:
statement ::= open_sel
statement ::= closed_sel
statement ::= other
open_sel ::= KWD_IF LPAREN expression RPAREN open_sel
open_sel ::= KWD_IF LPAREN expression RPAREN other
closed_sel ::= KWD_IF LPAREN expression RPAREN closed_sel
closed_sel ::= KWD_IF LPAREN expression RPAREN closed_sel KWD_ELSE statement
closed_sel ::= KWD_IF LPAREN expression RPAREN other KWD_ELSE statement
它既复杂又挑剔,如果你有多种陈述,比如如果......否则,这就是为什么人们通常依赖解析器生成器中的默认冲突解决。
解析器生成器工具的作者都知道这一点,因此几乎每个解析器生成器都有冲突解决规则,如果...否则无需像这样重构语法即可工作。