Antlr4左递归规则包含一个左递归替代,后跟空字符串

时间:2016-09-26 23:55:47

标签: antlr4 left-recursion

所以我定义了一个语法来解析C风格的语法语言:

grammar mygrammar;

program
: (declaration)*
  (statement)*
  EOF
;

declaration
: INT ID '=' expression ';'
;

assignment
: ID '=' expression ';'
;

expression
: expression (op=('*'|'/') expression)*
| expression (op=('+'|'-') expression)*
| relation
| INT
| ID
| '(' expression ')'
;

relation
: expression (op=('<'|'>') expression)*
;

statement
: expression ';'
| ifstatement
| loopstatement
| printstatement
| assignment
;

ifstatement
: IF '(' expression ')' (statement)* FI ';'
;

loopstatement
: LOOP '(' expression ')' (statement)* POOL ';'
;

printstatement
: PRINT '(' expression ')' ';'
;

IF : 'if';
FI : 'fi';
LOOP : 'loop';
POOL : 'pool';
INT : 'int';
PRINT : 'print';
ID : [a-zA-Z][a-zA-Z0-9]*;
INTEGER : [0-9]+;
WS : [ \r\n\t] -> skip;

我可以解析一个简单的测试:

int i = (2+3)*3/2*(3+36);
int j = i;
int k = 2*1+i*3;
if (k > 2)
  k = k + 1;
  i = i / 3;
  j = j / 3;
fi;
loop (i < 10)
  i = i + 1 * (i+k);
  j = (j + 1) * (j-k);
  k = i + j;
  print(k);
pool;

但是,当我想在intelliJ中生成ANTLR Recogonizers时,我收到了这个错误:

  

sCalc.g4:19:0:左递归规则表达式包含左递归替代,后面可以跟空字符串

我想知道这是否是由ID可能是一个空字符串引起的?

2 个答案:

答案 0 :(得分:1)

这是关于您的expressionrelation规则。表达式规则可以在一个alt中与relation匹配,后者又会递归到expression.由于relation

,规则(op=('<'|'>') expression)*还可能无法匹配

更好的方法可能是relation调用expression并从relation删除expression alt。然后在您使用relation的任何地方使用expression。这是表达式中的典型场景,从低优先级操作开始作为顶级规则并向下钻取到更高优先级规则,最终以简单表达式规则(或类似)结束。

答案 1 :(得分:1)

你的语法有几个问题:

  • INT内有expression作为替代,而您可能需要INTEGER
  • 无需执行expression (op=('+'|'-') expression)*:这样做:expression op=('+'|'-') expression
  • ANTLR4不支持间接左递归规则:您必须在relation内包含expression

这样的事情应该这样做:

grammar mygrammar;

program
: (declaration)*
  (statement)*
  EOF
;

declaration
: INT ID '=' expression ';'
;

assignment
: ID '=' expression ';'
;

expression
: expression op=('*'|'/') expression
| expression op=('+'|'-') expression
| expression op=('<'|'>') expression
| INTEGER
| ID
| '(' expression ')'
;

statement
: expression ';'
| ifstatement
| loopstatement
| printstatement
| assignment
;

ifstatement
: IF '(' expression ')' (statement)* FI ';'
;

loopstatement
: LOOP '(' expression ')' (statement)* POOL ';'
;

printstatement
: PRINT '(' expression ')' ';'
;

IF : 'if';
FI : 'fi';
LOOP : 'loop';
POOL : 'pool';
INT : 'int';
PRINT : 'print';
ID : [a-zA-Z][a-zA-Z0-9]*;
INTEGER : [0-9]+;
WS : [ \r\n\t] -> skip;

此外,(statement)*只能写成statement*