2017-11-05 12 views
0

私は小さなパーサを書こうとしています。残念ながら、私は「シフトを減らす紛争」を起こします。文法は私の強みではありません。私はこれを小さなものにする必要があります。修正された文法を与える解決策は、エラーを生成する文法の縮小です:文法の中でIF-ELSEの競合を減らす/減らす

stmts_opt -> stmts 
; 

stmts -> stmt 
| stmts stmt 
| stmsts 
; 

stmt -> id 
| ITERATE content_stmt 
| IF test then content_stmt ELSE content_stmt 
| IF test then content_stmt 
; 

content_stmt: BEGIN stmt_opt END 
| stmt 
; 

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

編集:私は私の文法はRICIの答え@合ったが、問題が解決しない修正

。ここに私の実際の文法プロダクションです:

BEGINNING-OF-PROGRAM 
    BEGINNING-OF-EXECUTION 

    IF not-next-to-a-beeper THEN 
     move; 

    IF not-facing-north THEN 

     turnleft; 


    ELSE <--- ERROR 
     turnleft; 

    IF not-facing-east THEN 
     IF not-facing-west THEN 
     turnleft; 

    turnoff 
    END-OF-EXECUTION 
END-OF-PROGRAM 

私が最初ELSEのエラーを取得しています:ここで

prog: BEGIN_PROG def_sprogram BEGIN_EXEC stmts_opt END_EXEC END_PROG 
      {() } 
; 

def_sprogram: /* empty */  {() } 
| define_new def_sprogram  {() } 
; 


define_new:   DEFINE_NEW_INSTRUCTION ID AS content_stmt SEMI { } 
; 

stmts_opt: /* empty */  {() } 
|   stmts   {() } 
; 

stmts:  stmt   {() } 
|   stmts SEMI stmt {() } 
|   stmts SEMI  {() } 
; 

content_stmt: BEGIN stmts_opt END {() } 
|  stmt {() } 
; 

stmt:  open_stmt {() } 
|   closed_stmt {() } 
; 

open_stmt: ITERATE INT TIMES open_stmt {() } 
|   WHILE test DO open_stmt {() } 
|   IF test THEN closed_stmt ELSE open_stmt {() } 
|   IF test THEN stmt {() } 
; 

closed_stmt: simple_stmt {() } 
|   ITERATE INT TIMES closed_stmt {() } 
|   WHILE test DO closed_stmt {() } 
|   IF test THEN closed_stmt ELSE closed_stmt {() } 
; 

は、私がテストしてい例です。 @riciが示唆しているように簡単な優先順位を宣言しようとしました:

%nonassoc THEN 
%nonassoc ELSE 

しかし、それでもエラーは解決されませんでした。

+0

yacc/bisonが正しい解決法を選択しているため、shift-reduceの矛盾が曖昧な曖昧さから生じる場合は、文法は正しく動作します。警告を取り除きたい場合は、ここで「他の人を抱きしめる」を検索してください。 – rici

+0

私はcamlyaccを使用しており、警告ではなくエラーが発生しています。私はここで検索しようとしましたが、私の文法は少し異なります(BEGINとENDで)、提案された解決策は私のためには機能しませんでした。 –

+0

これをエラーにするのは面倒です。それはしないでください。しかし、開始トークンと終了トークンは何の影響も与えてはなりません。あなたは何をしなかったのですか? – rici

答えて

1

「ダングリングelse」のシフト・リダクションの最も単純な解決策は、ELSEトークンのシフトを優先して解決することです。

%nonassoc THEN 
%nonassoc ELSE 

(結合性のdoesn:camlyaccが優先宣言(むしろ不完全マニュアルに従って、私は見つけることができた)、これは(最初%%前に)あなたの宣言セクションに以下を追加するのと同じくらい簡単であるべきをサポートしていますので、

明示的な「一致/不一致」(または「開/閉文」)を使用する場合は、 BEGIN stmts_opt ENDTHENを受け入れることができないため、「一致」(または「閉じた」文)です。他の一致ステートメントは、比類のない文が

unmatched_stmt: ITERATE unmatched_stmt 
       | IF test THEN matched_stmt 
       | IF test THEN unmatched_stmt 
       | IF test THEN matched_stmt ELSE unmatched_stmt 

多くの人々がmatched_stmtunmatched_stmtを含み、非末端を作成することを好むです

matched_stmt: BEGIN stmts_opt END 
      | ITERATE matched_stmt 
      | IF test THEN matched_stmt ELSE matched_stmt 
      | /* Any other kind of simple statement */ 

です。しかし、あなたのケースでは、ネストしたくないようです。BEGIN&hellip; ENDブロックに分割し、それらを複合ステートメントの内容に制限します。したがって、stmtは、BEGIN stmts_opt END右側のを除いて、上記のすべてのになります。

+0

ありがとうございます。私はあなたの両方のソリューションを試してみました。私はどこかで間違っているとほとんど確信しています。私はmatched_stmtとunmatched_stmtを含めた後、完全に新しい文法で質問を更新しました。 –

+0

@ Joker00:私たちは通常、[mcve]を主張し、なぜ答えを出した後に編集の質問をしないのかという理由があります。私はあなたのパーサーを構築しようとしたときに私が推測していたシフト・リダクションの衝突を解決したという点で、私の答えがあなたの最初の質問に正しく答えたと確信しています。あなたの編集した質問では、*異なる文法*(セミコロンの文の区切り文字を含む)の結果である*異なる問題*(パーサの実行中の構文エラー*)を報告します。 – rici

+0

... 'stmt'は、あなたが定義したように、*の末尾にセミコロン*が含まれていないことに注意してください。 if文の構文( 'IF test THEN closed_stmt ELSE ...')にはセミコロンは含まれていません。しかし、「そうでないなら、北側はターン・レフトです。 ELSE'にはセミコロンが含まれているため、ルールと一致しません。 – rici

関連する問題