Yacc
関数、変数等をC言語で記述できるパートである。構文解析器プログラムでyyparse()関数の展開が終わったあとの末尾に、そのままコピーされる。 たとえば字句解析器関数yylex()、エラー報告関数yyerror()、C言語メインプログラムmain()なども、それぞれ必要があればここに記述する。
のようにまた2個分縮む。
(このように、還元が起こるたびに、まるでゲームのテトリスで同じ色のブロックが並んだときのように、スタックが伸びてはストンストンと短くなる。還元が長く起こらないとスタックが長くなって、既定のサイズを超えるとスタックオーバフロー例外で異常終了してしまうのも、ゲームオーバーに似ている。なお、スタックオーバフローを起こさないためには、
explist: exp | explist ',' exp
のような右再帰の形を避けて
explist: exp | exp ',' explist
のような左再帰の形で定義することである。規模が大きくなる場合はスタックサイズの定義マクロYYMAXDEPTHの値を大きく指定する.)
またまた先読みしていた「-」を読み直す。今度はさすがに適用できる規則がなくシフトされる。
次にNUM《40》が読まれてもシフトするしかない。
この状態で先読みトークンに、電卓ユーザが押した改行EOLがくる。
この状態において、演算子優先度が関係ない先読みEOLに遠慮する必要がないので、
がマッチとして還元が実行されて、スタックから3個消える。その代わり、意味値が610-40=570と計算されたグループexprが押し込まれるので、
のようにまた2個分縮む。
先読みしていたEOLを読み直す。すると、この状態でexprには、
しかマッチせず、アクションのprintf関数が実行されて,
たとえば、この構文規則から生成した構文解析器が、数値トークンNUM、End Of LineトークンEOLおよび演算子からなるトークン列
を読むとしよう。
ただこの前半では、トークンNUMが何の文字列をもってそう認識するかは定義されていない。Yaccにユーザが与えたYacc文法ファイルには、通常、字句解析をするための文法が存在していないからである(もっとも、無理に字句解析までやらせることは、複雜になるが不可能ではない)。 その代わりトークンの入力は、yylex()という決まった名前の関数を呼ぶように展開される。目的の構文解析器の実行時に、Yaccによって生成されている構文解析器関数yyparse()は、ひとつひとつトークンをyylex()を呼んで要求する。yylex()はどこからか文字列を呼んでひとつトークンを返し,あれば変数lval経由でその意味値も同時に返し、ファイルの終端に達したとき(1行ごとにyyparser()から帰ってはまた呼び出す構文解析器を作るにおいては、行末に達したなどそのプログラムが解析のまとまりと認識している区切りに達したとき)はバイナリ0か負数を返して知らせる。
利用者はyylex()を自分でプログラミングするか、Lex、Flexなどの字句解析ツールを使って作成する必要がある。つまりLex、FLex、JFLexなどの字句解析器ジェネレータは、Yaccが作ってくれない関数yylex()を自動で作ってくれるツールといえる。