野牛移位/减少问题将添加操作移动到子表达式中

发布于 2024-08-06 02:50:33 字数 567 浏览 2 评论 0原文

最初在示例中,

expr:
        INTEGER
        | expr '+' expr           { $$ = $1 + $3; }
        | expr '-' expr           { $$ = $1 - $3; }
        ;

我希望它“更简单”,所以我写了这个(我意识到它会为加法和减法执行“+”。但这只是一个例子)

expr:
        INTEGER
        | expr addOp expr           { $$ = $1 + $3; }
        ;

addOp:
          '+' { $$ = $1; }
        | '-' { $$ = $1; }
        ;

现在我得到了一个移位/减少错误。应该是一模一样的-_-(对我来说)。我需要做什么来解决这个问题?

编辑:为了把事情说清楚。第一个没有警告/错误。我使用 %left 来设置优先级(并且我将使用 %right 来表示 = 和其他右操作)。然而,当进入子表达式时,它似乎不适用。

Originally in the example there was this

expr:
        INTEGER
        | expr '+' expr           { $ = $1 + $3; }
        | expr '-' expr           { $ = $1 - $3; }
        ;

I wanted it to be 'more simple' so i wrote this (i realize it would do '+' for both add and subtract. But this is an example)

expr:
        INTEGER
        | expr addOp expr           { $ = $1 + $3; }
        ;

addOp:
          '+' { $ = $1; }
        | '-' { $ = $1; }
        ;

Now i get a shift/reduce error. It should be exactly the same -_- (to me). What do i need to do to fix this?

edit: To make things clear. The first has NO warning/error. I use %left to set the precedence (and i will use %right for = and those other right ops). However it seems to not apply when going into sub expressions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(2

太阳哥哥 2024-08-13 02:50:33

您确定冲突仅涉及这两条规则吗?第一个应该比第二个有更多的冲突。至少使用一个前瞻符号,第二次决定转移到堆栈上有 addOp 的状态会更容易。

更新(我相信我可以证明我的理论...:-):

$ cat q2.y
%% expr: '1' | expr '+' expr | expr '-' expr;
$ cat q3.y
%%  expr: '1' | expr addOp expr;
    addOp: '+' | '-';
$ yacc q2.y
conflicts: 4 shift/reduce
$ yacc q3.y
conflicts: 2 shift/reduce

话虽如此,yacc 语法有歧义是正常的,任何现实生活中的系统都可能不仅仅是一个很少但实际上是数十的转移/减少冲突。根据定义,当存在完全有效的移位可用时,就会发生这种冲突,因此,如果您不介意解析器采用该移位,则不必担心。

现在,在 yacc 中,您应该更喜欢左递归规则。您可以通过以下方式实现这一点消除语法歧义:

$ cat q4.y
%% expr: expr addOp '1' | '1';
  addOp: '+' | '-';
$ yacc q4.y
$ 

注意:上面的示例中没有冲突。如果您喜欢现有的语法,只需执行以下操作:

 %expect 2
%%  expr: '1' | expr addOp expr;
    addOp: '+' | '-';

Are you sure the conflicts involve just those two rules? The first one should have more conflicts than the second. At least with one symbol of look-ahead the decision to shift to a state with addOp on the stack is easier the second time around.

Update (I believe I can prove my theory... :-):

$ cat q2.y
%% expr: '1' | expr '+' expr | expr '-' expr;
$ cat q3.y
%%  expr: '1' | expr addOp expr;
    addOp: '+' | '-';
$ yacc q2.y
conflicts: 4 shift/reduce
$ yacc q3.y
conflicts: 2 shift/reduce

Having said all that, it's normal for yacc grammars to have ambiguities, and any real-life system is likely to have not just a few but literally dozens of shift/reduce conflicts. By definition, this conflict occurs when there is a perfectly valid shift available, so if you don't mind the parser taking that shift, then don't worry about it.

Now, in yacc you should prefer left-recursive rules. You can achieve that and get rid of your grammar ambiguity with:

$ cat q4.y
%% expr: expr addOp '1' | '1';
  addOp: '+' | '-';
$ yacc q4.y
$ 

Note: no conflicts in the example above. If you like your grammar the way it is, just do:

 %expect 2
%%  expr: '1' | expr addOp expr;
    addOp: '+' | '-';
锦爱 2024-08-13 02:50:33

问题是该规则

expr: expr addOp expr { ..action.. }

没有优先权。通常规则会获得 RHS 上第一个标记的优先级,但此规则的 RHS 上没有标记。您需要向其添加 %prec 指令:

expr: expr addOp expr %prec '+' { ..action.. }

以显式赋予规则优先级。

请注意,这样做并不能消除原始语法中存在的移位/归约冲突。它只是根据您指定的优先级规则来解析它,这意味着 bison 不会给您有关它的消息。一般来说,使用优先级来解决冲突可能很棘手,因为它可能隐藏您可能想要以不同方式解决的冲突,或者在您编写的语法中可能无法解决的冲突。

另请参阅我对这个问题的回答

The problem is that the rule

expr: expr addOp expr { ..action.. }

has no precedence. Normally rules get the precedence of the first token on the RHS, but this rule has no tokens on its RHS. You need to add a %prec directive to it:

expr: expr addOp expr %prec '+' { ..action.. }

to explicitly give the rule a precedence.

Note that doing this doesn't get rid of the shift/reduce conflict, which was present in your original grammar. It just resolves it according to the precedence rules you specify, which means that bison won't give you a message about it. In general, using precedence to resolve conflicts can be tricky, since it can hide conflicts that you might have wanted to resolve differently, or might be unresolvable in your grammar as written.

Also see my answer to this question

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