17

1 週間前、私は次のプロジェクトを開始しました: Java コードのサフィックスを認識する文法です。

ANTLRJavaの公式文法 ( Java.g4) をベースラインとして使用し、いくつかの規則を追加し始めました。しかし、これらの新しい規則は左再帰も導入し、これにも対処しなければなりませんでした。

数日間の作業の後、次のコードができました。テストを開始したとき、まだ説明できない異常なことに気付きました。入力が与えられると{ }、パーサーは私に教えてくれますno viable alternative at input '<EOF>'が、ルールの右手側で端子の順序を切り替えるとs2、特に右手側を から に変更するv2_1 | v2_2 | v2_3 ...v2_36 | v2_1 | v2_2 ...(端子v2_36が最初の位置に移動します)、シーケンス{ }が受け入れられます。

私の最初の考えは、入力によってパーサーの最初のバージョンがルールに従い始め、何も見つからず、他のオプションを考慮しようとしないことを報告するだけAntlrであることに気付いたため、バックトラックしないということでした (それは私が思うことですが、そうではないかもしれません) true) のように、正の答えを正確に返します。{ }v2_3v2_36

しかし、いくつかの調査の後、実際にはバックトラックが行われることがわかりましたが、ANTLRそれは他のすべてが失敗した場合に限られます. 少なくともこれは v3.3 には当てはまりますが (公式ANTLRの論文を読んでください) v4、. 今、私は少し混乱しています。このプロジェクトに非常に多くの時間を費やした後、うまくいかなかったら本当にひどい気分になります。誰かが何らかのヒントか何かを与えることができますか? よろしくお願いします。

編集

問題を切り分けることができた

grammar Java;
@parser::members {String ruleName; }

start : compilationUnitSuf EOF;

compilationUnitSuf
    :   {ruleName = "typeDeclarationSuf"; } s2
    ;

s2: '{' '}' v2_81 | '{' '}';
v2_81 : {ruleName.equals("enumBodyDeclarationsSuf")}? t173 | t173 '}';
t173: '}' | '{'*;

LBRACKET: '{';
RBRACKET: '}';

WS  :  [ \t\r\n\u000C]+ -> skip
    ;

では、なぜ予測アルゴリズムがs2 -> v'{' '}' v2_81 -> ...ではなく従うように提案するのs2 -> '{' '}'でしょうか?

4

1 に答える 1

1

あなたが期待する方法で後戻りしていないことがわかると思います。その理由は、 を見つけてから、 が見つからないことを{}期待しているためです。v2_181その後バックトラックしないため、必要な代替手段が見つかりません。別の方法は、単にv2_181オプションにすることです。そうすれば、バックトラッキングは必要ありません。以下のようなもの:

grammar Java;
@parser::members {String ruleName; }

start : compilationUnitSuf EOF;

compilationUnitSuf
    :   {ruleName = "typeDeclarationSuf"; } s2
    ;

s2: '{' '}' v2_81?;
v2_81 : {ruleName.equals("enumBodyDeclarationsSuf")}? t173 | t173 '}';
t173: '}' | '{'*;

LBRACKET: '{';
RBRACKET: '}';

WS  :  [ \t\r\n\u000C]+ -> skip
    ;
于 2013-10-20T13:18:01.967 に答える