我很遗憾地问另一个关于相互左递归的问题,我觉得我的情况是独一无二的,或者至少我无法弄清楚将其与其他人的语法联系起来。我对comp sci世界有点新鲜(我在java中自学,这是我的目标语言,现在是ANTLR4)所以如果可能的话请用layperson术语描述,而不是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
;
答案 0 :(得分:5)
如果您只是在语法中删除了几个不必要的括号,那么您的语法实际上可以与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
对象。这允许您在自动生成的侦听器和访问者中区分规则中的不同备选方案。