[解決済み] シフト/リデュース カップ付きエラー
質問
こんにちは、私は大学で使用しているプログラミング言語のパーサーを、jflexとCupを使って書いています。 プロセスや変数宣言など、最初の基本的な構造だけから始めました。
次のようなエラーが発生します。
Warning : *** Shift/Reduce conflict found in state #4
between vardecls ::= (*)
and vardecl ::= (*) IDENT COLON vartyp SEMI
and vardecl ::= (*) IDENT COLON vartyp EQEQ INT SEMI
under symbol IDENT
Resolved in favor of shifting.
Warning : *** Shift/Reduce conflict found in state #2
between vardecls ::= (*)
and vardecl ::= (*) IDENT COLON vartyp SEMI
and vardecl ::= (*) IDENT COLON vartyp EQEQ INT SEMI
under symbol IDENT
Resolved in favor of shifting.
私のCupでのコードは次のようなものです。
non terminal programm;
non terminal programmtype;
non terminal vardecl;
non terminal vardecls;
non terminal processdecl;
non terminal processdecls;
non terminal vartyp;
programm ::= programmtype:pt vardecls:vd processdecls:pd
{: RESULT = new SolutionNode(pt, vd, pd); :} ;
programmtype ::= IDENT:v
{: RESULT = ProblemType.KA; :} ;
vardecls ::= vardecl:v1 vardecls:v2
{: v2.add(v1);
RESULT = v2; :}
|
{: ArrayList<VarDecl> list = new ArrayList<VarDecl>() ;
RESULT = list; :}
;
vardecl ::= IDENT:id COLON vartyp:vt SEMI
{: RESULT = new VarDecl(id, vt); :}
| IDENT:id COLON vartyp:vt EQEQ INT:i1 SEMI
{: RESULT = new VarDecl(id, vt, i1); :}
;
vartyp ::= INTEGER
{: RESULT = VarType.Integer ; :}
;
processdecls ::= processdecl:v1 processdecls:v2
{: v2.add(v1);
RESULT = v2; :}
| {: ArrayList<ProcessDecl> list = new ArrayList<ProcessDecl>() ;
RESULT = list; :}
;
processdecl ::= IDENT:id COLON PROCESS vardecls:vd BEGIN END SEMI
{: RESULT = new ProcessDecl(id, vd); :}
;
Process Declaration と VariableDeclaration の両方が Identifiers で始まり、 ":" と Terminal PROCESS または Terminal like INTEGER で始まるため、エラーが発生するのだと思われます。もしそうなら、私のパーサーにもう少し先を見るように指示する方法を知りたいです。あるいは、可能な限りの解決策を。
ご回答ありがとうございました。
どのように解決するのですか?
あなたの診断はまったく正しいです。なぜなら、パーサーは
IDENT
が開始されます。
processdecl
または
vardecl
を削減したことを知ることができません。
vardecl
を見ていて
IDENT
を見ようとしているのか、別の
vardecl
または
processdecl
.
最初のケースでは、単に
IDENT
の一部として、以下のように
vardecl
. 2番目のケースでは、まず空の
vardecls
を、順次リデュースしていきます。
vardecls
完全なリストを作成するまで。
シフト・リデュースの衝突をなくすには、パーサーの意思決定を単純化する必要があります。
最も単純な解決策は、パーサーがどのような順序で宣言を受け入れてもよいようにすることです。そうすると、次のようなものが出来上がります。
program ::= program_type declaration_list ;
declaration_list ::=
var_declaration declaration_list
| process_declaration declaration_list
|
;
var_declaration_list ::=
var_declaration var_declaration_list
|
;
process_declaration ::=
IDENT:id COLON PROCESS var_declaration_list BEGIN END SEMI ;
(個人的には、宣言リストを右帰納ではなく左帰納にしたいのですが、リストのアクションでappendとprependのどちらを優先するかは人それぞれです。左再起動の方がパーサーのスタック使用量が少なくて済みます)
もし、すべての変数宣言がプロセス宣言の前に来ることを強く希望する場合は
declaration_list
.
また、宣言リストの種類を右再帰ではなく左再帰にすることから始めることもできます。そうすると ほとんど これは、最初のプロセス宣言が削減される前に、空のプロセス宣言リストを削減する必要があるためです。
幸いなことに、これを回避するのは簡単です。プロセス宣言のリストが空でなければ問題はないので、プロダクションを並べ替えればよいだけです。
program ::= program_type var_declaration_list process_declaration_list
| program_type var_declaration_list
;
var_declaration_list ::=
var_declaration var_declaration_list
|
;
process_declaration_list ::=
process_declaration_list process_declaration
| process_declaration
;
最後に、醜いけれども可能な代替案として、変数宣言リストを左再起に、プロセス宣言リストを右再起にする方法があります。この場合、最後の変数宣言と最初のプロセス宣言の間に空のプロダクションは存在しない。
関連
-
[解決済み】LL(0)パーサーというものがあるのですか?
-
[解決済み] シフトとリデュースの競合を解決するには?
-
[解決済み] シフト/リデュース カップ付きエラー
-
[解決済み] UnixツールでJSONをパースする
-
[解決済み] レクサーとパーサーの比較
-
[解決済み] トークナイザー」「パーサー」「レキサー」とは何か、どのような関係にあり、どのように使われるのか、明確な定義をお探しですか?
-
[解決済み] 自由形式の住所/郵便番号をテキストから解析し、コンポーネントに変換する方法
-
[解決済み] パース」の反対語は何ですか?[クローズド]
-
[解決済み] Flex/LexとYacc/Bisonの違いは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン