Raccで作る奇妙なプログラミング言語
Rubyで作る奇妙なプログラミング言語 ~Esoteric Language~
- 作者: 原悠
- 出版社/メーカー: 毎日コミュニケーションズ
- 発売日: 2008/12/20
- メディア: 単行本(ソフトカバー)
- 購入: 8人 クリック: 148回
- この商品を含むブログ (69件) を見る
- Racc
- "racc 1.4.6"
- 結局一番参考になるのは無道編になるのか (以下「無道編」)
- 作者: 青木峰郎
- 出版社/メーカー: アスキー
- 発売日: 2001/02
- メディア: 単行本
- 購入: 4人 クリック: 44回
- この商品を含むブログ (57件) を見る
Racc の復習と「Hello world! 言語」
そもそも Racc の基本的な使い方ってどんなだっけ、復習がてら「HQ9+」の基礎にもなる、「Hello world! 言語」インタプリタを作ってみる、「H」があったら「Hello world!」と出力するだけの言語です。
基本の流れ
- 文法ファイル「H.y」を書く、典型的には拡張子は「.y」或は「.ry」という説もある
- raccコマンドでパーサ、インタプリタを作る「racc H.y」
- コマンドオプション適宜(racc --help)、-t (又は -g)でデバッグモードのものを作る
- -v でパーサの構造を示す「.output」ファイルも出力する
- 出来た「H.tab.rb」を実行する
- 拡張子「.tab.rb」の出力ファイル名は -oオプションで変更出来る
ということで文法ファイル
class HParser rule program : | program H { puts "Hello world!\n" } end ---- inner def parse(source) @queue = [] # (A) source.each_char{ |h| @queue << [:H, nil] if 'H' == h } # (B) #@queue << [false, nil] # (C) #@yydebug = true do_parse end # def parse(source) def next_token p @queue if @yydebug @queue.shift end # def next_token ---- footer HParser.new.parse((ARGV.size >0 ? ARGF : $stdin).read) # (D)
取り敢えず Racc の文法ファイルに必要なのは次の通り
- クラス定義の中の rule セクション、文法とアクションを書く
- 「---- inner」セクション
- 「---- footer」セクション
- 実際にソースを取ってきてパースを実行する処理 (D)
取り敢えずと言ってるのは、「do_parse, next_token」じゃなくて「yyparse」を使う書き方に移行したり、仕様が大きくなって来ると、inner や footer セクションに書いてるのはファイルを分離するようになるという含み。
@yydebug インスタンス変数は、-t(-g) オプションつきでパーサを作っているときのデバッグ出力のオン/オフ、ついでのスキャン結果のトークン列も出力するようにしてみた。これは起動オプションみる様にしてもいいかな。
それから (C) について。本来、入力が終わったらその印に [false, <何か>] を送ってやることになっている。だが、「無道編」p.63 にもあるように nil でも終わりと見做されるのでこの行はコメントアウトしても大丈夫だった。next_token は @queue が空配列なら Array#shift で nil を返す。
最後パーサを実行するところ (D)「奇妙な言語」p.33 にもあるのだけど、どういう形でパーサを呼び出すかは諸説ある。取り敢えずパーサインスタンスを new して、その parseメソッドにソースを与えるようにしてみた。余裕が出来たらソースを与えてパーサインスタンスを new するようにしよう。また、parseメソッドはパースするだけで実際実行するのは更に別メソッド(evaluateとか)にするというのも考えよう。
後ちょっと気になるのは、パースメソッドで真っ先にスキャナの実装を書いてるのにパース自体はメソッド呼び出しで済ませてる点。せめてメソッド分けたいな。