Несколько вещей не верны:
1
Вы поместили токен WS
на канал HIDDEN
, что делает их недоступными для правил синтаксического анализа.Таким образом, все WS
токены в вашем body
правиле неверны.
2
_ ( ваше последнее изменение устраняет проблему левой рекурсии, но я все равно сделаюсмысл извините, у вашего другой вопрос есть левое рекурсивное правило (expr
), поэтому я оставлю эту информацию здесь) _
ANTLR является LL-парсером -генератором, так что вы можете создавать леворекурсивные грамматики.Следующее остается рекурсивным:
expr
: term term operator
;
term
: INT
| ID
| expr
;
, потому что первое term
в правиле expr
может соответствовать самому правилу expr
.Как и любой анализатор LL, сгенерированный ANTLR синтаксический анализатор не может справиться с левой рекурсией.
3
Если вы исправите проблему WS
, ваше правило body
выдаст следующее сообщение об ошибке:
(1/7) Decision can match input such as "INT" using multiple alternatives
Это означает, что анализатор не может "увидеть", к какому правилу относится токен INT
.Это связано с тем, что вся ваша альтернатива body
может повторяться ноль или более раз, а expr
и nested
также повторяются.И все они могут соответствовать INT
, на что жалуется ANTLR.Если вы удалите *
вот так:
body
: nested
| var
| get
;
// ...
expr
: term (term operator)
;
nested
: expr (expr operator)
;
, ошибки исчезнут (хотя это все равно не приведет к правильному анализу вашего ввода!).
Я понимаю, чтоэто все еще может звучать расплывчато, но объяснять (или понимать, если вы новичок во всем этом нетривиально) нетрудно.вам нужно держаться подальше от левой рекурсии, как я объяснил в # 2 .Вы можете сделать это следующим образом:
expr
: term (expr operator | term operator)*
;
, который все еще неоднозначен, но это в случае описания выражения постфикса с использованием грамматики LL, неизбежного AFAIK.Чтобы решить эту проблему, вы можете включить глобальный возврат в разделе options { ... }
грамматики:
options {
language=Python;
output=AST;
backtrack=true;
}
Demo
Небольшая демонстрация того, как анализировать рекурсивные выражения, может выглядеть следующим образом:
grammar star;
options {
language=Python;
output=AST;
backtrack=true;
}
parse
: expr EOF -> expr
;
expr
: (term -> term) ( expr2 operator -> ^(operator $expr expr2)
| term operator -> ^(operator term term)
)*
;
expr2
: expr
;
term
: INT
| ID
;
operator
: ('*' | '+' | '/' | '%' | '-')
;
ID
: ('a'..'z' | 'A'..'Z') ('a..z' | '0'..'9' | 'A'..'Z')*
;
INT
: '0'..'9'+
;
WS
: (' ' | '\n' | '\t' | '\r') {$channel=HIDDEN;}
;
Тестовый сценарий:
#!/usr/bin/env python
import antlr3
from antlr3 import *
from antlr3.tree import *
from starLexer import *
from starParser import *
def print_level_order(tree, indent):
print '{0}{1}'.format(' '*indent, tree.text)
for child in tree.getChildren():
print_level_order(child, indent+1)
input = "5 1 2 + 4 * + 3 -"
char_stream = antlr3.ANTLRStringStream(input)
lexer = starLexer(char_stream)
tokens = antlr3.CommonTokenStream(lexer)
parser = starParser(tokens)
tree = parser.parse().tree
print_level_order(tree, 0)
производит следующий вывод:
-
+
5
*
+
1
2
4
3
, который соответствует следующему AST: