web-dev-qa-db-ja.com

ANTLR4相互に左再帰的エラー解析時

私はこのANTLR4文法を持っています:

constantFixedExpresion : term (('+'|'-') term)+;

term : factor (('*'|'//'|'REM')factor)+;

factor : ('+'|'-')*
           ( wholeNumberConstant
           | constantFixedExpresion
           | 'TOFIXED' (stringConstant | bitCodeConstant)      
           | identifier)
         ('FIT'constantFixedExpresion)*;

次のエラーが発生します。

error(119):LanguageA.g4 :::次のルールのセットは相互に左再帰的です[constantFixedExpresion、factor、term]

私はたくさんの方法を試しましたが、それを修正することはできません。問題は何ですか?どうすれば解決できますか?

20
Alican

AntlrはLL(*)パーサーであり、多くの点で LL(k)パーサー よりも「優れています」が、それでも多くの欠点があります。これらの1つは、左再帰を処理できないという事実です(実際、バージョン4は同じルール内で左再帰を処理できます)。エラーが言っているのは、LLパーサーの悩みの種である文法の左再帰があるということです。

これは、文法のこの構造が原因です。

_constantFixedExpression: term ...;
term: factor ...;
factor: ('+' | '-')* (constantFixedExpression | ...) ...;
_

_*_演算子は0以上を意味するため、0でインスタンス化できます。したがって、パーサーは次のように実行します。 "try constantFixedExpression、したがってtermを試行する必要があるため、 factorを試してみてください。したがって、constantFixedEXpressionを試してみる必要があるので、[...] "すると、無限ループになります。


幸いなことに、文脈自由形式文法には、左再帰を削除するための同等の変換があります。これは、一般的に次のように表すことができます。

_A -> Aa | b
-- becomes --
A -> bR
R -> aR | ε
_

またはAntlr表記:

_A: Aa | b;
// becomes
A: bR;
R: (aR)?;
_

このプロセスの詳細については、オートマトン/文法の本または ウィキペディア を参照してください。


左再帰を削除するために、リファクタリングを使用して文法を修正することはお任せします。ただし、別の点で触れたいと思います。Antlr4は左再帰を実行できます。私が述べたように、バージョン4は左再帰を処理できます同じルール内で。 Antlr4で行っているように、直接解析する以外に、演算子の優先順位と結合性を示す方法があります。それがどのように機能するか見てみましょう:

_expr: NUMBER
      |<assoc=right> expr '^' expr
      | expr '*' expr
      | expr '/' expr
      | expr '+' expr
      | expr '-' expr;
_

これは、基本的な電卓の文法の例です。上部の演算子は優先順位が最も高い演算子であり、下部の演算子は優先順位が低い演算子です。これは、_2+2*3_が_(2+2)*3_ではなく2+(2*3)として解析されることを意味します。 _<assoc=right>_構文は、右結合の演算子を意味するため、_1^2^3_は_(1^2)^3_ではなく1^(2^3)として解析されます。

ご覧のとおり、左再帰を使用して演算子を指定する方がはるかに簡単なので、Antlr4はこれらの瞬間に非常に役立ちます。この機能を利用するには、文法を書き直すことをお勧めします。

25
Mephy