バージョン 0.10.3 では埋めこみアクションをサポートしました。
バージョン 0.10.2 では prepare が header に driver が footer になりました。
前のままでも使えますが将来は消えるかもしれません。
バージョン 0.10 では class に対応する end がなくなり、
class...rule...end の形になりました。
0.9 ではダサダサのピリオド方式をやめて { と } で囲むようにしました。
トップレベルは、規則部とユーザーコード部に分けられます。ユーザーコード部は クラス定義の後に来なければいけません。
文法ファイルには、一部例外を除いて、ほとんどどこにでもコメントを 書くことができます。コメントは、Rubyの #.....(行末) スタイルと、 Cの /*......*/ スタイルを使うことができます。
規則部は以下のような形をしています。
class クラス名 [演算子順位] [スタート規則] [トークンシンボル値定義] rule 文法記述 end"クラス名"はここで定義するパーサクラスの名前です。 これはそのままRubyのクラス名になります。
racc で生成するパーサが理解できる文法を記述します。 文法は、予約語 rule と end の間に、以下のような書式で書きます。
トークン: トークンの並び アクション ; トークン: トークンの並び アクション | トークンの並び アクション | トークンの並び アクション ; (必要なだけ同じようにつづける)書式は yacc とほぼ同じです。ただし、セミコロンは必須です。アクションがあっても 省略してはいけません。
アクションは { } で囲みます。ただしまだ対応が不十分なので、
中では % 文字列やヒアドキュメントは使えません。コメントは # タイプのみ。
正規表現は // タイプのみです
(本当は'}'がはいってなければどれも大丈夫ですが、やらないほうが無難です)。
また、アクションは省略してもかまいません。
右辺の返り値($$)は、アクションから出たときのローカル変数 result の値か、
もしくは明示的に return で返した値になります。また、result はアクション実行の前に
val[0]($1)に初期化されます。
以下に文法記述の全体の例をしめします。
rule goal: def ruls source { result = val } ; def : /* none */ { result = [] } | def startdesig { result[0] = val[1] } | def precrule # これは上の行の続きです。 { result[1] = val[1] } ; (略) end # endで規則部終了アクション内では、いくつか特別な意味をもった変数が使えます。そのような変数には、 以下のものがあります(将来この名前は変えられるようになる予定です)。かっこの中は、 yacc での表記です。
さらに、バージョン 0.10.3 からは埋めこみアクションをサポートしました。 埋めこみアクションはトークン列の途中の好きなところに記述することができます。 以下は埋めこみアクションの例です。
target: A B { puts 'test test' } C D { normal action };このように記述すると A B を検出した直後(本当は違うが。) puts が実行されます。 また、埋めこみアクションはそれ自体が値を持ちます。つまり、以下の例において
target: A { result = 1 } B { p val[1] };p val[1] は埋めこみアクションの値 1 を表示します。B の値ではありません。
さらに、意味的には埋めこみアクションは 空の規則を持つ非終端記号を追加することと全く同じ働きをします。 つまり、上記の例は以下と全く同じ意味です。
target: A nonterm B { p val[1] }; nonterm: /* void */ { result = 1 };
あるトークン上でシフト・還元衝突がおこったとき、そのトークンに演算子優先順位が設定して あると、衝突を解消できる場合があります。そのようなものとして特に有名なのは数式の 演算子と (だから演算子優先順位っていうのか (^^;; ) if...else構文です。
優先順位で解決できる文法は、うまく文法をくみかえてやれば、必ず優先順位なしでも同じ 効果を得られます。しかしたいていの場合、優先順位を設定するほうが、文法が簡単になります。
シフト・還元衝突がおこったとき、Raccはまずその規則に順位が設定されているか調べます。 規則の順位は、その規則で一番うしろにある終端トークンの優先順位です。たとえば、
target: TERM_A nonterm_a TERM_B nonterm_b ;のような規則の順位はTERM_Bの優先順位になります。もしTERM_Bに優先順位が設定されて いなかったら、優先順位で衝突を解決することはできないと判断し、 「Shift/Reduce conflict」を報告します。
演算子優先順位は、つぎのように書きます。
prechigh に近いほうが、順位の「高い」トークンです。上下をまるごとさかさまにして、
preclow...prechigh の順番に書くこともできます。
prechigh nonassoc PLUSPLUS left MULTI DEVIDE left PLUS MINUS right '=' preclowleft right nonassoc はそれぞれ「右結合」「左結合」「結合しない」をあらわします。
また、通常は還元する規則の、最後のトークンが順位を決めますが、ある規則に限って 順位をあげたいときがあります。yaccで言えば%precです。たとえば、符号反転のマイナスは 引き算のマイナスより順位を高くしないといけません。
prechigh nonassoc UMINUS left '*' '/' left '+' '-' preclow (略) exp: exp '*' exp | exp '-' exp | '-' exp = UMINUS # 順位を上げるこのように記述すると、'-' exp の規則の順位がUMINUSの順位になります。こうすることで、 符号反転の'-'は'*'よりも順位が高くなるので、正常に処理されます。
パーサをつくるためには、どの規則が「最初の」規則か、ということをRaccにおしえて やらなければいけません。それを明示的に書くのがスタート規則です。スタート規則は 次のように書きます。
start real_targetこのように書くと、real_targetの規則をスタート規則として使います。省略すると、 一番上にある規則がスタート規則になります。普通は、最初の規則を一番上にかくほうが 書きやすく、わかりやすくなりますから、start はあまりつかう必要はないでしょう。
トークンシンボルを表す値は、デフォルトでは
となっていますが、たとえば他の形式のスキャナがすでに存在する場合などは、 これにあわせなければならず、このままでは不便です。このような場合には、 token節を加えることで、トークンシンボルを表す値を変えることができます。 以下がその例です。
token PLUS 'PlusClass' # --> PlusClass MIN 'MinusClass' # --> MinusClass endデフォルトでは、トークンシンボルPLUSに対してはトークンシンボル値は:PLUSですが、 上のような記述がある場合は、PlusClassになります。 変換後の値は false、nil 以外ならなんでも使えます。
変換後の値として文字列を使うときは、次のように引用符を重ねる必要があります。
token PLUS '"plus"' # --> "plus" end
また、「'」を使っても生成された Ruby のコード上では「"」になるので注意してください。 バックスラッシュによるクオートは有効ですが、バックスラッシュは消えずにそのまま 残ります。これは仕様です。バグではありません。
PLUS '"plus\n"' # --> "plus\n" MIN "\"minus#{val}\"" # --> \"minus#{val}\"
ユーザーコード部には、パーサクラスの内部または外部で使用するRubyのコードを書きます。 raccコマンドでは、header inner footer の 3つをコードの名前として使い、それぞれを生成するファイルの特定の場所に転写しています。
ユーザーコード部の書式は以下の通りです。
---- ユーザーコードの識別子 rubyの文 rubyの文 rubyの文 ---- 次のユーザーコードの識別子 rubyの文 :行の先頭から4つ以上連続した「-」があるとユーザーコードとみなされます。 識別子は一つの単語で、そのあとには「=」以外なにを書いてもかまいません。
また、次のような文で外部ファイルをユーザーコードとしてインクルードすることもできます。
---- 識別子 = ファイル名 ファイル名 ファイル名 .....このように書くと、すべてのファイルの内容をその順番につなげたものが そのユーザーコードになります。次はその例です。
---- footer = init.rb err.rb run.rb print "this line is added, too\n"ここでは init.rb と run.rb を footer コードとして指定しています。 ----のある行の下に書いたもの(printのある行など)もつづけて加えられます。 さきほど ---- のある行の識別子のあとはなにを書いてもいいと言いましたが、 ファイルを記述する場合に限ってはなにも書くことができません。 コメントなどもだめです。正確にファイル名だけをならべて書いてください。 この制限はもちろん「対応するのがめんどくさかったから」です ^^;;;
Copyright (c) 1999,2000 Minero Aoki <aamine@dp.u-netsurf.ne.jp>