У меня есть следующая грамматика выражений, которую я генерирую синтаксическим анализатором, используя опцию
-DcontextSuperClass=RuleContextWithAltNum
, чтобы я мог узнать, какая альтернатива для правила соответствует.Однако для грамматики с левым рекурсивным правилом, подобным приведенному ниже, она дает неожиданные значения для альтернатив, фактически каждой альтернативе правила aexpr
присваивается альтернативный номер 1.
grammar expr;
expr : aexpr
;
aexpr : NUM
| IDENTIFIER
| aexpr binop aexpr
| '(' aexpr ')'
| funcall
| '-' aexpr
;
binop : '*' | '+' | '-' | '**' | '/'
;
funcall : IDENTIFIER '('expr (',' expr)*')'
;
NUM : [1-9][0-9]*
;
IDENTIFIER : [a-zA-Z][a-zA-Z0-9_]*
;
WS : [ \r\t\n]+ -> skip
;
Вот драйверпрограмма и слушатель, который просто печатает альтернативный номер.
public class Main {
public static void main(String[] args) throws Exception {
// create a CharStream that reads from standard input
ANTLRInputStream input = new ANTLRInputStream(System.in);
// create a lexer that feeds off of input CharStream
exprLexer lexer = new exprLexer(input);
// create a buffer of tokens pulled from the lexer
CommonTokenStream tokens = new CommonTokenStream(lexer);
// create a parser that feeds off the tokens buffer
exprParser parser = new exprParser(tokens);
ParseTree tree = parser.expr(); // begin parsing at init rule
ParseTreeWalker walker = new ParseTreeWalker();
Listener listen = new Listener();
walker.walk(listen, tree);
System.out.println(tree.toStringTree(parser));
}
}
public class Listener extends exprBaseListener {
public void enterEveryRule(ParserRuleContext ctx) {
System.out.println(ctx.getRuleIndex() +"/"+ctx.getAltNumber());
}
}
Я проверил его на следующих входах
входное выражение: ((21))
output:
0/1
1/1
1/1
1/1
(expr:1 (aexpr:1 ( (aexpr:1 ( (aexpr:1 21) )) )))
Третий вариант правила aexpr
был найден, но он возвращается с альтернативным номером 1.
Однако, избавление от (комментирование)левая рекурсивная альтернатива aexpr : aexpr binop aexpr
, возвращаются правильные альтернативные номера.На том же входе ((21))
я получаю:
0/1
1/3
1/3
1/1
(expr:1 (aexpr:3 ( (aexpr:3 ( (aexpr:1 21) )) )))
Подобная проблема , кажется, все еще открыта, хотя позже в комментариях говорится, что она будет исправлена в Antlr4,6.Я использую 4.7.2.Кто-нибудь когда-нибудь пытался решить эту проблему, или, по крайней мере, получить правильные альтернативные числа для другой нерекурсивной альтернативы aexpr
?Или какая-либо идея о том, как сделать исправление из источников (я просматривал источники antlr)?