Was stimmt mit dieser Beispiel-ANTLR-3-Python-Grammatik nicht?
Frage
Ich versuche den Umgang mit ANTLR zu erlernen und bin beim Befolgen dieses „Tutorials“ offenbar auf einen Fehler gestoßen:https://theantlrguy.atlassian.net/wiki/display/ANTLR3/Five+minute+introduction+to+ANTLR+3
Im Wesentlichen erstelle ich die Datei SimpleCalc.g:
grammar SimpleCalc;
options {
language = Python;
}
tokens {
PLUS = '+' ;
MINUS = '-' ;
MULT = '*' ;
DIV = '/' ;
}
@header {
import sys
import traceback
from SimpleCalcLexer import SimpleCalcLexer
}
@main {
def main(argv, otherArg=None):
char_stream = ANTLRFileStream(sys.argv[1])
lexer = SimpleCalcLexer(char_stream)
tokens = CommonTokenStream(lexer)
parser = SimpleCalcParser(tokens);
try:
parser.expr()
except RecognitionException:
traceback.print_stack()
}
/*------------------------------------------------------------------
* PARSER RULES
*------------------------------------------------------------------*/
expr : term ( ( PLUS | MINUS ) term )* ;
term : factor ( ( MULT | DIV ) factor )* ;
factor : NUMBER ;
/*------------------------------------------------------------------
* LEXER RULES
*------------------------------------------------------------------*/
NUMBER : (DIGIT)+ ;
WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; } ;
fragment DIGIT : '0'..'9' ;
Wenn ich die ANTLR-Tools ausführe
java -classpath antlr-3.1.3.jar antlr.Tool SimpleCalc.g
Ich erhalte Fehlermeldungen, beginnend mit der ersten Zeile:
ANTLR Parser Generator Version 2.7.7 (20060906) 1989-2005
SimpleCalc.g:2:1: unexpected token: grammar
error: Token stream error reading grammar(s):
SimpleCalc.g:15:1: unexpected char: '@'
SimpleCalc.g:2:1: rule grammar trapped:
SimpleCalc.g:2:1: unexpected token: grammar
TokenStreamException: unexpected char: '@'
Das lässt mich glauben, dass ich etwas Dummes tue, aber ich bin mir nicht sicher, was.
Lösung
Du verwendest das Falsche Tool
Klasse zum Generieren des Lexers und Parsers.Die meisten ANTLR 3.x-Versionen weisen noch Abhängigkeiten zur älteren Version v2.7 auf, die daher in v3.x enthalten ist.Der Tool
Klasse aus v2.7 wird aufgerufen antlr.Tool
, während die v3.x-Version aufgerufen wird org.antlr.Tool
.Letzteres sollten Sie verwenden:
java -classpath antlr-3.1.3.jar org.antlr.Tool SimpleCalc.g
BEARBEITEN
Hier ist eine kleine Demo, die auf der Grammatik aus dem Wiki basiert, aber dann mit etwas Python-Code ergänzt wurde, der den Ausdruck auswertet:
grammar SimpleCalc;
options {
language=Python;
}
@header {
import sys
import traceback
from SimpleCalcLexer import SimpleCalcLexer
}
@main {
def main(argv, otherArg=None):
char_stream = ANTLRStringStream(sys.argv[1])
lexer = SimpleCalcLexer(char_stream)
tokens = CommonTokenStream(lexer)
parser = SimpleCalcParser(tokens);
try:
print parser.eval()
except RecognitionException:
traceback.print_stack()
}
eval returns [value]
: add EOF {$value = $add.value}
;
add returns [value]
: m1=mult {$value = $m1.value} ( '+' m2=mult {$value += $m2.value}
| '-' m2=mult {$value -= $m2.value}
)*
;
mult returns [value]
: a1=atom {$value = $a1.value} ( '*' a2=atom {$value *= $a2.value}
| '/' a2=atom {$value /= $a2.value}
)*
;
atom returns [value]
: NUMBER {$value = float($NUMBER.text)}
| '(' add ')' {$value = $add.value}
;
NUMBER : DIGIT+ ('.' DIGIT*)?;
WHITESPACE : ('\t' | ' ' | '\r' | '\n')+ {$channel = HIDDEN;};
fragment DIGIT : '0'..'9' ;
Einen Lexer/Parser generieren und einen Ausdruck auswerten:
java -cp antlr-3.1.3.jar org.antlr.Tool SimpleCalc.g
python SimpleCalcParser.py "5 * (8 + 2)"
erzeugt die Ausgabe:
50.0