単純なRaccの使い方

ひとの作ったパーサを使う

もうすでに文法ファイルがある場合です。この場合は単にraccコマンドが使えればよく、 文法ファイルの書きかたを覚えたりする必要はありません。

文法ファイルの名前が parse.y と仮定すると、コマンドラインから以下のように 打ちこむことで、パーサを含んだファイルが得られます。


$ racc parse.y

生成されるファイルはデフォルトでは "ファイル名.tab.rb" になります。 これは -o オプションで変更できます。

自分でパーサを作る

自分でraccの文法ファイルを記述する場合です。 racc は yacc を知っていることを前提にしていますので、もし知らないのなら 先に yacc を勉強しましょう。いきなり racc を使うのは不可能です。(これは断言できます)

(以下、yacc を知っていることが前提)
yacc は yyparse(関数)を生成しますが、racc はパーサクラスを生成します。 生成されるクラスは全て Parser の下位クラスで、名前は文法ファイル中で指定します。 以下に文法ファイル全体の概形を示します。


class MyParser

rule
  target: exp ;
  exp: tok     { print val[0] }
     | exp tok { print val[1] };  # コメント
  tok: A | '+' | '-';             /* これもコメント */
end

Rubyスクリプトのように class でクラス名を指定し、rule ... end の間に文法を記述します。 アクションは、yacc と同じように規則のあとに { と } で囲んで指定します。 当然ながら、アクションはRubyの文で記述します。 yacc の $1 $2... は racc では配列 val で、$$ は result です。
また、yacc だと終端記号を %token で指定する必要がありますが、racc ではそのような 指定は必要ありません。左辺に来ないトークンはすべて終端記号とみなされます。

演算子の優先順位(と結合)は class ... rule の間に以下のように書きます。


  prechigh
    right    kNOT
    left     '+' '-'
    left     kIF_MOD kUNLESS_MOD
    nonassoc tEQ
  preclow

prechigh と preclow が逆でも構いません。

yacc では生成されたコードに直接転写されるコードがありました。racc でも同じように、 ユーザ指定のコードが書けます。racc ではクラスを生成するので、クラス定義の前/中/後の 三個所があります。racc ではそれぞれを適当に prepare inner driver と呼んでいます。 ユーザーコードは以下のように書きます。


---- prepare = prepare.rb
---- inner

  def yylex
    @scanner.scan if @tokens.empty?
    @tokens.shift
  end

  def yyunput( arr )
    @tokens.unshift arr
  end

prepare のような書きかたをすると、prepare.rb というファイルがその部分に使われます。
一方 inner では直接コードを記述しています。この例で記述している二つのメソッドは 特別な意味を持っていて、パースするときに呼びだされます。yylex はその通りの意味で、 トークンシンボルとその値の二要素を持つ配列を返すようにします。 またスキャンが終了して、もう送るものがない場合は nil を返してください。 yyunput は同じ形式の配列を書き戻すためのものです。この二つがない場合、 パース途中で例外が発生します。
driverはここでは必要ないので省略しました。どのパートも省略できます。

これだけあればだいたい書けると思います。racc に -g オプションをつけ、@yydebug を true にセットするとデバッグ用の出力が得られます。また、-v オプションをつけると .output が得られます。どちらもデバッグの参考になるでしょう。
これ以上の個々の詳細は 文法リファレンスを参照してください。


Copyright(c) 1998-1999 Minero Aoki