web-dev-qa-db-ja.com

ANTLR 4.5-入力 'x'に 'x'が必要です

私はANTLRを使い始めており、レクサールールにはかなり気まぐれであることに気付きました。非常にイライラする例は次のとおりです。

grammar output;

test: FILEPATH NEWLINE TITLE ;

FILEPATH: ('A'..'Z'|'a'..'z'|'0'..'9'|':'|'\\'|'/'|' '|'-'|'_'|'.')+ ;
NEWLINE: '\r'? '\n' ;
TITLE: ('A'..'Z'|'a'..'z'|' ')+ ;

この文法は次のようなものと一致しません。

c:\ test.txt
バツ

奇妙なことに、TITLETITLE: 'x' ;に変更すると、今回はまだ失敗し、「入力 'x'に 'x'が必要です」というエラーメッセージが表示され、非常に混乱します。さらに奇妙なことに、TITLEtestの使用をFILEPATHに置き換えると、すべてが機能します(ただし、FILEPATHは一致するものよりも一致します)だから、一般的にそれは私にとって有効な解決策ではありません)。

ANTLRがこのような非常に奇妙なエラーを出し、その後、物事をシャッフルするときに明白な理由もなく突然動作する理由について、私は非常に混乱しています。

30
Chiune Sugihara

これはANTLRのよくある誤解のようです:

ANTLRでの言語処理:

言語処理は、厳密に分離された2つのフェーズで実行されます。

  • Lexing、つまりテキストをトークンに分割する
  • 解析、つまりトークンから解析ツリーを構築する

字句解析は解析に先行する必要があるため、結果があります。字句解析プログラムは構文解析プログラムから独立しているため、構文解析プログラムは字句解析に影響を与えることができません。

Lexing

ANTLRのLexingは次のように機能します。

  • 最初の文字が大文字のルールはすべてレクサールールです
  • レクサーは先頭から開始し、現在の入力に最も一致するルールを見つけようとします
  • 最適な一致は、最大長のmatchです。つまり、次の入力文字を最大長の一致に追加した結果のトークンは、レクサールールと一致しません。
  • トークンは一致から生成されます:
    • one rulemaximum length matchに一致する場合、対応するトークンがトークンストリームにプッシュされます
    • multiple rulesmaximum length matchに一致する場合文法で最初に定義されたトークンがトークンストリームにプッシュされます

例:文法の何が問題なのか

文法には、重要な2つのルールがあります。

FILEPATH: ('A'..'Z'|'a'..'z'|'0'..'9'|':'|'\\'|'/'|' '|'-'|'_'|'.')+ ;
TITLE: ('A'..'Z'|'a'..'z'|' ')+ ;

TITLEに一致する各一致は、FILEPATHにも一致します。そして、FILEPATHはTITLEの前に定義されます:したがって、タイトルになると予想される各トークンはFILEPATHになります。

そのための2つのヒントがあります。

  • レクサールールを分離したままにします(他のスーパーセットに一致するトークンはありません)。
  • トークンが意図的に同じ文字列に一致する場合は、正しい順序に並べます(この場合はこれで十分です)。
  • パーサー駆動のレクサーが必要な場合は、別のパーサージェネレーターに変更する必要があります。PEG-ParsersまたはGLR-Parsersがそれを行います(もちろん、これは他の問題を引き起こす可能性があります)。
55
CoronA

これは直接OPの問題ではありませんでしたが、同じエラーメッセージを持っている人のために、ここで確認できるものがあります。


同じMismatched Input 'x' expecting 'x'新しいキーワードを導入したときのあいまいなエラーメッセージ。私の理由は、新しいキーワードとしてではなく変数名として割り当てたVARNAMEレクサールールの後に新しいキーWordを配置したためです。 VARNAMEルールの前にキーワードを置くことで修正しました。

1
Blubber

同じエラーがありますが、レクサーのどのルールが関係するのか想像できません。
CobolのいくつかのCDEファイルを解析しようとしています-これはHPノンストップ固有のものだと思います。

とにかく、私が解析したいのは次のようなものです

* SCHEMA PRODUCED DATE - TIME : 1/29/2019 - 15:17:01
?SECTION MYREQUEST,NONSTOP
* Definition MYREQUEST created on 05/11/2016 at 11:05
  01 MYREQUEST. 
  ...

パーサーは次のエラーで失敗します

mismatched input '?SECTION foo' expecting '?'

私の文法はこれです:

grammar CdeFile;

cdeFile : line+ ;
line : sectionLine ;
sectionLine : QUESTIONMARK SECTION sectionName '\r'? '\n' ;
sectionName : TEXTLIST ;

QUESTIONMARK : '?' ;
SECTION: S E C T I O N ;

TEXTLIST : TEXT (',' TEXT)* ;
TEXT : ~[,\n\r"]+ ;

WS : ( ' ' | '\t' | '\f' )+ -> skip;
LINE_COMMENT 
     : '*' {Column == 1}? '*'* ~('\n'|'\r')* '\r'? '\n' ->skip 
     ; 


// case insensitive chars
fragment A:('a'|'A');
fragment B:('b'|'B');
fragment C:('c'|'C');
fragment D:('d'|'D');
fragment E:('e'|'E');
fragment F:('f'|'F');
fragment G:('g'|'G');
fragment H:('h'|'H');
fragment I:('i'|'I');
fragment J:('j'|'J');
fragment K:('k'|'K');
fragment L:('l'|'L');
fragment M:('m'|'M');
fragment N:('n'|'N');
fragment O:('o'|'O');
fragment P:('p'|'P');
fragment Q:('q'|'Q');
fragment R:('r'|'R');
fragment S:('s'|'S');
fragment T:('t'|'T');
fragment U:('u'|'U');
fragment V:('v'|'V');
fragment W:('w'|'W');
fragment X:('x'|'X');
fragment Y:('y'|'Y');
fragment Z:('z'|'Z');

QUESTIONMARKの値は同期しており、すべてが再構築されます-それでもこの奇妙なメッセージです。

0
Slesa