HaskellのParsecを,Rubyで
こんなのがあったんだなぁ.名前は,『rparsec』.
rparsec is the Haskell Parsec implemented in Ruby.
(中略)
Feature hightlight:
Operator precedence grammar
Dynamic grammar, context-sensitive grammar.A calculator parser takes 10 lines of code; A sophisticated sql language parser takes only about 250 lines of code.
ということで,ふつけるを読んだ人なら皆知っているであろう,HaskellのParsecライブラリをRubyで実装しましたよ,という代物.電卓なら10行で,洗練されたSQLパーサですらたったの250行で書けるという凄まじさ.コレを使えばWikiエンジンもスッキリと実装できるかもしれません.
また,gemではないので,newgemでも使って勝手にgem化するのもアリです.ちなみにボクはnewgemを使ってgem化,インストールしましたが,5分もかかりませんでした.作者もgem化すりゃ良いのに*1.
簡単なデモ
コチラを見ながら.
http://jparsec.codehaus.org/Ruby+Parsec
簡単なデモなので,実際にこの電卓パーサが動くかどうかを試してみましょう.
# calc.rb require 'rubygems' require_gem 'rparsec' class Calculator include Parsers include Functors def parser ops = OperatorTable.new. infixl(char(?+) >> Plus, 20). infixl(char(?-) >> Minus, 20). infixl(char(?*) >> Mul, 40). infixl(char(?/) >> Div, 40). prefix(char(?-) >> Neg, 60) expr = nil term = integer.map(&To_i) | char('(') >> lazy{expr} << char(')') delim = whitespace.many_ expr = delim >> Expressions.build(term, ops, delim) end end
ParsersとFunctorsをincludeしているようです.果たして何者なのでしょうか.では,irbで走らせてみます.
$ irb irb(main):001:0> require 'calc.rb' => true irb(main):002:0> Calculator.new.parser.parse '1+2*(3-1)' => 5 irb(main):003:0> Calculator.new.parser.parse '1+2/(3-1)' => 2
ちゃんと計算できています.
大雑把に見る
RDocを見てみると,なるほど.たとえばFunctorsの定数には,
Plus = proc {|x,y|x+y} Minus = proc {|x,y|x-y} Mul = proc {|x,y|x*y} Div = proc {|x,y|x/y}
こんな感じにprocが入ってる.30個以上.RDocを見れば概要はちゃんと書いてあるので,詳しくはそちらを.他にも,charというメソッドやinfixlなんかはHaskellの臭いがするなぁ.
HaskellのParsecライブラリを知り尽くしていたり,言語処理系に興味がある人は,是非是非.
他にも
rparsecの他にHaskellのParsecっぽいものは,tdp4rというgemがあるようだけれど,RDocが入ってなかったので使い方がイマイチわかりません.
*1:テストはしてないけれど:p