lin*_*ogl 4 bison reduce-reduce-conflict
我是 Bison 解析的新手,我无法理解它是如何工作的。我有以下语法,其中我保留了最低限度的语法来突出问题。
%left '~'
%left '+'
%token T_VARIABLE
%%
start: expr;
expr: composite_expr | variable_expr;
variable_expr: T_VARIABLE;
composite_expr:
expr '+' expr
| '~' variable_expr { do_something_1(); }
| '~' composite_expr { do_something_2(); }
;
%%
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我想'~'
根据后面的表达式类型对运算符应用不同的函数。然而,这会产生2个reduce/reduce冲突。
当然,如果我像这样重写composite_expr规则......
composite_expr:
expr '+' expr
| '~' expr { /* ??? */ }
;
Run Code Online (Sandbox Code Playgroud)
...然后就没有冲突了,但现在我不能调用 or ,do_something_1()
因为do_something_2()
我无法再判断expr
isvariable_expr
或composite_expr
。
还有其他方法可以做到这一点吗?谁能解释为什么首先要减少/减少冲突?
请记住,这是一个精简版本,实际上,规则composite_expr
很长。所以复制它是不可能的。
基本问题是您的语法不明确,并且您(尝试)使用优先级规则来解决歧义性,但它失败了,因为歧义性表现为归约/归约冲突,并且优先级规则在这种情况下毫无用处。-v
通过使用 bison 的选项来获取它构建的状态机的列表,您可以更好地了解正在发生的情况,这样您就可以准确地看到冲突在哪里以及如何体现。
在这种情况下,您会看到类似以下内容:
state 8
3 expr: variable_expr .
6 composite_expr: '~' variable_expr .
$end reduce using rule 6 (composite_expr)
'+' reduce using rule 3 (expr)
'+' [reduce using rule 6 (composite_expr)]
$default reduce using rule 3 (expr)
Run Code Online (Sandbox Code Playgroud)
这告诉您它不知道在前瞻中要减少哪个规则+
。现在显然从你的优先级规则中你想要规则6(因为~
优先级高于+
),但是野牛中的优先级消歧规则有点黑客,无法处理这个问题——它无法理解减少规则3会导致在减少+
将消耗 的规则之前移动~
.
那么你能对此做些什么呢?您可以接受冲突的存在并制定规则,以便正确的事情发生。在这种情况下,您需要将expr: composite_expr | variable_expr
规则移至末尾(至少移至composite_expr
规则之后)。这有点丑陋,难以理解,更难维护。
或者,您可以对事物进行分解以摆脱单个规则(具有单个非终结符且右侧没有其他内容的规则 - 这些是往往会触发归约/归约问题的规则。),例如:
composite_expr:
composite_expr '+' composite_expr
| composite_expr '+' variable_expr
| variable_expr '+' composite_expr
| variable_expr '+' variable_expr
| '~' variable_expr { do_something_1(); }
| '~' composite_expr { do_something_2(); }
;
Run Code Online (Sandbox Code Playgroud)
composite_expr
如果有很多像您描述的规则,这不太可能实用。
最好的选择可能是根本不在语法中这样做,而是根据您的语义规则进行选择。就像是:
expr:
expr '+' expr { $$.isComposite = true; }
| '~' expr { if ($2.isComposite)
do_something_2();
else
do_something_1();
$$.isComposite = true; }
| T_VARIABLE { $$.isComposite = false; }
;
Run Code Online (Sandbox Code Playgroud)
并且您将%type
for设置expr
为一个带有额外bool isComposite
字段的结构以及您使用它的其他内容。