Lemon Parser Generatorは盛大にマクロを定義する。ヘッダオンリーのパーサを生成したいとき、これは困る。gcc -dM -Eで調べてみる。
入力したルール。
定義されたマクロの一覧。
これは全て#undefされるべきであって、
のようなものをlemon_epilogue.hppなどという名前で用意しておけば良いのではないか。lemon_prologue.hppも用意して、既に定義されていたら退避するようなしかけも必要かもしれない。
もうすこし、続きを書いておくと、マクロのなかにはlemon.cが#defineを出力するものと、lempar.cのなかで#defineされているものの2種類がある。あと、lemonに-mオプションをつけた場合も挙動が変わる(生成されるファイルが.cだけになって、そっちにトークン用の定数定義が入る)。lemon.cが出力するかもしれないマクロは次のとおり(ソースコードから抽出)。ただし、[%name%]は%nameディレクティブで指定した文字列(デフォルトは“Parse”)。
lempar.cのほうで定義されているのは、
入力したルール。
%token_type {token} %extra_argument {builder* ctx} %left ADD SUB. %left MUL DIV. root ::= expression. { std::cout << "root ::= expression.\n"; } expression ::= expression ADD expression. { std::cout << "expression ::= expression ADD expression.\n"; ctx->push_operator<add>(); } expression ::= expression SUB expression. { std::cout << "expression ::= expression SUB expression.\n"; ctx->push_operator<sub>(); } expression ::= expression MUL expression. { std::cout << "expression ::= expression MUL expression.\n"; ctx->push_operator<mul>(); } expression ::= expression DIV expression. { std::cout << "expression ::= expression DIV expression.\n"; ctx->push_operator<div>(); } expression ::= NUMBER(x). { std::cout << "expression ::= NUMBER.\n"; ctx->push_number(x); }
定義されたマクロの一覧。
#define INTERFACE 1 #define ParseARG_FETCH builder* ctx = yypParser->ctx #define ParseARG_PDECL ,builder* ctx #define ParseARG_SDECL builder* ctx; #define ParseARG_STORE yypParser->ctx = ctx #define ParseTOKENTYPE token #define TOKEN (yyminor.yy0) #define YYACTIONTYPE unsigned char #define YYCODETYPE unsigned char #define YYNOCODE 10 #define YYNRULE 6 #define YYNSTATE 11 #define YYSTACKDEPTH 100 #define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) #define YY_ACTTAB_COUNT (15) #define YY_ERROR_ACTION (YYNSTATE+YYNRULE) #define YY_NO_ACTION (YYNSTATE+YYNRULE+2) #define YY_REDUCE_COUNT (4) #define YY_REDUCE_MAX (6) #define YY_REDUCE_MIN (-1) #define YY_REDUCE_USE_DFLT (-2) #define YY_SHIFT_COUNT (7) #define YY_SHIFT_MAX (5) #define YY_SHIFT_MIN (0) #define YY_SHIFT_USE_DFLT (-1) #define yytestcase(X)
これは全て#undefされるべきであって、
#undef INTERFACE #undef ParseARG_FETCH #undef ParseARG_PDECL #undef ParseARG_SDECL #undef ParseARG_STORE #undef ParseTOKENTYPE #undef TOKEN #undef YYACTIONTYPE #undef YYCODETYPE #undef YYNOCODE #undef YYNRULE #undef YYNSTATE #undef YYSTACKDEPTH #undef YY_ACCEPT_ACTION #undef YY_ACTTAB_COUNT #undef YY_ERROR_ACTION #undef YY_NO_ACTION #undef YY_REDUCE_COUNT #undef YY_REDUCE_MAX #undef YY_REDUCE_MIN #undef YY_REDUCE_USE_DFLT #undef YY_SHIFT_COUNT #undef YY_SHIFT_MAX #undef YY_SHIFT_MIN #undef YY_SHIFT_USE_DFLT #undef yytestcase
のようなものをlemon_epilogue.hppなどという名前で用意しておけば良いのではないか。lemon_prologue.hppも用意して、既に定義されていたら退避するようなしかけも必要かもしれない。
もうすこし、続きを書いておくと、マクロのなかにはlemon.cが#defineを出力するものと、lempar.cのなかで#defineされているものの2種類がある。あと、lemonに-mオプションをつけた場合も挙動が変わる(生成されるファイルが.cだけになって、そっちにトークン用の定数定義が入る)。lemon.cが出力するかもしれないマクロは次のとおり(ソースコードから抽出)。ただし、[%name%]は%nameディレクティブで指定した文字列(デフォルトは“Parse”)。
- [%name%]TOKENTYPE
- YYCODETYPE
- YYNOCODE
- YYACTIONTYPE
- YYWILDCARD
- YYSTACKDEPTH
- [%name%]ARG_SDECL
- [%name%]ARG_PDECL
- [%name%]ARG_FETCH
- [%name%]ARG_STORE
- YYNSTATE
- YYNRULE
- YYERRORSYMBOL
- YYERRSYMDT
- YYFALLBACK
- YY_ACTTAB_COUNT
- YY_SHIFT_USE_DFLT
- YY_SHIFT_COUNT
- YY_SHIFT_MIN
- YY_SHIFT_MAX
- YY_REDUCE_USE_DFLT
- YY_REDUCE_COUNT
- YY_REDUCE_MIN
- YY_REDUCE_MAX
lempar.cのほうで定義されているのは、
- INTERFACE
- YY_NO_ACTION
- YY_ACCEPT_ACTION
- YY_ERROR_ACTION
- yytestcase(X)
- TOKEN
コメントをかく