ANTLR(2) - 四則演算
お決まりの四則演算。
one-pathでAST構築なし。合成属性関係が少しわかった。大学の授業レベルならこの辺の知識でよさそう。
文法
grammar Expr; @header { package introduction; } @lexer::header { package introduction; } // entry start returns [double value] : expr ';' EOF { $value = $expr.value; } ; // +, - expr returns [double value] : left=term { $value = $left.value; } ( '+' right=term { $value += $right.value; } | '-' right=term { $value -= $right.value; } )* ; // *, / term returns [double value] : left=unary { $value = $left.value; } ( '*' right=unary { $value *= $right.value; } | '/' right=unary { $value /= $right.value; } )* ; // prefix operations unary returns [double value] : factor { $value = $factor.value; } | '+' factor { $value = + $factor.value; } | '-' factor { $value = - $factor.value; } ; // factor factor returns [double value] : NUMBER { $value = Double.parseDouble($NUMBER.text); } | '(' expr ')' { $value = $expr.value; } ; NUMBER : ('0'..'9')+ ( '.' ('0'..'9')+ )? ; SKIP : ( ' ' | '\t' | '\r' | '\n' )+ { $channel = HIDDEN; } ;
- term ( '+' term )* が書けた。LL(*)らしくEBNFはOKみたい。
returns [ ] : ... - 合成属性の定義。"expr returns [double value]" としておくと、exprルールを使った際に$expr.valueでexprルールの戻り値を取得できる。
- 戻り値の設定は、ルールの中で { $value = 100; } のように $
= ...; とする感じ。 - $NUMBER.text のように、トークンは必ず returns [String text] な属性が定義されているんだろう。
= - ルールに名前を付けるらしい。「expr : factor '+' factor」だと、{ $factor.. } とした時にどちらか判別できないため、「expr : f1=factor '+' f2=factor」と名前を付ける。ただ可読性は下がるのでどうしたもんか。
確認コード
public class ExprTest { public static void main(String[] args) throws IOException, RecognitionException { ANTLRInputStream in = new ANTLRInputStream(System.in, "UTF-8"); Lexer lexer = new ExprLexer(in); CommonTokenStream tokens = new CommonTokenStream(lexer); ExprParser parser = new ExprParser(tokens); System.out.println("result = " + parser.start()); } }
- start returns [double value] は外まで流れ出てるみたい。ExprParser#start()の戻り値がdouble型になってた。
実行結果
> echo 1 + 2 * 3; | java -cp bin;lib\antlr-runtime-3.0.1.jar introduction.ExprTest result = 7.0 > echo (1 + 2) * 3; | java -cp bin;lib\antlr-runtime-3.0.1.jar introduction.ExprTest result = 9.0