野牛减少/减少
我是 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个reduce/reduce冲突。
当然,如果我像这样重写composite_expr规则......
composite_expr:
expr '+' expr
| '~' expr { /* ??? */ }
;
那么就没有冲突,但现在我不能调用 do_something_1()
或 do_something_2()
因为我无法再判断 expr
是 variable_expr
还是 composite_expr
。
还有其他方法可以做到这一点吗?谁能解释为什么首先要减少/减少冲突?
请记住,这是一个精简版本,实际上,规则 composite_expr
非常长。所以复制它是不可能的。
I am new to Bison parsing and I cannot understand how it works. I have the following grammar, where I have kept the bare minimum to highlight the problem.
%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(); }
;
%%
As you can see, I want to apply different functions to the '~'
operator depending on the kind of expression that follows. However, this produces 2 reduce/reduce conflicts.
Of course, if I rewrite the composite_expr rule like this...
composite_expr:
expr '+' expr
| '~' expr { /* ??? */ }
;
...then there are no conflicts, but now I cannot call either do_something_1()
or do_something_2()
because I can no longer tell if expr
is variable_expr
or composite_expr
.
Is there any other way that I can do this? Can anyone explain why there where reduce/reduce conflicts in the first place?
Keep in mind that this is a stripped down version and, in reality, the rule composite_expr
is very long. So duplicating it is out of the question.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
基本问题是您的语法不明确,并且您(尝试)使用优先级规则来解决歧义性,但它失败了,因为歧义性表现为归约/归约冲突,并且优先级规则在这种情况下毫无用处。您可以通过使用 bison 的
-v
选项获取其构建的状态机列表来更好地了解正在发生的情况,这样您就可以准确地看到冲突在何处以及如何体现。在这种情况下,您将看到类似以下内容:
这告诉您它不知道在
+
的前瞻中减少哪个规则。现在显然从你的优先级规则来看,你需要规则 6(因为~
的优先级高于+
),但是 bison 中的优先级消歧规则有点破解,可以'无法处理这个问题——它无法理解减少规则 3 将导致在减少将消耗~
的规则之前移动+
。那么你能对此做些什么呢?您可以接受冲突的存在并制定规则,以便正确的事情发生。在这种情况下,您需要移动表达式:composite_expr | Variable_expr 规则到最后(至少到
composite_expr
规则之后)。这有点丑陋,难以理解,更难维护。或者,您可以对事物进行分解以摆脱单个规则(具有单个非终结符且右侧没有其他内容的规则 - 这些是往往会触发归约/归约问题的规则。)类似于:
这不太可能如果有许多像您描述的那样的
composite_expr
规则,那么要实用。最好的选择可能是根本不在语法中这样做,而是根据您的语义规则进行选择。类似于:
您将
expr
的%type
设置为一个带有额外bool isComposite
字段以及您使用的其他内容的结构体为了。The basic problem is that you have an ambiguous grammar, and you're (attempting to) use precedence rules to resolve the ambiguity, but it fails because the ambiguity manifests as a reduce/reduce conflict, and precedence rules are useless in that case. You can get a better idea what is going on by using bison's
-v
option to get a listing of the state machine it builds, so you can see exactly where and how the conflict manifests.In this case, you'll see something like:
which is telling you it doesn't know which rule to reduce on a lookahead of
+
. Now obviously from your predence rules you want rule 6 (since~
is higher precedence than+
), but the precedence disambiguation rules in bison are a bit of a hack and can't deal with this -- it fails to understand that reducing rule 3 will result in shifting the+
before reducing a rule that will consume the~
.So what can you do about this? You can accept the existence of the conflict and order your rules so the right thing happens. In this case, you need to move the
expr: composite_expr | variable_expr
rule to the end (at least to after thecomposite_expr
rules). This is kind of ugly, hard to understand, and even harder to maintain.Alternately, you can unfactor things to get rid of the single rules (rules with a single non-terminal and nothing else on the right side -- these are the rules that tend to trigger reduce/reduce problems.) Something like:
This is unlikely to be practical if there are many
composite_expr
rules like you describe.The best alternative is likely to be to not do this is in the grammar at all, and instead make the choice based on your semantic rules. Something like:
and you setup the
%type
forexpr
to be a struct with an extrabool isComposite
field along with whatever else you were using it for.