Java 互左递归ANTLR 4

Java 互左递归ANTLR 4,java,antlr4,left-recursion,Java,Antlr4,Left Recursion,我很抱歉再问一个关于相互左递归的问题,我觉得我的问题对我的情况来说是独一无二的,或者至少我不能把它和其他人的语法联系起来。我对comp-sci有点陌生(我自学了java,这是我的目标语言,现在是ANTLR4),所以如果可能的话,请用外行的术语,而不是CS专业的术语来描述事情 我正在编写一个程序,它需要代数和符号导数,当然也需要解析东西,对树进行操作,但我甚至不想担心这个问题,因为我认为ANTLR4支持直接左递归,但显然它不支持。在输出上,它一直告诉我我的方法[表达式]是相互左递归的,显然这是不允

我很抱歉再问一个关于相互左递归的问题,我觉得我的问题对我的情况来说是独一无二的,或者至少我不能把它和其他人的语法联系起来。我对comp-sci有点陌生(我自学了java,这是我的目标语言,现在是ANTLR4),所以如果可能的话,请用外行的术语,而不是CS专业的术语来描述事情

我正在编写一个程序,它需要代数和符号导数,当然也需要解析东西,对树进行操作,但我甚至不想担心这个问题,因为我认为ANTLR4支持直接左递归,但显然它不支持。在输出上,它一直告诉我我的方法[表达式]是相互左递归的,显然这是不允许的。。。? 我的问题是:

1) 有人能解释左递归吗?如果有,相互左递归和直接左递归之间的区别是什么

2) 解释在我的语法中是什么导致了这种递归烦恼,以及如何修复它? 我不确定这是否与主题有关:

3) 人们谈论替代品和标记替代品(我认为他们指的是#标签符号)。那是干什么用的

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
;

如果您只是删除了语法中几个不必要的括号,那么您的语法实际上可以与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
语法更改了为该备选方案生成的解析树类。例如,表达式
3
将生成
VarIntContext
,而不是生成普通的
ExpressionContext
对象。这允许您在自动生成的侦听器和访问者中区分规则中的不同备选方案。

非常感谢!经过一点调整,我的语法树在ANTLRworks中看起来不错,它终于构建出来了!至于我是否能想出如何使用它,或者它是否保留了操作的顺序,我们拭目以待,但我会留待以后。