単純なRaccの使い方

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

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

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


$ racc parse.y

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

自分でパーサを作る

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

(以下、yacc を知っていることが前提)
yacc は yyparse(関数)を生成しますが、 racc は yyparse に相当する do_parse メソッドを持ったパーサクラスを生成します。 生成されるクラスは全て 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 ではそれを上から順番に header inner footer と呼んでいます。 0.10.1 までは prepare inner driver でしたがかっこわるいので変更しました。 ただし、互換性のため前のままでも使えるようになっています。 ユーザーコードは以下のように書きます。


---- header = header.rb
---- inner

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

header のような書きかたをすると、header.rb というファイルがその部分に使われます。
一方 inner では直接コードを記述しています。この例で記述している二つのメソッドは 特別な意味を持っていて、パースするときに呼びだされます。next_token はその通りの意味で、 Racc における yylex です。トークンシンボルとその値の二要素を持つ配列を返すようにします。 またスキャンが終了して、もう送るものがない場合は [false,false] を返してください。
driverはここでは必要ないので省略しました。どのパートも省略できます。

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


Copyright (c) 1998-1999 Minero Aoki <aamine@dp.u-netsurf.ne.jp>