Rubyのパーサジェネレータ Racc のメモ。Ruby 1.8以上ならばランタイムライブラリが標準ライブラリとして含まれている。
環境
% rvm -v rvm 1.25.22 (stable) by Wayne E. Seguin <wayneeseguin@gmail.com>, Michal Papis <mpapis@gmail.com> [https://rvm.io/] % ruby -v ruby 2.1.1p76 (2014-02-24 revision 45161) [x86_64-linux]
チュートリアル:calc.y にべき乗、変数を付け加える
GitHub:tenderlove/racc sample/calc.yよりサンプルプログラムを入手する。以後は以下にしたがい使い方を覚える。
コンパイルして実行してみる。
% racc -o calc.rb calc.y % ruby calc.rb
strscanでスキャナ(字句解析器)を作成する
上のチュートリアルの「パーサとスキャナの分離」まで終わっているとする。Calcp#parse()をRubyの標準ライブラリstrscanを使って書き直す。構文の定義ファイルをcalc.rbとする。
require './calc.rb' require "strscan" class Calcp def initialize @vartab = {} end def do_assign(varname, val) @vartab[varname] = val end def do_refvar(varname) @vartab[varname] end def parse(str) @q = [] s = StringScanner.new(str) until s.eos? case when s.scan(/\s+/) when s.scan(/\d+/) @q.push [:NUMBER, s[0].to_i] when s.scan(/[a-zA-Z]+/) @q.push [:IDENT, s[0]] when s.scan(/.|\n/o) @q.push [s[0], s[0]] end end @q.push [false, '$end'] do_parse end def next_token @q.shift end end parser = Calcp.new puts puts 'type "Q" to quit.' puts while true puts print '? ' str = gets.chop! break if /q/i =~ str begin puts "= #{parser.parse(str)}" rescue ParseError puts $! end end
元のCalcp#parse()では、正規表現にマッチした部分を捨てる処理があったが、strscanの場合はStringScannerオブジェクト自身がどこまで文字列を読み込んだのか覚えているのでその処理が不要になる。