我有这个ANTLR 4语法:
constantFixedExpresion : term (('+'|'-') term)+;
term : factor (('*'|'//'|'REM')factor)+;
factor : ('+'|'-')*
( wholeNumberConstant
| constantFixedExpresion
| 'TOFIXED' (stringConstant | bitCodeConstant)
| identifier)
('FIT'constantFixedExpresion)*;
我收到以下错误:
错误(119):LanguageA.g4 :::以下几组规则是相互左递归的[constantFixedExpresion,factor,term]
我尝试了很多方法,但无法修复它。有什么问题,如何解决?
答案 0 :(得分:24)
Antlr是一个LL(*)解析器,它在很多方面比LL(k) parser“更好”,但仍有许多不利之处。其中一个原因是它不能处理左递归(实际上,版本4可以处理同一规则中的左递归)。错误的含义是你有一个语法的左递归,LL解析器的祸根。
这是由你的语法中的这种结构引起的:
constantFixedExpression: term ...;
term: factor ...;
factor: ('+' | '-')* (constantFixedExpression | ...) ...;
由于*
运算符意味着0或更多,我可以用0实例化它,因此解析器会执行此操作:“try constantFixedExpression
,因此需要尝试term
,所以它需要尝试factor
,所以它需要尝试constantFixedEXpression
,所以它[...]“并且你自己有一个无限循环。
幸运的是,无上下文的正式语法具有删除左递归的等效转换!它可以通过以下方式表达:
A -> Aa | b
-- becomes --
A -> bR
R -> aA | ε
或者以Antlr表示法:
A: Aa | b;
// becomes
A: bR;
R: (aA)?;
有关此过程的更多信息,请参阅自动机/语法书籍或Wikipedia。
我将通过重构纠正你的语法,以删除左递归作为你的工作。但是,我想触及另一点:Antlr 4可以进行左递归!正如我所提到的,版本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
。
正如您所看到的,使用左递归指定运算符要容易得多,因此Antlr 4在这些时刻有很大帮助!我建议重新编写语法以使用此功能。