1

次のファイルを解析する必要がある非常に単純なantlr文法ファイルを作成しようとしています。

Report (MyReport)
Begin
End

またはレポート名なし:

Report
Begin
End

そして、これが私の文法ファイルです:

grammar RL;

options {
  language = Java;
}

report:
  REPORT ('(' SPACE* STRING_LITERAL SPACE* ')')?
  BEGIN
  END
  ;

REPORT
    :   'Report'
    ;     

BEGIN
    :   'Begin'
    ;

END :   'End';

NAME:   LETTER (LETTER | DIGIT | '_')*;

STRING_LITERAL :    NAME SPACE*;

fragment LETTER: LOWER | UPPER;

fragment LOWER: 'a'..'z';

fragment UPPER: 'A'..'Z';

fragment DIGIT: '0'..'9';

fragment SPACE: ' ' | '\t';

WHITESPACE: SPACE+ { $channel = HIDDEN; };

rule: ;

ただし、ANTLRWorksでデバッグすると、常に次のエラーが発生します。

 root -> report -> MismatchedTokenException(0!=0)

文法ファイルの何が問題になっていますか?

ありがとう、グリーン

4

1 に答える 1

3

いくつかのコメント:

  • Java;はデフォルトの言語であるため、省略できlanguage=Java;ます。
  • SPACEパーサー ルール内で使用していますが、このSPACEトークンはfragment: これにより、レクサーはこのトークンを作成しなくなります: パーサー ルールから削除します。
  • 入力"Report "("Report" の後に 1 つの空白が続く) は!STRING_LITERALではなく としてトークン化されています。REPORTANTLR のレクサーは貪欲に文字を消費します。2 つ以上のルールが同じ量の文字に一致する場合にのみ、最初に定義されたルールが優先されます。lexer は、パーサーが照合しようとしているトークンを生成しませ(解析とトークン化は個別に実行されます!)。

代わりに次のことを試してください。

grammar RL;

report
 : REPORT ('(' NAME ')')? BEGIN END
 ;

REPORT : 'Report';     
BEGIN  : 'Begin';
END    : 'End';
NAME   : LETTER (LETTER | DIGIT | '_')*;

fragment LETTER : LOWER | UPPER;
fragment LOWER  : 'a'..'z';
fragment UPPER  : 'A'..'Z';
fragment DIGIT  : '0'..'9';

SPACE  : (' ' | '\t' | '\r' | '\n')+ { $channel = HIDDEN; };

green さんが書きました:

Report NAME 内で "SPACE" を許可したい場合はどうすればよいですか?

私はまだレクサーのスペースをスキップします。名前の間のスペースを受け入れても、他のコンテキストではそれらを無視すると、いくつかの厄介なルールが発生します。レポート名の間のスペースを考慮する代わりに、次のようにします。

report
 : REPORT ('(' report_name ')')? BEGIN END
 ;

report_name
 : NAME+
 ;

結果として、次の解析ツリーが生成されます。

ここに画像の説明を入力

入力用:

報告書(スペース入りの名前)
始める
終わり

green さんが書きました:

名前に「レポート」などの予約語を使用できるようにすることはできますか?

もちろん、明示的にreport_nameルールに追加してください:

report_name
 : (NAME | REPORT | BEGIN | END)+
 ;
于 2012-06-25T15:33:11.973 に答える