野牛减少/减少

发布于 2024-11-23 22:03:01 字数 876 浏览 0 评论 0原文

我是 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()因为我无法再判断 exprvariable_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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

听风吹 2024-11-30 22:03:01

基本问题是您的语法不明确,并且您(尝试)使用优先级规则来解决歧义性,但它失败了,因为歧义性表现为归约/归约冲突,并且优先级规则在这种情况下毫无用处。您可以通过使用 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(因为 ~ 的优先级高于 +),但是 bison 中的优先级消歧规则有点破解,可以'无法处理这个问题——它无法理解减少规则 3 将导致在减少将消耗 ~ 的规则之前移动 +

那么你能对此做些什么呢?您可以接受冲突的存在并制定规则,以便正确的事情发生。在这种情况下,您需要移动表达式: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; }
;

您将 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:

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)

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 the composite_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:

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(); }
;

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:

expr:   
     expr '+' expr      { $.isComposite = true; }
   | '~' expr           { if ($2.isComposite)
                              do_something_2();
                          else
                              do_something_1();
                          $.isComposite = true; }
   | T_VARIABLE         { $.isComposite = false; }
;

and you setup the %type for expr to be a struct with an extra bool isComposite field along with whatever else you were using it for.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文