I'm sorry to ask yet another question on mutual left recursion, I feel like mine is unique to my situation, or at least I can't figure out enough to relate it to everyone else's grammars. I'm a bit new to the comp sci world (I'm self taught in java, which is my target language, and now ANTLR4) so if possible please describe things in layperson terms, not CS major terms.
I'm writing a program that requires algebra and symbolic derivatives, and of course that requires that things be parsed, and trees be operated upon but I'm not even going to worry about that yet because I thought ANTLR4 supported direct left recursion, but apparently it doesn't somehow. On the output, it keeps telling me that my method [expression] is mutually left recursive and apparently that's not allowed...? MY QUESTIONS:
1) Can someone explain left recursion/the difference between mutual and direct left recursion if there is one?
2) Explain what in my grammar is causing this recursive annoyance, and how to fix it? And I'm not sure if this is on topic:
3) People say things about alternatives and labeling alternatives (I think they mean the #label notation). What is that for?
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
;
Your grammar would actually work with ANTLR 4 if you simply removed several cases of unnecessary parentheses in your grammar. The left recursion elimination algorithm only works with direct left recursion, which appears in the following example:
The primary other type of recursion is indirect left recursion, which is typically demonstrated using two separate rules.
In the case of your grammar, ANTLR is treating
(...)
as an anonymous sub-rule, so code like the following is determined to be indirect left recursion. If you remove the parentheses from the example, it behaves like the first case.To answer your last question, the
#label
syntax changes the generated parse tree class for that alternative. For example, rather than generate a plainExpressionContext
object, the expression3
will generate aVarIntContext
. This allows you to distinguish between different alternatives in a rule in automatically generated listeners and visitors.