私はこのANTLR4文法を持っています:
constantFixedExpresion : term (('+'|'-') term)+;
term : factor (('*'|'//'|'REM')factor)+;
factor : ('+'|'-')*
( wholeNumberConstant
| constantFixedExpresion
| 'TOFIXED' (stringConstant | bitCodeConstant)
| identifier)
('FIT'constantFixedExpresion)*;
次のエラーが発生します。
error(119):LanguageA.g4 :::次のルールのセットは相互に左再帰的です[constantFixedExpresion、factor、term]
私はたくさんの方法を試しましたが、それを修正することはできません。問題は何ですか?どうすれば解決できますか?
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はこれらの瞬間に非常に役立ちます。この機能を利用するには、文法を書き直すことをお勧めします。