yacc の規則

文法ファイルの規則セクションには、1 つ以上の文法規則が入っています。 それぞれの規則は、 構造体を記述するとともにその名前を与えています。

文法規則は、次の形式で記述されます。
A : BODY;

ここで、A は非終端名であり、 BODY は 0 個以上の名前、 リテラルおよび意味構造アクションのシーケンスで、 その後にオプショナルで優先度規則を続けることができます。 文法を構成するために必須なものは、名前とリテラルだけです。 意味構造アクションと優先度規則は、オプショナルです。 コロンとセミコロンは、yacc には必須の句読点です。

意味構造アクションを使用すると、 入力プロセスで規則が認識されるたびに実行するアクションを関連付けることができます。 アクションは任意の C ステートメントであり、C ステートメントとして、 入力または出力の実行、サブプログラムのコール、または外部変数の変更を行うことができます。 またアクションは、パーサーのアクション、 例えばシフトや縮小などのアクションを参照することもできます。

優先規則は %prec キーワードによって定義され、 ある特定の文法規則と関連した優先順位を変更します。 予約記号 %prec は、 文法規則のすぐ後に置くことができ、後にトークン名またはリテラルを続けることができます。 この構成によって、文法規則の優先度がトークン名またはリテラルの優先度になります。

非終端名の繰り返し

複数の文法規則に同じ非終端名がある場合、 左側の書き直しを避けるために、| (パイプ記号) を使用してください。 さらに、パイプ記号によって結合するすべての規則の最後だけに ; (セミコロン) を使用します。 例えば、次の文法規則があるとします。
A  :  B  C  D  ;
A  :  E  F  ;
A  :  G  ;
これは、次のようにパイプ記号を使用することによって、yacc コマンドに指定することができます。
A  :  B  C  D
   |  E  F
   |  G
   ;

文法ファイルでのリカージョンの使用

リカージョン とは、 関数を定義するためにそれ自体を使用する過程です。 言語定義では、これらの規則は、通常次のような形式を取ります。

rule    :        EndCase
        |        rule EndCase

したがって、rule の最も単純なケースは EndCase ですが、 rule は複数の EndCase のオカレンスで構成される場合もあります。 2 番目の行の rule の定義で rule を使用しているのは、リカージョンです。 パーサーは、ストリームが縮小されて最終的な EndCase になるまで、入力を循環して解析します。

規則の中でリカージョンを使用する場合、常にその規則内の左端の項目として、 規則の名前を書きます (前の例のように)。 規則の名前の呼び出しが、次の例のように行の後の方にあると、パーサーは、 内部スタック・スペースを使い尽くして、停止してしまう場合があります。
rule    :       EndCase
        |       EndCase rule

次の例は、line 規則を、 その後に改行文字 (¥n) が続く文字列の 1 つまたは複数の組み合わせの形で定義します。

lines   :        line
        |        lines line
        ;

line    :        string '¥n'
        ;

空文字列

空文字列を突き合わせる非終端記号を示す場合は、 規則の本体の中に ; (セミコロン) を単独で使用します。 文字列を突き合わせる記号を定義するには、 次のような規則を使用します。
empty   :  ;
        | x;
または
empty   :
        | x
        ;

入力の終わりマーカー

字句解析プログラムは入力ストリームの終わりに達すると、 入力の終わりマーカーをパーサーに送ります。 このマーカーは、終了マーカー と呼ばれる特殊なトークンであり、トークン値は 0 です。 パーサーは、入力の終わりマーカーを受け取ると、 定義された文法規則にすべての入力を割り当てたかどうか、 および処理済みの入力が完全な単位 (yacc 文法ファイルで定義されている) になっているかどうかを検査します。 入力が完全な単位である場合パーサーは停止します。 そうでない場合はエラーのシグナルを送って停止します。

字句解析プログラムは、ファイルの終わりやレコードの終わりなどの、 適切な時期に入力の終わりマーカーを送る必要があります。