1

我有一个用柠檬写的小语法,导致解析冲突。

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

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

我已经看到了这个答案,但它只适用于野牛/yacc 我不知道如何在柠檬中复制它。

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

提前致谢。

4

2 回答 2

2

Lemon以与 Bison 相似但不完全相同的方式实现优先规则,并且该功能可用于解决您遇到的“悬空其他”移位/减少冲突,因为它通常应用于野牛。

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

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

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

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

综上所述,您可以将Bison 解决方案应用于 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

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

于 2019-08-13T16:01:48.010 回答
1

所写的语法模棱两可且不正确,因为您实际上不希望在另一个 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 无需像这样重构语法即可工作。

于 2019-08-13T13:05:34.143 回答