有一个更简单的解决方案。如果你知道 LR 解析器是如何工作的,那么你就会知道冲突发生在这里:
if ( expression ) statement * else statement
其中星号标记光标的当前位置。解析器必须回答的问题是“我应该转移,还是应该减少”。通常,您希望将 绑定else
到最近的if
,这意味着您现在要移动else
令牌。现在减少意味着您希望else
等待绑定到“旧” if
。
现在您想“告诉”您的解析器生成器“当令牌"else"
与规则“stm -> if (exp) stm”之间存在移位/减少冲突时,那么令牌必须获胜”。为此,请为您的规则的优先级“命名”(例如"then"
),并指定其"then"
优先级低于"else"
. 就像是:
// Precedences go increasing, so "then" < "else".
%nonassoc "then"
%nonassoc "else"
%%
stm: "if" "(" exp ")" stm %prec "then"
| "if" "(" exp ")" stm "else" stm
使用 Bison 语法。
我对%nonassoc
这里感到不安,因为它确实这么说"then"
并且"else"
是非关联的,这在大多数语法中都是如此,但我只是想给它们优先级,而不是关联性。野牛%precedence
为此提供:
// Precedences go increasing, so "then" < "else".
%precedence "then"
%precedence "else"
%%
stm: "if" "(" exp ")" stm %prec "then"
| "if" "(" exp ")" stm "else" stm
实际上,我最喜欢的答案是甚至给予"then"
和"else"
相同的优先级。当优先级相等时,为了打破想要移动的令牌和想要减少的规则之间的联系,Bison/Yacc 将查看关联性。在这里,可以说是要促进右结合性(更准确地说,是要促进“转变”),所以:
%right "then" "else" // Same precedence, but "shift" wins.
就足够了。