デバッグのための情報


デバッグの流れと注意点

まず、規則ファイルを書きます。拡張子に制限はないので好きなものにしてください。 生成するファイルの拡張子は、デフォルトでは.tab.rbになりますが、racc.rbの -oオプションで変更できます。また、-vオプションをつけてコンパイルするとyaccと 同様に、内部情報が.outputファイルに出力されます。このファイルの情報は デバッグには必須でしょう。デバッグ中は常に-vgをつけてコンパイルすることを おすすめします。

規則ファイルをコンパイルします。たぶんパースエラーが出るでしょうね。 特に注意すべきは、ひとつの規則の最後に「必ず」セミコロンが必要なことです。 (例 word: ATOM | QUOTED ; )たとえアクションがあっても必要です。 また、縦棒(|)のまえにセミコロンがあってはいけません。(pascalか?)

ただ、徐々に減ってはいますが、現時点ではまだまだバグの可能性も高いです。 もし「これはバグに違いない!」というエラーに遭遇したらメールをください。 そのときは、規則ファイルなどもつけてくださるようお願いします。

パースは通ったら、パーサ自身のデバッグです。一番ありがちな問題は、衝突でしょうか。 衝突があると、yacc同様にraccもコンパイル後に「衝突がある」とメッセージをだすので すぐわかります。.outputファイルにはさらに詳しい情報が出力されます。それをどうやって 解決するか、とかそういうことに関しては…それなりの本を読んでください。とても ひとことでは言えません。(おすすめの本はやはりNutshellのlex&yaccでしょう)

あと結構あるのが、racc独自の問題です。たとえば、パーサクラスのprivateメソッドに 関係するものです。特に注意したいのは、「スキャンが終了したら必ずfalseを送る」と いうことです。これは自分自身いまだに忘れます。falseじゃなくてnilならそういうことは 起きなそうですが諸事情によりnilは使えません。

それから、next_tokenのほうに返すべき情報をまちがってnext_valueに返すというのも ぼくはよくやります。とくに、トークンをArrayにキャッシュしているとそういう 間違いをしやすくなります。

Known Bugのスキャナとのからみ。
パーサが先読みトークンを読んだ結果還元が起こり、そのアクションの中でスキャナの モードを変えると、先読みトークンとその次のトークンが違ってしまう可能性があります。 両方のトークンでの動作が同じならいいですが、もし違う場合は、「100%確実に」そこで パースエラーです。これは当分解決できそうにないので、「各自注意してください」 としか言えません。
yaccはこういうのをどうしているんだろう。どなたかご存知でしたらお知らせください。

最後に論理的なバグの修正。
raccに-gオプションをつけてコンパイルすると、デバッグ用のコードが付加されます。 ここで、パーサクラスのインスタンス変数@__debug__をtrueにしておいてから do_parseを呼ぶと、デバッグ用メッセージを出力します。パーサがシフト/還元していく 様子が直接見えますので、「LALRを知っていれば」、完全に現在の状態を把握できます。


yaccとの文法の違い

定義部

yaccでは%がいっぱいでてきますが、raccでは%は出てきません。それから、 Cは変数に型があるためにそれを指定する文法がたくさんありますが、Rubyは 型無しですからそっち関係のものはなくなっています。

yaccでは終端記号(トークン)を事前に指定しますが、raccでは左辺にこないものを自動的に 終端記号とみなします。ということはつまり、非終端記号nontermをnotermと書きまちがったが ために、それが終端記号とみなされて、妙なことになる可能性があるということです。 これを防止するためには、.outputファイルを出力させて、変なものが終端記号になって いないか(もちろんその逆も)チェックするとよいでしょう。 (-vオプションをつけると.outputファイルが生成されます) これをチェックできるように文法を追加する予定もあります。

yaccでの%precはraccではpreclow...prechighです。

クラス名を指定するclass...endがふえています。それから、classに対応するendを 書きわすれないでください。といいつつ自分でもよく忘れるのですが。
もしかすると、そのうち class...end はブロック構造じゃなくなるかも。

規則部

規則部分は yacc とほぼ同じですが、最大の違いは、規則の最後にセミコロンが必須なことです。

%precは=をつかいます。

yacc ではコメントは /* ... */ だけですが racc では #...(行末) もあります。

ユーザーコード部

yacc ではユーザーコードを分類する必要はありませんが、racc ではパーサがクラスなので、 配置する場所によってユーザーコードを分類しています。ユーザーコードの指定方法も 0.9 で ---- を使うように大きく変わったので気をつけてください。


Copyright(c) 1998-1999 Minero Aoki.