2012-10-04 1 views
17

与えられた文法のためにbisonのshift-reduce競合を取り除くにはどうすればよいですか?if-then-elseでshiftを減らすために文法を改訂する

selection-stmt -> if (expression) statement | 
         if (expression) statement else statement 

修正された文法を与える解決策が高く評価されます。

+0

、[このページ](http://www.tldp.org/HOWTO/Lex-YACC-HOWTO-7: –

答えて

34

はるかに簡単な解決法があります。あなたはLRパーサがどのように機能するかを知っている場合は、競合がここで起こることを知っている:

if (expression) statement * else statement 
スターは、カーソルの現在位置をマークし

。パーザが答えなければならない質問は、 "私は変わるべきか、減らすべきか"です。通常、elseを最も近いifにバインドします。つまり、今すぐelseトークンを移動する必要があります。今すぐ減らすことは、elseが "古い" ifにバインドされるのを待つことを意味します。

パーサージェネレータに "トークン"else"とルール" stm - > if(exp)stm "の間にシフト/リダクションの競合がある場合、トークンが勝つ必要があります。そうするには、ルールの優先順位に「名前を付ける」(例:"then")。"then""else"より優先度が低いと指定します。次のようなものがあります。

// Precedences go increasing, so "then" < "else". 
%nonassoc "then" 
%nonassoc "else" 
%% 
stm: "if" "(" exp ")" stm   %prec "then" 
    | "if" "(" exp ")" stm "else" stm 

Bison構文を使用します。

実際、私の好きな答えは、"then""else"に同じ優先順位を付けることさえあります。優先順位が等しい場合、シフトしたいトークンと縮小したいルールとの間の繋がりを壊すために、Bison/Yaccは結合性を調べます。ここでは、そう、(より正確には、あなたが「シフト」を推進したい)いわば、右結合性を促進したい:

%right "then" "else" // Same precedence, but "shift" wins. 

は十分です。今後の個人のための

statements: 
    statements lineEnd statement 
| statements lineEnd IfStat 
| statements lineEnd IfElseStat 
| IfStat 
| IfElseStat 
; 
IfStat: 
    if (statement) 
; 
IfElse: 
    IfStat else statement 
; 
+0

は、次のように文の後の非末端Nが存在する場合、私は同じ行うことができます方法: IF_KEYWORD「(」式のN「)」ここでM声明N ELSE_KEYWORD M声明 は、MとNは非終端記号です。 – Vishwas

+0

@VishwasJainそれはあなたのif-thenルールに依存します。 '' else '' M ''部分がオプションである場合、同じアプローチが適用されるべきです。 – akim

4

あなたがいる場合ダングリングのif-else場合によっては(またはで終わる)することができないでいる途中statement事実を認識する必要がある(ANがない場合は、他と。)それを行うための最も簡単な方法は、stmtルールを分割することです二つに:

stmt -> stmt-ending-with-dangling-if | stmt-not-ending-with-dangling-if 
stmt-not-ending-with-dangling-if -> 
    if (expression) stmt-not-ending-with-dangling-if else stmt-not-ending-with-dangling-if | 
    ...other statements not ending with dangling if... 
stmt-ending-with-dangling-if -> 
    if (expression) stmt | 
    if (expression) stmt-not-ending-with-dangling-if else stmt-ending-with-dangling-if | 
    ...other statements ending with dangling if... 

whateverstmtで終わっていないその他のstmt -> whateverルールは、2つのバージョンがstmt GET分割で終了しないすべてのstmtルールながら、stmt-not-ending-with-ifルールに進み、 ルールのnot-ending-with-ifバージョンとdangling-ifルールのdangling-ifバージョンです。

編集

他の作品とのより完全な文法:WHILE (expr) stmtよう

stmt : stmt-ending-with-dangling-if | stmt-not-ending-with-dangling-if 
stmt-not-ending-with-dangling-if : 
    IF '(' expr ')' stmt-not-ending-with-dangling-if ELSE stmt-not-ending-with-dangling-if | 
    WHILE '(' expr ')' stmt-not-ending-with-dangling-if | 
    DO stmt WHILE '(' expr ')' ';' | 
    expr ';' | 
    '{' stmt-list '}' 
stmt-ending-with-dangling-if: 
    IF '(' expr ')' stmt | 
    IF '(' expr ')' stmt-not-ending-with-dangling-if ELSE stmt-ending-with-dangling-if | 
    WHILE '(' expr ')' stmt-ending-with-dangling-if 

ルール(彼らはstmtで終わるような)二つに分割し得る、expr;ようなルールがない間はありません。

+0

他のステートメントを詳述してもらえますか?私はselection-stmtで他のプロダクションを持っていませんが、無駄な非終端記号を使用しているとエラーが表示されます これは私がやったことです: selection-stmt \tオープン: \t \t |閉鎖 \t \t; open \t \t:IF LFT_BRKT式RGT_BRKT文 \t \t | IF LFT_BRKT式RGT_BRKTがELSEを開いたままにした場合 \t \t; closed \t \t:IF LFT_BRKT式RGT_BRKTが閉じられたELSEが閉じられる \t \t; –

+0

見てください –

+0

http://stackoverflow.com/questions/12720219/bison-shift-reduce-conflict-unable-to-resolve/12720483#12720483 完全な文法はここにあります –

0

は次のように、通常の文よりもあれば、他のより高いレベルにします。 html)は、同様の問題で私を助けました。また、スイッチ `--debug`と` --verbose`をbisonに渡して、生成されたファイルを見てください。すべての情報が標準出力に印刷されるわけではありません。
+0

これで問題を解決できないと思います。 –

関連する問題