2012-12-13 23 views
5

Próbuję napisać gramatykę dla wyrażeń arytmetycznych i boolowskich. Nie rozumiem, co robię źle. Dla mojej gramatyki ANTLR mówi:gramatyka wyrażenie logiczne i arytmetyczne w ANTLR

[fatalna] reguła logic_atom ma decyzję inną niż LL (*) z powodu rekursywnych wywołań reguł osiągalnych z alts 1,2. Rozwiąż przez lewostronne faktoring lub używając predykatu składniowego lub używając opcji backtrack = true.

Ale nie mogę zrobić lewostronnego faktoringu. I nie chcę dotykać arith_expr, ponieważ do tego mam kod.

Błąd w logic_atom : LBR logic_expr RBR | cmp_expr ;

mojego kodu:

grammar ArithmeticInterpreter; 

options { 
    output = AST; 
    language = C; 
} 
//options{greedy=true;}: 

axiom : lines EOF! ; 
lines : line (SEP! line)* ; 
line : (def_var | print_expr | scan_expr)? ; 

def_var : VARIABLE ASSIGMENT^ logic_expr ; 
print_expr : PRINT_KEYW^ arith_expr ; 
scan_expr : SCAN_KEYW^ VARIABLE ; 

arith_expr : ((PLS | MNS)^)? term ((PLS | MNS)^ term)*; 
term  : power ((MLP | DIV)^ power)*; 
power  : atom (options{greedy=true;}: PWR^ power)*; 
atom  : INT | FLOAT | VARIABLE | LBR arith_expr RBR -> ^(arith_expr); 

logic_expr : logic_atom ((OR | AND)^ logic_atom)*; 
logic_atom : LBR logic_expr RBR | cmp_expr ; 
cmp_expr: arith_expr (LSS | LSQ | GRT | GRQ | EQL | NEQ) arith_expr; 

WS : (' '| '\t'| '\r') {$channel=HIDDEN;}; 

LBR : '(' ; 
RBR : ')' ; 
PLS : '+' ; 
MNS : '-' ; 
MLP : '*' ; 
DIV : '/' ; 
PWR : '^' ; 

LSS : '<' ; 
LSQ : '<=' ; 
GRT : '>' ; 
GRQ : '>=' ; 
EQL : '==' ; 
NEQ : '!=' ; 
AND : '&&' ; 
OR : '||' ; 
NOT : '!' ; 

ASSIGMENT : '=' ; 
PRINT_KEYW : 'print' ; 
SCAN_KEYW : 'scan' ; 

SEP : '\n' | ';' ; 

INT : ('0'..'9')+; 

FLOAT : INT '.' INT* EXP? | '.' INT EXP? | INT EXP; 
fragment EXP : ('e'|'E') (PLS | MNS)? INT; 

VARIABLE : SS (SS | '0'..'9')* ; 
fragment SS : 'a'..'z' | 'A'..'Z' | '_' ; 

// (LBR arith_expr)=> nie działa.

Odpowiedz

3

Rozważmy zmieniając logic_expr i cmp_expr do tego:

logic_expr : cmp_expr ((OR | AND)^ cmp_expr)*; 
cmp_expr : (arith_expr (LSS | LSQ | GRT | GRQ | EQL | NEQ))=> arith_expr (LSS | LSQ | GRT | GRQ | EQL | NEQ)^ arith_expr 
      | LBR logic_expr RBR -> logic_expr 
      ; 

usunąłem regułę logic_atom ponieważ zasłania się błąd, że dostajesz i nie dodaje wartości.

Korzystając składniową orzecznik w cmp_expr, jesteś w stanie powiedzieć, że każdy ANTLR arith_expr następnie znak logiczny będzie stosowana tylko przez arith_expr, co oznacza, że ​​wszelkie nawiasy że antlr spotkania musi należeć do wyrażenia arytmetycznego i nie logiczne.

Zapewnia to, że tylko logic_expr obsługuje wartości logiczne, a arith_expr dotyczy tylko wartości numerycznych.


Testowałem różne scenariusze ze zmodyfikowanym gramatyki i ja nie dostaję błędy w ANTLRWorks lub w moim kodu niestandardowego testowym. Czy możesz podać więcej informacji o tym, co widzisz?

Oto pełna gramatyka, której używam. Zauważ, że usunąłem language, dzięki czemu mogłem to przetestować w Javie. To powinno być w porządku, ponieważ nie ma żadnych działań/semantycznych predykatów. Wprowadziłem również kilka drobnych zmian, ale nie spodziewam się, że będą to poważne poprawki. Są oznaczone komentarzami.

grammar ArithmeticInterpreter; 

options { 
    output = AST; 
} 
//options{greedy=true;}: 

axiom : lines EOF! ; 
lines : line (SEP! line)* ; 
line : (def_var | print_expr | scan_expr)? ; 

def_var : VARIABLE ASSIGMENT^ logic_expr ; 
print_expr : PRINT_KEYW^ arith_expr ; 
scan_expr : SCAN_KEYW^ VARIABLE ; 

arith_expr : ((PLS | MNS)^)? term ((PLS | MNS)^ term)*; 
term  : power ((MLP | DIV)^ power)*; 
power  : atom (PWR^ atom)*; //<-- changed 
atom  : INT | FLOAT | VARIABLE 
      | LBR arith_expr RBR -> arith_expr //<-- changed 
      ; 

logic_expr : cmp_expr ((OR | AND)^ cmp_expr)*; 
cmp_expr : (arith_expr (LSS | LSQ | GRT | GRQ | EQL | NEQ))=> arith_expr (LSS | LSQ | GRT | GRQ | EQL | NEQ)^ arith_expr 
      | LBR logic_expr RBR -> logic_expr 
      ; 

WS : (' '| '\t'| '\r') {$channel=HIDDEN;}; 

LBR : '(' ; 
RBR : ')' ; 
PLS : '+' ; 
MNS : '-' ; 
MLP : '*' ; 
DIV : '/' ; 
PWR : '^' ; 

LSS : '<' ; 
LSQ : '<=' ; 
GRT : '>' ; 
GRQ : '>=' ; 
EQL : '==' ; 
NEQ : '!=' ; 
AND : '&&' ; 
OR : '||' ; 
NOT : '!' ; 

ASSIGMENT : '=' ; 
PRINT_KEYW : 'print' ; 
SCAN_KEYW : 'scan' ; 

SEP : '\n' | ';' ; 

INT : ('0'..'9')+; 

FLOAT : INT '.' INT* EXP? | '.' INT EXP? | INT EXP; 
fragment EXP : ('e'|'E') (PLS | MNS)? INT; 

VARIABLE : SS (SS | '0'..'9')* ; 
fragment SS : 'a'..'z' | 'A'..'Z' | '_' ; 

danego wejścia x=(2<3) następujące drzewo AST jest produkowany:

(= x (< 2 3)) 

co czyni tak:

(= x (< 2 3))

Zmodyfikowany gramatyka może również obsługiwać bardziej złożone sprawy teraz, jak x = 2 + 3 < 4 || (5^5 > 30 && 3 == 10 + 2):

(= x (|| (< (+ 2 3) 4) (&& (> (^ 5 5) 30) (== 3 (+ 10 2))))) 

a more complex graph

Więc spróbuj kopiowanie gramatykę powyżej i zobaczyć czy to rozwiązuje błąd dostać. Jeśli nie, daj mi znać więcej na temat błędu, który widzisz.

+0

Próbowałem tego również. Do tego antlrworks narysował drzewo błędów. Na przykład: 'x = (1 <2)' narysował '(... -> cmp_expr -> NoViableAltExpression)' –

+1

@AlexanderLavrukov I zaktualizowałem odpowiedź gramatyką, której użyłem do testowania i przykładowym wyjściem. Kiedy masz czas, spróbuj uruchomić tę gramatykę samodzielnie, aby zobaczyć, czy daje błędy. – user1201210

+2

@AlexanderLavrukov, upewnij się, że ** nie ** używasz interpretera podczas testów. Zamiast tego użyj debuggera. –

1

Moja szybka sugestia to łączenie wyrażeń arytmetycznych i logicznych. Zobacz przykładową gramatykę, na przykład Java.g lub cokolwiek innego. ANTLR v4 poradziłby sobie z tym bez problemu, btw.