Взаимная левая рекурсия ANTLR 4

Мне жаль задавать еще один вопрос о взаимной левой рекурсии, я чувствую, что мой характерен только для моей ситуации, или, по крайней мере, я не могу понять достаточно, чтобы связать его с грамматикой всех остальных. Я немного новичок в мире компьютерных технологий (я самоучка в java, который является моим целевым языком, а теперь и ANTLR4), поэтому, если возможно, опишите вещи в терминах непрофессионала, а не в терминах CS.

Я пишу программу, которая требует алгебры и символических производных, и, конечно, требует, чтобы вещи были проанализированы, и деревья оперировались, но я даже не буду беспокоиться об этом, потому что я думал, что ANTLR4 поддерживает прямую левую рекурсию, но по-видимому, это не так. На выходе он говорит мне, что мой метод [выражение] является взаимно рекурсивным и, по-видимому, это не разрешено...? МОИ ВОПРОСЫ:

1) Может ли кто-нибудь объяснить левую рекурсию / разницу между взаимной и прямой левой рекурсией, если она есть?

2) Объясните, что в моей грамматике вызывает это рекурсивное раздражение, и как это исправить? И я не уверен, если это по теме:

3) Люди говорят что-то об альтернативах и маркируют альтернативы (я думаю, что они имеют в виду обозначение #label). Для чего это?

grammar MathProcessor;
@header {package utils;}
END: ';';
EQUALS: '=';
SIN: 'sin(';
COS: 'cos(';
TAN: 'tan(';
SEC: 'sec(';
CSC: 'csc(';
COT: 'cot(';
LN: 'ln(';
EPOW: 'pow(';
RPAREN: '(';
LPAREN: ')';
EXP: '^';
MULT: '*';
DIV: '/';
ADD: '+';
SUBT: '-';
VAR: ('a'..'z'|'A'..'Z');
INT: ('0'..'9')+;
mathobj: ((equation|expression) END) EOF;
equation: (expression '=' expression);

expression: 
((RPAREN|SIN|COS|TAN|SEC|CSC|COT|LN|EPOW) expression (RPAREN)) #parenOps
| (expression EXP expression) #exponent
| (expression (MULT|DIV) expression) #multiplyDivide 
| (expression (ADD|SUBT) expression) #addSubtract
| (VAR|INT) #varInt
;

1 ответ

Ваша грамматика фактически будет работать с ANTLR 4, если вы просто удалите несколько случаев ненужных скобок в вашей грамматике. Алгоритм исключения левой рекурсии работает только с прямой левой рекурсией, что показано в следующем примере:

a
  : B
  | a B  // the reference to 'a' here is direct left recursion
  ;

Основной другой тип рекурсии - косвенная левая рекурсия, которая обычно демонстрируется с использованием двух отдельных правил.

a
  : B
  | c
  ;

c
  : a B // the reference back to 'a' is indirect left recursion
  ;

В случае вашей грамматики ANTLR лечит (...) как анонимное подправило, поэтому код, подобный следующему, определяется как косвенная левая рекурсия. Если вы удалите скобки из примера, он будет вести себя как в первом случае.

a
  : B
  | (a B)
  ;

Чтобы ответить на ваш последний вопрос, #label синтаксис изменяет сгенерированный класс дерева разбора для этой альтернативы. Например, вместо генерации простого ExpressionContext объект, выражение 3 будет генерировать VarIntContext, Это позволяет вам различать разные альтернативы в правиле автоматически генерируемых слушателей и посетителей.

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