連休の時間をもてあましたので、peg.rb を改造して、PEG コンパイラ・コンパイラ pegc.rb を作ってみた。使い方は、おおむね次のようになる。サンプルプログラムは次の記事に投稿する。
1. ソースリストの作り方 require 'pegc.rb' # コンパイラコンパイラのインクルード parser = Peg.new # コンパイラオブジェクトの作成 parser.mkhead('Parse') # オブジェクトプログラムのヘッダー部分の作成、引数はパーサのクラス名 (文法の定義) parser.mkend # パーサクラスの定義の終わり 以上がソースリストの記述になる。このリストを仮に foo.rb とすると、コンソールから > ruby foo.rb と入力すると、コンパイルの結果が画面に表示される。リダイレクトで、 > ruby foo.rb > bar.rb とすると、オブジェクトプログラム(パーサのクラスを定義したプログラム)が出来上がる。 簡単なプログラムだが、手作業で再帰下降構文分析のルーチンを書くことを考えたら随分楽ができる。骨組みができているので後は、動作のプログラムだけになる。(それも結構大変だが。) 2.PEG コンパイラ・コンパイラ pegc.rb class Peg def initialize @line = '' @match = '' @stack = [] end attr_accessor :line, :match, :stack def push(value) @stack.push(value) end def pop @stack.pop end def mkhead(class_name) puts <<END class #{class_name} def initialize @line = '' @match = '' @stack = [] end attr_accessor :line, :match, :stack def push(value) @stack.push(value) end def pop @stack.pop end END end def mkend puts 'end' puts end def mkterm(func_name, reg, action = '') prog = <<END def #{func_name} if (@line =~ #{reg}) @match = $& @line.sub!(#{reg}, '') #{action} return true else return false end end END puts prog end def mkandt(func_name, reg) prog = <<END def #{func_name} if (@line =~ #{reg}) return true else return false end end END puts prog end def mknott(func_name, reg) prog = <<END def #{func_name} if (@line =~ #{reg}) return false else return true end end END puts prog end def mkand(func_name, expr) prog = <<END def #{func_name} line = @line.dup stack = @stack.dup if ( #{expr} ) @line = line @stack = @stack.dup return true else @line = line @stack = @stack.dup return false end end END puts prog end def mknot(func_name, expr) prog = <<END def #{func_name} line = @line.dup stack = @line.dup if ( #{expr} ) @line = line @stack = stack return false else @line = line @stack = stack return true end end END puts prog end def mkstar(func_name, expr) prog = <<END def #{func_name} while ( #{expr} ) end return true end END puts prog end def mkseq(func_name, expr, action = '') prog = <<END def #{func_name} line = @line.dup stack = @stack.dup if (#{expr}) @match = line[0...(line.size - @line.size)] #{action} return true else @line = line @stack = stack return false end end END puts prog end def mkslash(func_name, *exprs) prog = <<END def #{func_name} line = @line.dup stack = @stack.dup END for expr in exprs prog += <<END @line = line.dup @stack = stack.dup if ( #{expr} ) return true end END end prog += <<END @line = line @stack = stack return false end END puts prog end def mkconsole puts <<END while true print 'console> ' parser.line = gets exit if (parser.line =~ /exit/) parser.program end END end def mkcheck puts <<END while true print 'check> ' puts gets end END end end
by tnomura9
| 2008-05-04 17:02
| Ruby
|
Comments(0)
|
カテゴリ
新型コロナウイルス 主インデックス Haskell 記事リスト 圏論記事リスト 考えるということのリスト 考えるということ ラッセルのパラドックス Haskell Prelude Ocaml ボーカロイド 圏論 jQuery デモ HTML Python ツールボックス XAMPP Ruby ubuntu WordPress 脳の話 話のネタ リンク 幸福論 キリスト教 心の話 メモ 電子カルテ Dojo JavaScript C# NetWalker ed と sed HTML Raspberry Pi C 言語 命題論理 以前の記事
最新のトラックバック
最新のコメント
ファン
記事ランキング
ブログジャンル
画像一覧
|
ファン申請 |
||