前回(Bisonで再入可能な構文解析器を作る(C言語版)) の続き。
先に何やったかだけ。
Flexの定義部にオプションを追加
main.l
%option reentrant
Bisonの定義部とコード部を修正
main.y
%{
#include "stdio.h"
extern void yyerror(void *scanner, char *s);
%}
%define api.pure full
%parse-param { void *scanner }
%lex-param { scanner }
%code provides {
#define YY_DECL int yylex(YYSTYPE *yylval, void *yyscanner)
}
%%
void yyerror(void *scanner, char *s) {
printf("aaa%sn", s);
}
main関数
calc.c
#include "main.tab.h"
#include "lex.yy.h"
main() {
yyscan_t scanner;
yylex_init(&scanner);
yyparse(scanner);
yylex_destroy(scanner);
}
以上。
%option reentrant をつけると、Flexが出力するヘッダファイルに yyscan_t という型が定義されます。
yyscan_t 自体は void* の typedef です。
#ifndef YY_TYPEDEF_YY_SCANNER_T
#define YY_TYPEDEF_YY_SCANNER_T
typedef void* yyscan_t;
#endif
yylex_init によって スキャナの持つ状態を格納する構造体用のメモリ領域が確保されます。
yylex_destroy によって、確保されたメモリ領域が解放されます。
yylex が yyscan_t を引数としてとるようになったので、YY_DECL も修正してやる必要があります。
また、yyparse を呼び出すときにyyscan_tを渡したいので、Bison側で yyparse の宣言を変えて、さらに yylex にも同じものを渡すように yylex に渡す引数も変えます。
これはそれぞれ %parse-param と %lex-param で指定します。
Flex は yy_error を呼び出す時にも yyscan_t を渡すように宣言を変えてくるので、
yy_errorの定義も修正します。
yy_error に限らず、Flex が作り出す関数は全て引数の最後に yyscan_t をとるようになります。
グローバル変数だった yytext などの実体はyyscan_t の指すメモリ領域に移動し、yytext などはマクロになっています。
#define yytext yyg->yytext_r
上の yyg というのは yylex関数 のローカル変数ですので、このマクロは Flexのルール部でのみ使えます。
yy_in など、yylex の外で使いたい元グローバル変数用に、 yyget_やyyset_ で始まるアクセサも定義されます。
今まで
yy_in = fp;
%option reentrant を付けた場合
yyset_in(fp, scanner)