Lemon Parser Generatorは盛大にマクロを定義する。ヘッダオンリーのパーサを生成したいとき、これは困る。gcc -dM -Eで調べてみる。

入力したルール。

%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

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

メンバーのみ編集できます