「Hello world! 言語」再び
前記、スキャナを別メソッドにする、そしてその辺の呼び出しは yyparse を使う、@queue のようなものは必要なくなった。initializeメソッドで @sourceインスタンス変数にソースを格納するようにしてみる。あと、デバッグオプションは OptionParser と OpenStruct を使う。OptionParserのメッセージ類も少し書く。
「---- header」セクションも作ってバージョンなど。それからマジックコメントもここに書いておく、しかし実行ファイルの本当の先頭にコピーされるわけではないので余り意味はない。
class HParser rule# class HParser program : | program 'H' {puts "Hello world!\n"} end # class HParser ---- inner def initialize(source) @source = source end # def initialize(source) def scan @source.each_char{ |h| yield [h, nil] if 'H' == h } yield nil # (A) end # def scan def parse(opts = nil) @yydebug = opts.yydebug if opts.respond_to? :yydebug yyparse self, :scan end # def parse(opts = nil) ---- header # -*- coding: utf-8; -*- Version = '$Id: Hhyy.y 3236 2009-01-31 06:00:02Z hs9587 $' # $Date: 2009-01-31 15:00:02 +0900 (土, 31 1 2009) $ ---- footer require 'optparse' require 'ostruct' opts = OpenStruct.new opts.yydebug = false ARGV.options do |opt| opt.on('--[no-]yydebug', 'debug mode (from racc -t) on/off'){ |v| opts.yydebug = v } opt.release = '0.1' opt.banner += "\n\tH the 'Hello world!' interpreter.\nOptions:" opt.parse! end # ARGV.options do |opt| HParser.new((ARGV.size > 0 ? ARGF : $stdin).read).parse(opts)
入力の終わり、next_tokenメソッドを使っていたときは @queue が最後に nil を返してくれたが、今の場合は明示的に nil を yield してやる (A)。