我是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(); }
;
%%
如您所见,我想根据后面的表达式将'~'
运算符应用于不同的函数。但是,这会产生2个减少/减少冲突。
当然,如果我像这样重写composite_expr规则......
composite_expr:
expr '+' expr
| '~' expr { /* ??? */ }
;
...然后没有冲突,但现在我无法拨打do_something_1()
或do_something_2()
,因为我无法再判断expr
是variable_expr
还是{{} 1}}。
我还有其他办法吗?任何人都可以解释为什么首先在哪里减少/减少冲突?
请记住,这是一个精简版本,实际上,规则composite_expr
非常长。所以复制它是不可能的。
答案 0 :(得分:4)
基本问题是你有一个模糊的语法,并且你(试图)使用优先级规则来解决歧义,但它失败了,因为模糊性表现为减少/减少冲突,优先规则在那种情况。通过使用bison的-v
选项获取其构建的状态机列表,您可以更好地了解正在发生的事情,这样您就可以确切地看到冲突的显示位置和方式。
在这种情况下,您会看到类似的内容:
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)
告诉你它不知道在+
的前瞻中要减少哪条规则。现在很明显,根据您之前的规则,您需要规则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(); }
;
如果您描述的composite_expr
规则很多,则这不太可行。
最好的替代方案可能是根本不在语法中,而是根据你的语义规则做出选择。类似的东西:
expr:
expr '+' expr { $$.isComposite = true; }
| '~' expr { if ($2.isComposite)
do_something_2();
else
do_something_1();
$$.isComposite = true; }
| T_VARIABLE { $$.isComposite = false; }
;
并且您将%type
的{{1}}设置为具有额外expr
字段的结构以及您正在使用它的其他内容。