解析时ANTLR4相互左递归错误

时间:2014-10-20 06:57:30

标签: java recursion antlr

我有这个ANTLR 4语法:

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

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

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

我收到以下错误:

  

错误(119):LanguageA.g4 :::以下几组规则是相互左递归的[constantFixedExpresion,factor,term]

我尝试了很多方法,但无法修复它。有什么问题,如何解决?

1 个答案:

答案 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在这些时刻有很大帮助!我建议重新编写语法以使用此功能。