如何解决此解析冲突?

How do I fix this parsing conflict?

我有一个用 lemon 编写的小语法导致解析冲突。

这是导致冲突的语法部分:

selection_statement ::= KWD_IF LPAREN expression RPAREN statement.
selection_statement ::= KWD_IF LPAREN expression RPAREN statement KWD_ELSE statement.

我看过 this 答案,但它只适用于 bison/yacc 我不知道如何在柠檬中复制它。

解决此解析冲突的最佳方法是什么?

提前致谢。

所写的语法含糊不清且不正确,因为您实际上不想让没有 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

它既复杂又繁琐,如果您有多种类型的语句(如 if...else),情况会变得更糟,这就是为什么人们通常依赖解析器生成器中的默认冲突解决方案。

解析器生成器工具的作者知道这一点,所以几乎每个解析器生成器都有冲突解决规则,使 if...else 无需像这样重构语法就可以工作。

Lemon 实现了您遇到的 precedence rules in a way that is similar but not quite identical to Bison, and that feature can be used to resolve the "dangling else" shift/reduce 冲突,因为它通常应用于 bison。

Lemon 和 Bison 优先级声明之间有两个主要区别:

  1. Bison 提供 %precedence 作为 %left%right%nonassoc 的替代方案。但是,%nonassoc 通常可以用在 %precedence 更合适的任何地方。

  2. 在 Bison 中,您可以使用 %prec TERMINAL 显式声明产生式的优先级。在 Lemon 中,您可以通过在产生式之后放置 [TERMINAL] 来做同样的事情。 (这在上面链接的手册的优先规则部分中有解释。)

此外,Bison 允许您在终端中使用双引号字符串,这是 Lemon 中不可用的功能。

综上所述,您可以按如下方式使 Bison solution 适应 Lemon:

/* 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

也可以使语法明确无歧义,但工作量要大一些。在链接的维基百科条目中有一个如何做到这一点的例子。