SimpleCalc
簡単な構文からANTLRの基礎の基礎を固める。
まずは簡単な足し算器を
- SimpleCalc.g
grammar SimpleCalc;
options { language = Ruby; }
prog returns [result]
: r1=INTEGER '+' r2=INTEGER { $result = $r1.text.to_i + $r2.text.to_i }
;
INTEGER : DIGIT+ ;
fragment
DIGIT : '0' .. '9' ;
WS: (' '|'\t'|'\n')+ {$channel=HIDDEN};
% antlr4ruby SimpleCalc.g
次にテスト用のスクリプトファイルを用意
- test.rb
require 'rubygems'
require 'SimpleCalcLexer'
require 'SimpleCalcParser'
fetch =
begin
require 'readline'
proc do
Readline.readline ">>>", true
end
rescue LoadError
proc do
print ">>>"
l = $stdin.gets and l.chomp
end
end
puts "enter calculator expressions or 'quit' to exit"
loop do
case line = fetch.call
when /q(uit)?/i, /e(xit)?/i, nil then break
else
printf "\t=> %s\n", SimpleCalc::Parser.new( line ).prog
end
end
この記述は、1行ごと構文解析を行う。
別の場所でも使いまわしができる。
別の場所でも使いまわしができる。
- 実行してみる
% ruby test.rb enter calculator expressions or 'quit' to exit >>>2+3 =>5
Tokenのメソッド
ここでTokenのメソッドがどのようなものがあるか気になったので少し調べてみた。
r1,r2はTokenモジュール。
Tokenはlib/antlr3/token.rbで定義されている。
r1,r2はTokenモジュール。
Tokenはlib/antlr3/token.rbで定義されている。
メソッド | DataType | 説明 |
text | String or nil | トークンを文字列として取得 |
type | Integer | トークンの名前, SimpleCalcなら"INTEGER"とか |
line | Integer | トークンの行位置 |
column | Integer | トークンの列位置 |
channel | Symbol | チャネル設定,HIDDEN_CHANNELが設定されたトークンは字句解析の対象から除外される |
index | Integer | トークン番号 |
input | トークン入力 | |
start | Integer | トークン開始位置 |
stop | Integer | トークン終了位置 |
<=> | ||
concrete? | boolean | |
imaginary? | boolen | |
name | String | typeを取得 |
source_name | String | |
hidden? | boolean | トークンがhiddenかどうか |
inspect | 検査、デバッグ用? | |
hide! | トークンをhidden(隠し)に設定 | |
pretty_print | inspect内容を引数のprinterに渡す | |
range | ||
to_i | Integer | indexを数値として取得(注意としてトークンを数値に変換するものではない=>.text.to_iを使う) |
to_s | String | text.to_sと同義 |
よく使うのはもっぱらtextくらいかな。
あとは内部制御で使うものが多い。
あとは内部制御で使うものが多い。
つまり、トークンを扱うときは"text"だけ覚えておけばとりあえず問題なさそう。
メモ
- grammar SimpleCalc;とすることで、SimpleLexerクラスとSimpleParserクラスを生成する
- options { language = Ruby; }で出力形式をRuby言語とする
- fragmentはそれ自体をトークンとせずマクロ扱いにする
- $channel=HIDDEN は一致したトークンを字句解析から除外する(隠す)
足し算と引き算をする
足し算器に引き算器を追加してみた。
grammar SimpleCalc;
options { language = Ruby; }
prog returns [result]
: r=expression { $result = $r.result }
;
expression returns [result]
: r1=atom
( '+' r2=atom { $r1.result += $r2.result }
| '-' r2=atom { $r1.result -= $r2.result }
)* { $result = $r1.result }
;
atom returns [result]
: n=INTEGER { $result = n.text.to_i }
;
INTEGER : DIGIT+ ;
fragment
DIGIT : '0' .. '9' ;
WS: (' '|'\t'|'\n')+ {$channel=HIDDEN};
構文にexpressionとatomを追加した。
expressionは加減算、atomはトークン文字列を数値に変換している。
expressionをみると、returnsで返すresultを使って計算している。これで計算結果を渡す。
expressionは加減算、atomはトークン文字列を数値に変換している。
expressionをみると、returnsで返すresultを使って計算している。これで計算結果を渡す。