  {
          result = val
        }

  def : /* none */
        {
          result = []
        }
      | def startdesig
        {
          result[0] = val[1]
        }
      | def
          precrule   # これは上の行の続き
        {
          result[1] = val[1]
        }
(略)
--
アクション内では特別な意味をもった変数がいくつか使えます。
そのような変数を以下に示します。括弧の中は yacc での表記です。

  * result ($$)

左辺の値。初期値は val[0] です。

  * val ($1,$2,$3…)

右辺の記号の値の配列。Ruby の配列なので当然インデックスはゼロから始まります。
この配列は毎回作られるので自由に変更したり捨てたりして構いません。

  * _values (...,$-2,$-1,$0)

値スタック。Racc コアが使っているオブジェクトがそのまま渡されます。
この変数の意味がわかる人以外は<em>絶対に</em>変更してはいけません。

またアクションの特別な形式に、埋めこみアクションというものがあります。
これはトークン列の途中の好きなところに記述することができます。
以下に埋めこみアクションの例を示します。
--
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 : /* 空の規則 */ { result = 1 }
--

=== 演算子優先順位

あるトークン上でシフト・還元衝突がおこったとき、そのトークンに
演算子優先順位が設定してあると衝突を解消できる場合があります。
そのようなものとして特に有名なのは数式の演算子と if...else 構文です。

優先順位で解決できる文法は、うまく文法をくみかえてやれば
優先順位なしでも同じ効果を得ることができます。しかしたいていの
場合は優先順位を設定して解決するほうが文法を簡単にできます。

シフト・還元衝突がおこったとき、Racc はまずその規則に順位が設定
されているか調べます。規則の順位は、その規則で一番うしろにある
終端トークンの優先順位です。たとえば
--
target: TERM_A nonterm_a TERM_B nonterm_b
--
のような規則の順位はTERM_Bの優先順位になります。もしTERM_Bに
優先順位が設定されていなかったら、優先順位で衝突を解決することは
できないと判断し、「Shift/Reduce conflict」を報告します。

演算子の優先順位はつぎのように書いて定義します。
--
prechigh
  nonassoc PLUSPLUS
  left     MULTI DIVIDE
  left     PLUS MINUS
  right    '='
preclow
--
prechigh に近い行にあるほど優先順位の高いトークンです。上下をまるごと
さかさまにして preclow...prechigh の順番に書くこともできます。left
などは必ず行の最初になければいけません。

left right nonassoc はそれぞれ「結合性」を表します。結合性によって、
同じ順位の演算子の規則が衝突した場合にシフト還元のどちらをとるかが
決まります。たとえば
--
a - b - c
--
が
--
(a - b) - c
--
になるのが左結合 (left) です。四則演算は普通これです。
一方
--
a - (b - c)
--
になるのが右結合 (right) です。代入のクオートは普通 right です。
またこのように演算子が重なるのはエラーである場合、非結合 (nonassoc) です。
C 言語の ++ や単項のマイナスなどがこれにあたります。

ところで、説明したとおり通常は還元する規則の最後のトークンが順位を
決めるのですが、ある規則に限ってそのトークンとは違う順位にしたいことも
あります。例えば符号反転のマイナスは引き算のマイナスより順位を高く
しないといけません。このような場合 yacc では %prec を使います。
racc ではイコール記号を使って同じことをできます。
--
prechigh
  nonassoc UMINUS
  left '*' '/'
  left '+' '-'
preclow
(略)
exp: exp '*' exp
   | exp '-' exp
   | '-' exp     = UMINUS    # ここだけ順位を上げる
--
このように記述すると、'-' exp の規則の順位が UMINUS の順位になります。
こうすることで符号反転の '-' は '*' よりも順位が高くなるので、
意図どおりになります。

=== トークン宣言

トークン(終端記号)のつづりを間違えるというのはよくあることですが、
発見するのはなかなか難しいものです。1.1.5 からはトークンを明示的に
宣言することで、宣言にないトークン / 宣言にだけあるトークンに対して
警告が出るようになりました。yacc の %token と似ていますが最大の違いは
racc では必須ではなく、しかもエラーにならず警告だけ、という点です。

トークン宣言は以下のように書きます。
--
token A B C D
        E F G H
--
トークンのリストを複数行にわたって書けることに注目してください。
racc では一般に「予約語」は行の先頭に来た時だけ予約語とみなされるので
prechigh などもシンボルとして使えます。ただし深淵な理由から end だけは
どうやっても予約語になってしまいます。

=== オプション

racc のコマンドラインオプションの一部をファイル中にデフォルト値
として記述することができます。
--
options オプション オプション …
--
現在ここで使えるのは

  * omit_action_call

空のアクション呼び出しを省略する

  * result_var

変数 result を使う

です。
それぞれ no_ を頭につけることで意味を反転できます。

=== expect

実用になるパーサはたいてい無害な shift/reduce conflict を含みます。
しかし文法ファイルを書いた本人はそれを知っているからいいですが、
ユーザが文法ファイルを処理した時に「conflict」と表示されたら
不安に思うでしょう。そのような場合、以下のように書いておくと
shift/reduce conflict のメッセージを抑制できます。
--
expect 3
--
この場合 shift/reduce conflict はぴったり三つでなければいけません。
三つでない場合はやはり表示が出ます (ゼロでも出ます)。
また reduce/reduce conflict の表示は抑制できません。

=== トークンシンボル値の変更

トークンシンボルを表す値は、デフォルトでは

  * 文法中、引用符でかこまれていないもの (RULEとかXENDとか)
    →その名前の文字列を intern して得られるシンボル (1.4 では Fixnum)
  * 引用符でかこまれているもの(':'とか'.'とか)
    →その文字列そのまま

となっていますが、たとえば他の形式のスキャナがすでに存在する場合などは、
これにあわせなければならず、このままでは不便です。このような場合には、
convert 節を加えることで、トークンシンボルを表す値を変えることができます。
以下がその例です。
--
convert
  PLUS 'PlusClass'      #→ PlusClass
  MIN  'MinusClass'     #→ MinusClass
end
--
デフォルトではトークンシンボル PLUS に対してはトークンシンボル値は
:PLUS ですが、上のような記述がある場合は PlusClass になります。
変換後の値は false・nil 以外ならなんでも使えます。

変換後の値として文字列を使うときは、次のように引用符を重ねる必要があります。
--
convert
  PLUS '"plus"'       #→ "plus"
end
--
また、「'」を使っても生成された Ruby のコード上では「"」になるので
注意してください。バックスラッシュによるクオートは有効ですが、バック
スラッシュは消えずにそのまま残ります。
--
PLUS '"plus\n"'          #→ "plus\n"
MIN  "\"minus#{val}\""   #→ \"minus#{val}\"
--

=== スタート規則

パーサをつくるためには、どの規則が「最初の」規則か、ということを Racc におしえて
やらなければいけません。それを明示的に書くのがスタート規則です。スタート規則は
次のように書きます。
--
start real_target
--
start は行の最初にこなければいけません。このように書くと、ファイルで
一番最初に出てくる real_target の規則をスタート規則として使います。
省略した場合は、ファイルの最初の規則がスタート規則になります。普通は
最初の規則を一番上にかくほうが書きやすく、わかりやすくなりますから、
この記法はあまりつかう必要はないでしょう。

=== ユーザーコード部

ユーザーコードは、パーサクラスが書きこまれるファイルに、
アクションの他にもコードを含めたい時に使います。このようなものは
書きこまれる場所に応じて三つ存在し、パーサクラスの定義の前が
header、クラスの定義中(の冒頭)が inner、定義の後が footer です。
ユーザコードとして書いたものは全く手を加えずにそのまま連結されます。

ユーザーコード部の書式は以下の通りです。
--
---- 識別子
  ruby の文
  ruby の文
  ruby の文

---- 識別子
  ruby の文
     :
--
行の先頭から四つ以上連続した「-」(マイナス)があるとユーザーコードと
みなされます。識別子は一つの単語で、そのあとには「=」以外なら何を
書いてもかまいません。
