2009-03-18
■ [ruby] Ruby用PEGパーザ、Treetopを使ってみる
TreetopはRuby用のPEG(解析表現文法)のpackrat parserである。 よく分かってないけど、そういうものらしい。
PEGの特徴については適宜google検索してもらうとして(ひどい)、ここではTreetopを使って簡単な文法をパーズしてみた。
1. インストール
gem install treetop
Vim使いはvim用の色付けもインストールしておくと良いかも。
2. 文法を書く
パーザといったら(異論もあろうが)四則演算である。リファレンスを参考に、とりあえず足し算だけの文法を定義してみよう。
dentaku.treetop:
grammar Dentaku rule additive (number "+" number) / number end rule number [0-9]+ end end
使う側はこんな感じ。
den.rb:
require 'treetop' require 'dentaku' p DentakuParser.new.parse("1+2+3")
(環境によってはrequire 'rubygems'が必要だろう。)
dentaku.rbというファイルは存在しないが、treetopには*.treetopを直接ロードし、コンパイルして使うという機能がある(気持ち悪いw) のでこれで良い。
ちなみに
$ tt dentaku.treetop
とすることで、文法のプリコンパイルを行うこともできる(dentaku.rbというファイルが生成される。ファイル名は-oで変更可)。
3. 動かしてみる。
$ ruby den.rb SyntaxNode+Additive0 offset=0, "1+2+3" (number,additive): SyntaxNode offset=0, "1": SyntaxNode offset=0, "1" SyntaxNode offset=1, "+" SyntaxNode+Additive0 offset=2, "2+3" (number,additive): SyntaxNode offset=2, "2": SyntaxNode offset=2, "2" SyntaxNode offset=3, "+" SyntaxNode offset=4, "3": SyntaxNode offset=4, "3"
よく分からないが、とりあえずパーズできているみたいだ。
4. アクションを定義する
パーズができたので、yaccでいうところのアクションを定義しよう。
Treetopでは、非終端記号(上で言うSyntaxNode)にメソッドを定義することでアクションの実装を行う。
(いろいろ試した結果)以下のようなdentaku.treetopになった。
grammar Dentaku rule additive number "+" additive { def value number.value + additive.value end } / number end rule number [0-9]+ { def value text_value.to_i end } end end
使う側は以下。
require 'treetop' require 'dentaku' result = DentakuParser.new.parse("1+2+3") p result p result.value
実行結果。
$ ruby den.rb SyntaxNode+Additive1+Additive0 offset=0, "1+2+3" (number,value,additive): SyntaxNode+Number0 offset=0, "1" (value): SyntaxNode offset=0, "1" SyntaxNode offset=1, "+" SyntaxNode+Additive1+Additive0 offset=2, "2+3" (number,value,additive): SyntaxNode+Number0 offset=2, "2" (value): SyntaxNode offset=2, "2" SyntaxNode offset=3, "+" SyntaxNode+Number0 offset=4, "3" (value): SyntaxNode offset=4, "3" 6
動いているようだ。
あとは公式サイトなど見て頑張ってください。