boost::spirit::leaf_node_dのバグ
boost 1.47.0のspirit(Qiじゃなくて古い方)で、ある言語のパーサを作ってたんですが、次のような構文規則
identifier = leaf_node_d[ lexeme_d[(alpha_p | '_') >> *(alnum_p | '_')] - keywords ];
を書いたところ、どうもうまく動作しない。
具体的にどういうことかというと、たとえば次のような入力があったとして、'abc'というパターンにマッチさせたいんですが、
... = abc; ... = /*comment*/abc; ... = abc;
次のようにマッチしてしまうんですね。
理想: 'abc' 'abc' 'abc' 現実: ' abc' ' /*comment*/abc' ' abc'
いろいろ試してみたんですが、leaf_node_dにセマンティックアクションを付けると期待通りの結果が返ってきたりで、明らかに挙動がおかしい。
で、まあ調べてみたんですが、やっぱりboost::spirit側のバグのようです。
上の記事だと足りないので補足すると、
leaf_node_dが直前のスキップパーサで弾かれた文字を含めちゃうということみたいです。
自分のコードではスキップパーサが次のようにしてあるんで、上記みたいな結果になったのだと思われます。
skip_p = +space_p | comment_p("/*", "*/");
しかし言及が2009年って、、、
修正が入ってないってことは本家に指摘されてないってこと?
とりあえず応急処置として、次のようにスキップを明示的に規則に入れることで対処できました。
identifier = no_node_d[*skip_p] >> leaf_node_d[ lexeme_d[(alpha_p | '_') >> *(alnum_p | '_')] - keywords ];
あと、文字列リテラルに一致させるつもりで書いた、次の規則もうまく動かない。
strl_p = leaf_node_d[ inner_node_d[ lexeme_d[confix_p('\"', *c_escape_ch_p, '\"')] ] ];
理想: "abcde" --> 'abcde' 現実: "abcde" --> '"abcde"'
やっぱりleaf_node_dが悪さをしているみたい。
ううむ。