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

競合にはこれら2つのルールだけが関係していると思いますか?最初のものは、2番目のものよりも多くの競合があるはずです。少なくとも先読みのシンボルが1つあれば、スタックにaddOpがある状態に移行するという決定は2回目は簡単です。

更新(私は私の理論を証明できると信じています... :-):

$ 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: '+' | '-';
于 2009-10-03T20:00:09.767 に答える
1

問題はそのルール

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

優先順位はありません。通常、ルールは RHS の最初のトークンの優先順位を取得しますが、このルールには RHS にトークンがありません。%prec ディレクティブを追加する必要があります。

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

ルールを明示的に優先します。

これを行っても、元の文法に存在していた shift/reduce の競合が解消されないことに注意してください。指定した優先ルールに従って解決するだけです。つまり、bison はそれに関するメッセージを表示しません。一般に、優先順位を使用して競合を解決するのは難しい場合があります。別の方法で解決したかった競合や、書かれた文法では解決できない可能性がある競合を隠してしまう可能性があるからです。

この質問に対する私の回答も参照してください

于 2009-10-06T18:44:12.353 に答える