1

私は学校向けのプロジェクトに取り組んでおり、BNF形式のカフェイン抜き仕様を文脈自由文法に変換してANTLRで構築しています。私は数週間それに取り組んでいて、行き詰まったときに教授のところに行きましたが、私はついに彼がエラーを引き起こしてはならないと言っていることに遭遇しました。これが私の文法の孤立した部分です。exprが出発点です。その前に、1つ質問があります。

レクサールールが文法のパーサールールの前に表示されるかどうか、または文法ファイル全体で断続的に混合されるかどうかは重要ですか?

calloutarg:         expr | STRING;
expr:  multexpr ((PLUS|MINUS) multexpr)* ;
multexpr : atom ((MULT|DIVISION) atom)*
;

atom : OPENPAR expr CLOSEPAR | ID ((OPENBRACKET expr CLOSEBRACKET)? | OPENPAR ((expr (COMMA)* )+)? CLOSEPAR)|
CALLOUT OPENPAR STRING (COMMA (calloutarg)+ COMMA)? CLOSEPAR | constant;
constant: INT | CHAR | boolconstant;
boolconstant: TRUE|FALSE;

醜いフォーマットは、デバッグに関する彼のアドバイスの一部が、個々のルールを取得し、エラーがどこから始まっているかを曖昧にするためにそれらを分解することであったためです。この場合、問題は長いID部分にあり、OPENBRACKETとOPENPARが原因であると言っています。何かアイデアがありましたら、心より感謝申し上げます。ありがとう、そして私が投稿したコードのフォーマットがいかに厄介であるか申し訳ありません。

4

1 に答える 1

1

文法のパーサールールの前にレクサールールが表示されるかどうかは重要ですか...

いいえ、それは問題ではありません。

問題は、atomルールの中で、ANTLRがこれらの3つのバリアントから選択できないことです。

  1. ID ( ...
  2. ID [ ...
  3. ID

(おそらく)バックトラックに頼ることなく。いくつかの構文述語(次のようになります(...)=> ...)を使用して解決できます。構文述語は「先読み」にすぎず、この「先読み」が成功すると、その特定のパスが選択されます。

現在のatomルールは次のように書き直すことができます。

atom 
  :  OPENPAR expr CLOSEPAR
  |  ID OPENPAR ((expr (COMMA)* )+)? CLOSEPAR 
  |  ID OPENBRACKET expr CLOSEBRACKET
  |  ID
  |  CALLOUT OPENPAR STRING (COMMA (calloutarg)+ COMMA)? CLOSEPAR
  |  constant
  ;

そして、述語を使用すると、次のようになります。

atom 
  :  OPENPAR expr CLOSEPAR
  |  (ID OPENPAR)=>     ID OPENPAR ((expr (COMMA)* )+)? CLOSEPAR 
  |  (ID OPENBRACKET)=> ID OPENBRACKET expr CLOSEBRACKET
  |  ID
  |  CALLOUT OPENPAR STRING (COMMA (calloutarg)+ COMMA)? CLOSEPAR
  |  constant
  ;

これでうまくいくはずです。

注:パーサーの生成またはテストにANTLRWorksを使用しないでください。述語を処理することはできません(よく)。コマンドラインで実行するのが最適です。

https://wincent.com/wiki/ANTLR_predicatesも参照してください。


編集

atomルールの6つの異なる「ブランチ」にからAまでのラベルを付けましょうF

atom                                                            // branch
  :  OPENPAR expr CLOSEPAR                                      //   A
  |  ID OPENBRACKET expr CLOSEBRACKET                           //   B
  |  ID OPENPAR ((expr COMMA*)+)? CLOSEPAR                      //   C
  |  ID                                                         //   D
  |  CALLOUT OPENPAR STRING (COMMA calloutarg+ COMMA)? CLOSEPAR //   E
  |  constant                                                   //   F
  ;

ここで、(将来の)パーサーが次のように入力を処理する必要がある場合:

ID OPENPAR expr CLOSEPAR

ANTLRは、パーサーがそれをどのように処理するかを知りません。これは、2つの異なる方法で解析できます。

  1. ブランチDに続いてブランチA
  2. ブランチC

ANTLRが不満を言っている曖昧さの原因はどれですか。Aブランチの1つ、CまたはをコメントアウトするDと、エラーは消えます。

お役に立てば幸いです。

于 2010-10-20T06:55:52.460 に答える