プログラミングユーティリティ

yacc 環境

yacc パーサーは、以下のコマンドを使用して作成します。

$ yacc grammar.y

上記の grammar.yyacc 仕様が含まれているファイルです (接尾辞 .y は、他のオペレーティングシステムによって認識される表記です。必ずこの表記にする必要はありません) 。 出力は、y.tab.c という C 言語サブルーチンのファイルになります。yacc が提供する関数は、yyparse() という整数値型の関数です。

yyparse() を呼び出すと、この関数は yylex() を繰り返し呼び出します。yylex() は、ユーザーが作成する、入力トークンを取得するための字句アナライザです (「字句解析」を参照)。エラーが検出されると、yyparse() は値 1 を返しますが、エラー回復を行うことはできません。または、字句アナライザがエンドマーカートークンを返して、パーサーがそれを受け取ります。その場合には、yyparse() は値 0 を返します。

実用的なプログラムを作成するためには、ある程度の環境をこのパーサーに提供する必要があります。たとえば、C 言語のプログラムの場合は、yyparse() を呼び出す main() というルーチンを必ず定義しなければなりません。また、構文エラーを検出したときにメッセージを出力するためには、yyerror() というルーチンが必要になります。

この 2 つのルーチンは、ユーザーがいずれかの形式で提供する必要があります。yacc をすぐに使えるようにするため、デフォルトの main()yyerror() を備えたライブラリが用意されています。ライブラリには、cc コマンドに対する引数 -ly によってアクセスできます。これらのデフォルトプログラムのソースコードを以下に示します。

main() 
{ 
     return (yyparse()); 
}
# include <stdio.h> 

yyerror(s) 
char *s; 
{ 
     (void) fprintf(stderr, "%s¥n", s); 
}

このように、デフォルトプログラムは非常に単純な構造になっています。yyerror() に対する引数は、エラーメッセージ (通常は、構文エラーのメッセージ) を含んだ文字列です。平均的なアプリケーションでは、これよりも複雑な処理が求められます。通常は、プログラムは入力の行番号を監視して、構文エラーを検出したときにメッセージと共にその行番号を出力する必要があります。外部整数変数 yychar には、エラーが検出されたときの lookahead トークンの番号が含まれています (これは診断に役立つ機能です)。ほとんどの場合、main() ルーチン (たとえば引数を読み取るなど) はユーザーによって提供されるので、yacc ライブラリは小規模プロジェクトや大規模プロジェクトの初期段階でしか役に立ちません。

外部整数変数 yydebug は、通常は 0 に設定されます。これを 0 以外の値に設定した場合には、パーサーは、読み取った入力シンボルやパーサーのアクションなどを含む、アクションの詳しい説明を出力します。