3

最初在示例中是这样的

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

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

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

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

现在我得到一个移位/减少错误。它应该完全相同-_-(对我来说)。我需要做什么来解决这个问题?

编辑:说清楚。第一个没有警告/错误。我使用 %left 来设置优先级(我将使用 %right 来表示 = 和其他正确的操作)。但是,当进入子表达式时,它似乎并不适用。

4

2 回答 2

1

问题是规则

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

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

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

明确地赋予规则优先级。

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

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

于 2009-10-06T18:44:12.353 回答
1

你确定冲突只涉及这两个规则吗?第一个应该比第二个有更多的冲突。至少使用一个前瞻符号,第二次切换到堆栈上带有 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 语法有歧义是很正常的,任何现实生活中的系统都可能不仅有几个,而且实际上有几十个 shift/reduce 冲突。根据定义,当有一个完全有效的移位可用时,就会发生这种冲突,所以如果你不介意解析器进行那个移位,那就不用担心了。

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

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

注意:以上示例中没有冲突。如果你喜欢你的语法,就这样做:

 %expect 2
%%  expr: '1' | expr addOp expr;
    addOp: '+' | '-';
于 2009-10-03T20:00:09.767 回答