Левое рекурсивное правило 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
сейчас. Это типичный сценарий в выражениях, начиная с операций с низким приоритетом в качестве правил верхнего уровня и переходя к правилам с более высоким приоритетом, в конечном итоге заканчивая простым правилом выражения (или аналогичным).