简单的动作会破坏Spirit X3的结果

时间:2019-05-03 07:54:16

标签: c++ parsing boost-spirit-x3 semantic-actions

我有这个Spirit X3解析器

    auto xyz_def = 
        x3::omit[x3::int_] >> x3::eol >> 
        (x3::lexeme[+(x3::char_ - x3::eol)]) >> x3::eol >>
        (*(chemical::parser::atom >> x3::eol)
    ;

可以解析,就像这样

2
Comment
H 1.2 3.2 4.5
C 1.1 9.1 8.5

现在,我想使用(而不是完全忽略)第一个整数作为提示来帮助构建矢量(来自Kleen *)。 为此,我做了:

    auto xyz_def = 
        x3::omit[x3::int_[([](auto& ctx){x3::_val(ctx).reserve(x3::_attr(ctx));})]] >> x3::eol >> 
        (x3::lexeme[+(x3::char_ - x3::eol)]) >> x3::eol >>
        (*(chemical::parser::atom >> x3::eol)
    ;

但是,当我这样做时,尽管解析函数成功了,但结果还是空的。这尤其神秘,因为原则上,语义动作没有明显的副作用。

我发现了这种解决方法,该方法是明确引入所有语义动作。

    auto xyz_def = 
        x3::omit[x3::int_[([](auto& ctx){x3::_val(ctx).reserve(x3::_attr(ctx));})]] >> x3::eol >> 
        (x3::lexeme[+(x3::char_ - x3::eol)])[([](auto& ctx){x3::_val(ctx).comment = x3::_attr(ctx);})] >> x3::eol >>
        (*(chemical::parser::atom >> x3::eol)[([](auto& ctx){x3::_val(ctx).atoms.insert(end(x3::_val(ctx).atoms), x3::_attr(ctx));})])
    ;

这显然是一个过大的杀伤力。 为什么当我在第一个元素中仅添加一个语义动作时,我必须为所有元素添加语义动作?

我最近问了一个similar question,但是我使用的是错误版本的Spirit(Qi),而且我现在也使用属性而不是捕获lambda,以便可以定义独立的规则。

完整代码为here,可以粘贴到https://wandbox.org/

1 个答案:

答案 0 :(得分:0)

偶然地,在阅读rule /usr/include/boost/spirit/home/x3/nonterminal/detail/rule.hpp的代码时,我注意到它具有第三个模板参数,称为“力属性”。

    template <typename ID, typename Attribute = unused_type, bool force_attribute = false>
    struct rule;

好吧,事实证明,放true可以使预期结果起作用。

    x3::rule<class xyz_, chemical::xyz, true> const xyz = "xyz";

(在x3::rule<class xyz_, chemical::xyz> const xyz = "xyz";之前)