Левое рекурсивное правило Antlr4 содержит левую рекурсивную альтернативу, за которой может следовать пустая строка

Поэтому я определил грамматику для синтаксического анализа языка синтаксиса в стиле 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;

Однако, когда я хочу сгенерировать рекогонизаторы ANTLR в intelliJ, я получил эту ошибку:

sCalc.g4: 19: 0: левое рекурсивное выражение правила содержит левую рекурсивную альтернативу, за которой может следовать пустая строка

Интересно, это вызвано моим ID может быть пустой строкой?

2 ответа

Решение

Есть несколько проблем с вашей грамматикой:

  • у тебя есть 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*

Это о вашем expression а также relation правила. Правило выражения может соответствовать relation в один альт, который в свою очередь возвращается к expression. правило relation кроме того, потенциально ничего не может сравниться из-за (op=('<'|'>') expression)*

Лучше подход, вероятно, иметь relation вызов expression и удалите relation Alt от expression, Тогда используйте relation везде, где вы использовали expression сейчас. Это типичный сценарий в выражениях, начиная с операций с низким приоритетом в качестве правил верхнего уровня и переходя к правилам с более высоким приоритетом, в конечном итоге заканчивая простым правилом выражения (или аналогичным).

Другие вопросы по тегам