yyparse()でsyntax errorと言われたときのデバッグ方法
yacc/lex(bison/flex)で生成したパーサ yyparse() は、シンタクスエラーのある入力ファイルを食わせると、デフォルトでは
[syntax error]
というそっけないエラーメッセージを吐いてエラー終了する。これではどこが間違っているのか分からないので、以下の3ステップでエラーになっている理由を探る。
YYERROR_VERBOSE
y.tab.cのコンパイル時に-DYYERROR_VERBOSEを指定する。
$(CC) -c $(CFLAGS) -DYYERROR_VERBOSE $(CINC) y.tab.c
すると、エラーメッセージが少し人間に優しくなる。
[syntax error, unexpected YYYY, expecting XXXX]
これは「次はXXXXのはずなのにYYYYが出てきましたよ」というエラー。
yaccの定義ファイル(*.y)は正しく、入力ファイルが間違っているとき、YYERROR_VERBOSEするだけで問題は解決する。
yacc -v
yaccの定義ファイルにバグがあって、プログラマが期待したようなパーサが生成されていない場合は、エラーメッセージをverboseにしただけでは問題解決できないことが多い。
yacc コマンドに -v オプションを付けると、y.tab.cを出力するディレクトリに、同時にy.outputというファイルを生成する。
ここにはパーサの状態遷移ルールが人間に読めるような形で記述されているので、入力ファイルと付き合わせると「なぜ、yaccはXXXXがある位置にYYYYが来ると考えたのか」が分かる。
y.outputはあまり読みやすいものではないのだが、初期状態が「state 0」であることだけ押さえておけば、何となく読めるような気がしてくる。
YYDEBUG
y.outputを見ても何が間違っているのか分からない場合は、main()に yydebug=1; を追加し、
extern int yydebug; int main(int argc, char *argv[]) { yydebug = 1; ...
y.tab.c のコンパイルオプションに YYDEBUG を指定する。
$(CC) -c $(CFLAGS) -DYYERROR_VERBOSE -DYYDEBUG $(CINC) y.tab.c
すると、標準エラー出力にトレース情報を出力しながら動作するので、どのstateからどのstateに飛んで、何でこけたのか分かる。
Entering state 28
Reading a token: Next token is token AAAA ()
Shifting token AAAA ()
Entering state 19
Reading a token: Next token is token BBBB ()
Shifting token BBBB ()
Entering state 78
Reading a token: Next token is token XXXX ()Error: popping token YYYY ()