[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Bison構文解析器の正体は、yyparse
という名前のCの関数です。
ここでは、yyparse
とほかに使う必要がある関数の間の
インターフェイスの方法を示します。
構文解析器の内部では、多くの`yy'または`YY'で始まるCの識別子が 使われていることに注意してください。 本書で説明しているものを除いて、そのような識別子を 文法ファイルのアクションや追加のCプログラムの中で使うと、 問題が起きるでしょう。
4.1 構文解析器関数yyparse | ||
4.2 字句解析器関数yylex | ||
4.3 エラー報告関数yyerror | ||
4.4 アクション中で使える特別な機能 |
yyparse
構文解析を始めるには、関数yyparse
を呼び出します。
この関数は、トークンを読み、アクションを実行し、最後には入力ファイルの
終わりに達するか回復不可能な構文エラーに達して、戻ります。
読み込みを打ち切ってyyparse
関数から戻るような
アクションを書くことも可能です。
構文解析が成功する、つまり入力ファイルの終わりに達すると、
yyparse
からの戻り値が0になります。
構文解析が失敗する、つまり構文エラーが発生すると、 戻り値が1になります。
アクションの中で、次のマクロを使って、
yyparse
からただちに戻れます。
YYACCEPT
成功の印である戻り値0をともなって、ただちに戻ります。
YYABORT
失敗の印である戻り値1をともなって、ただちに戻ります。
yylex
字句解析器(lexical analyzer)関数yylex
は、
入力からトークンを認識し、構文解析器に返します。
Bisonはこの関数を自動的に生成しないので、
yyparse
から呼び出されるようにyylex
を書く必要があります。
関数yylex
は"lexical scanner"と呼ばれることもあります。
単純なプログラムでは、よく文法ファイルの最後でyylex
を
定義します。yylex
が別のソースファイルの中で定義する場合は、
そこでトークン型マクロ定義を使えるように準備する必要があります。
そのためには、`-d'オプションを指定してBisonを実行してください。
すると、マクロ定義がヘッダファイル`name.tab.h'に
書き込まれ、それを必要とするソースファイルにインクルードできます。
See section Invoking Bison。
4.2.1 yylex を呼び出す方法 | yyparse がyylex を呼ぶ方法.
| |
4.2.2 トークンの意味値 | yylex がどのように読み込んだトークンの
意味値を返さなければならないか.
| |
4.2.3 トークンのテキスト中の位置 | アクションが望むときに、どのようにyylex が
テキストの位置(行数など)を返さなければならない
か。
| |
4.2.4 再入可能構文解析器を呼び出す方法 | 純粋な構文解析器で呼び出し型の習慣がどのように 違うか (see section A Pure (Reentrant) Parser). |
yylex
を呼び出す方法 yylex
が返す値は、見つかったトークンの型に対する番号で、
入力ファイルの終わりに達した場合には0を返します。
トークンが文法規則の中で名前で参照される場合、
構文解析器ファイルの中でのその名前は、
トークン型に対する適切な番号にCのマクロとして定義されます。
したがって、yylex
は型を示すためにその名前を使用できます。
See section 記号、終端と非終端。
文法規則の中でトークンが1文字リテラルとして参照される場合には、
その文字の文字符号がトークン型に対する番号でもあります。
そこで、yylex
は、単純に文字符号を返します。
しかし、戻り値0は入力ファイルの終わりを意味するので、
ヌル文字('\0'
)の文字符号を返してはいけません。
以下に例を示します。
yylex () { … if (c == EOF) /* ファイルの終わりか調べる。 */ return 0; … if (c == '+' || c == '-') return c; /* `+' に対するトークン型が '+' であると仮定する。 */ … return INT; /* トークン型を返す。 */ … } |
このようなインターフェイスは、
lex
が生成した字句解析器を、
yylex
の定義を変えずに使えるように設計されています。
文法規則が文字列リテラルトークンを使っている場合には、
yylex
がそれに対するトークン型番号を使う、
2つの方法があります。
文法が文字列リテラルトークンに対する別名として記号トークン名を
定義しているならば、yylex
はその記号名を他のトークンの記号名と
同様に使えます。この場合、文法ファイルの中での文字列リテラルトークンの
利用は、yylex
にまったく影響しません。
yylex
は、yytname
表の中で、
複数文字トークンを見つけられます。
トークンに対する表の添え字は、そのトークン型の番号です。
複数文字トークンはyytname
の中にダブルクォート記号で囲まれて
記憶されます。
トークンに含まれる文字はエスケープされず、
表の中の文字列にそのまま書き込まれています。
トークンを構成する文字列がtoken_buffer
に記憶されていると仮定して、
yytname
からトークンを探し出すプログラムを示します。
for (i = 0; i < YYNTOKENS; i++) { if (yytname[i] != 0 && yytname[i][0] == '"' && strncmp (yytname[i] + 1, token_buffer, strlen (token_buffer)) && yytname[i][strlen (token_buffer) + 1] == '"' && yytname[i][strlen (token_buffer) + 2] == 0) break; } |
yytname
表は、%token_table
宣言をした場合にのみ生成されます。
See section Bison宣言の要約。
通常の再入可能でない構文解析器では、
トークンの意味値が広域変数yylval
に代入される必要があります。
意味値に対してただ1つのデータ型を使っている場合には、
yylval
の型もそうです。
したがって、たとえば、宣言を省略して型がint
ならば、
次のように書けます。
… yylval = value; /* 値をBisonスタックに積む。 */ return INT; /* トークン型を返す。 */ … |
複数のデータ型を使っている場合には、
%union
宣言で作られた共用体がyylval
の型になります
(see section The Collection of Value Types)。
そこで、トークンの値を代入するには、
共用体のメンバの名前を指定する必要があります。
%union
宣言の例を示します。
%union { int intval; double val; symrec *tptr; } |
すると、yylex
の中のプログラムは次のようになります。
… yylval.intval = value; /* 値をBisonスタックに積む。 */ return INT; /* トークン型を返す。 */ … |
アクションの中で`@n'機能
(see section Special Features for Use in Actions)を
使っている場合には、トークンとグループのテキスト中の位置を
見失わないように、yylex
の中で位置情報を提供する必要があります。
関数yyparse
は、ちょうど解析されたトークンのテキスト中の位置が、
広域変数yylloc
に記憶されていると仮定します。
そこで、yylex
は、yyloc
に正しいデータを記憶する必要があります。
変数yylloc
は構造体で、アクションの中で使われる場合にのみ、
メンバを初期化する必要があります。
メンバは、first_line
、first_column
、
last_line
、last_column
の4つです。
この機能を使うと、構文解析器が著しく遅くなることに注意してください。
yylloc
のデータ型は、YYLTYPE
という名前を持っています。
純粋な、つまり再入可能な、構文解析器を生成するために、
%pure_parser
をBison宣言すると、広域変数yylval
と
yylloc
を使えなくなります
(see section A Pure (Reentrant) Parser)。
このような構文解析器では、2つの広域変数の代わりに、
yylex
への引数として渡されるポインタを使います。
yylex
を次のように宣言し、
これらのポインタを通して情報を受け渡しする必要があります。
yylex (lvalp, llocp) YYSTYPE *lvalp; YYLTYPE *llocp; { … *lvalp = value; /* 値をBisonスタックに積む。 */ return INT; /* トークン型を返す。 */ … } |
文法ファイルがテキスト中の位置を参照するための`@'機能を
使っていない場合は、YYLTYPE
は定義されません。
この場合、第2引数を省略し、yylex
は
1個の引数をともなって呼び出されます。
再入可能な構文解析器を使っている場合、
再入可能な方法で構文解析器に追加の引数を渡す方法があります。
そのためには、マクロYYPARSE_PARAM
を変数名として定義します。
すると、関数yyparse
は、定義された名前で、型がvoid *
の
追加の引数を受け取ります。
yyparse
を呼び出すときに、オブジェクトの番地を
void *
型にキャストして渡します。
文法のアクションは、ポインタを適切な型へのポインタへキャストし、
逆参照して、オブジェクトの内容を参照できます。
例を示します。
%{ struct parser_control { int nastiness; int randomness; }; #define YYPARSE_PARAM parm %} |
次のように構文解析器を呼び出します。
struct parser_control
{
int nastiness;
int randomness;
};
…
{
struct parser_control foo;
… /* |
文法アクションの中では、データを参照するために次のような式を使います。
((struct parser_control *) parm)->randomness |
yylex
に追加の引数を渡したい場合には、
YYPARSE_PARAM
と同様に、マクロYYLEX_PARAM
を定義します。
例を示します。
%{ struct parser_control { int nastiness; int randomness; }; #define YYPARSE_PARAM parm #define YYLEX_PARAM parm %} |
そして、yylex
が追加の引数、parm
の値を受け取るように、
yylex
を定義する必要があります
(型YYLTYPE
のどの引数が渡されるかに応じて、
引数の合計が2個または3個になります)。
引数を正しいオブジェクト型として宣言できます。すなわちvoid *
として
宣言し、上記の番地を参照できます。
YYPARSE_PARAM
を使わずに、`%pure_parser'を使って、
再入可能な構文解析器を生成することも可能です。
その場合、引数をつけずにyyparse
を呼び出すべきです。
yyerror
Bison構文解析器は、文法規則に適合しないトークンを読むたびに、
構文解析エラー(parse error)すなわち文法エラー(syntax error)を
検出します。文法中のアクションは、マクロYYERROR
を使って、
明示的にエラーを示せます
(see section Special Features for Use in Actions)。
Bison構文解析器は、yyerror
という名前の関数を使って、
エラーを報告するようになっています。
事前に用意が必要な
この関数は、文法エラーが発生するたびに、1個の引数をともなって、
yyparse
から呼び出されます。
構文解析エラーに対して、引数の文字列は通常"parse error"
です。
Bison定義部(see section The Bison Declarations Section)で、
マクロYYERROR_VERBOSE
を定義すると、
"parse error"
の代わりに、
エラーを詳細に報告する文字列が用意されます。
マクロYYERROR_VERBOSE
の定義はなんでもかまいません。
構文解析器は、もう1種類のエラーであるスタックオーバーフローを検出する
可能性があります。これは、入力がきわめて深い入れ子からなっていると
起こることがあります。Bison構文解析器は自動的にスタックの限界を大きく拡張し
ているので、スタックオーバーフローはめったに起きません。
しかし、もしスタックオーバーフローが起きれば、
"parser stack overflow"
という
文字列の引数をともなって、yyerror
が呼び出されます。
単純なプログラムでは、次の例のようにyyerror
を定義できます。
yyerror (s) char *s; { fprintf (stderr, "%s\n", s); } |
yyerror
から戻った後、yyparse
は、
適切なエラー回復文法規則(see section エラーからの回復)があれば、
エラーからの回復を試みます。
もし、回復が不可能ならば、yyparse
は即座に1を返します。
変数yynerrs
には、それまでに出くわした文法エラーの数が記憶されています。
通常、この変数は広域変数です。
しかし、再入可能な構文解析器(see section A Pure (Reentrant) Parser)
を生成した場合には、アクションからのみ参照可能な局所変数になります。
ここの表では、アクション中で有用な、Bisonの構造物、変数、 マクロを示します。
現在の規則で作られるグループに対する意味値を保持する変数のように働きます。 See section アクション。
現在の規則のn番目の構成要素に対する意味値を保持する変数のように 働きます。See section アクション。
$$
に似ていますが、%union
宣言で指定された共用体の中の
typealtを選びます。
See section Data Types of Values in Actions。
$n
に似ていますが、%union
宣言で指定された共用体の中の
typealtを選びます。
See section Data Types of Values in Actions。
yyparse
からただちに戻り、失敗を示します。
See section The Parser Function yyparse
。
yyparse
からただちに戻り、成功を示します。
See section The Parser Function yyparse
。
トークンを逆シフトします。 1個の値を還元する規則の中で、先読みトークンがない場合にのみ、 このマクロが使えます。 このマクロは、トークン型がtokenで意味値がvalueのトークンを、 先読みトークンとして格納し、この規則で還元されるはずだった値を捨てます。
先読みトークンがすでにあるような、このマクロが無効な状況で このマクロを使うと、メッセージ`cannnot back up'をともなう 文法エラーが報告され、通常のエラー回復が行われます。
どちらの場合も、アクションの残りの部分は実行されません。
先読みトークンがない場合に、変数yychar
に記憶されている値です。
ただちに文法エラーを発生させます。この文は、構文解析器がエラーを検出したように
エラー回復を始めますが、yyerror
を呼び出さず、
メッセージは表示されません。
もし、エラーメッセージを表示したければ、`YYERROR'文よりも先に、
明示的にyyerror
を呼び出してください。
See section エラーからの回復。
このマクロの値は、字句解析器が文法エラーからの回復中ならば1、 そうでなければ0です。 See section エラーからの回復。
現在の先読みトークンを含んでいる変数です
(再入可能構文解析器では、yyparse
の局所変数です)。
先読みトークンがない場合には、この変数に
YYEMPTY
という値が入っています。
See section Look-Ahead Tokens。
現在の先読みトークンを捨てます。エラー規則の中で有用です。 See section エラーからの回復。
後に続く文法エラーに対して、エラーメッセージの生成を再開します。 これは、エラー規則で特に重要です。 See section エラーからの回復。
現在の規則の第n要素の、行番号と列番号を含む、 配列変数のように働きます。 次のようなメンバがあります。
struct { int first_line, last_line; int first_column, last_column; }; |
たとえば、第3要素の開始行番号を知るには、 `@3.first_line'とします。
この構造体のメンバを有効な情報にするためには、
yylex
がそれぞれのトークンに対して、
情報を提供する必要があります。
一部分のメンバだけが必要ならば、
yylex
はそのメンバの値を設定するだけでかまいません。
(13)
この機能を使うと、字句解析器が著しく遅くなります。
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated by Akihiro Sagawa on June, 1 2005 using texi2html 1.70.