语义动作后丢弃解析结果 [英] Discarding parsed result after semantic action

查看:100
本文介绍了语义动作后丢弃解析结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Boost.Spirit中,只需执行以下操作就可以从流中读取到std::vector:

In Boost.Spirit one can read from a stream to a std::vector simply by doing:

#include<vector>
#include<boost/spirit/include/qi.hpp>
namespace sqi = boost::spirit::qi;
int main(){
        std::string const v_str = "AA BB CC";
        std::vector<std::string> v;
        auto it = begin(v_str);
        bool r = sqi::phrase_parse(it, end(v_str), 
                    (*sqi::lexeme[+sqi::char_("A-Z")]), sqi::space, v);
        assert( v.size() == 3  and v[2] == "CC" );
}

但是,由于输入格式的原因,我事先知道了元素的数量,所以我应该能够保留向量中的空间. 例如,如果输入字符串为"3 AA BB CC",则可以预先分配三个元素.

However, it happens that I know the number of elements in advance because of the input format and I should be able to prereserve the space in the vector. For example if the input string is "3 AA BB CC", one can allocate in advance three elements.

问题是如何将这些额外的信息传递给向量并优化后面的push_back(例如,避免重新分配).

The question is how to pass this extra information to the vector and optimize the later push_back (e.g. avoiding reallocations).

我尝试的是在执行reserve时将一个语义动作与它相关联的开始处解析一个整数.

What I tried was to parse an integer at the beginning at associate a semantic action to it where a reserve is executed.

        std::string const v_str = "3 AA BB CC";
        std::vector<std::string> v;
        auto it = begin(v_str);
        bool r = sqi::phrase_parse(it, end(v_str), 
             sqi::int_[([&](int i){v.reserve(i);})] >> 
                (*sqi::lexeme[+sqi::char_("A-Z")]), sqi::space, v);

问题在于,在执行语义操作之后,该整数不会被忽略,并且从我的测试中可以看出,它试图将结果(示例中的3)推到保留后的向量中.

The problem is that the integer is not ignored after the semantic action and from my tests I can see that it tries to push the result (the 3 in the example) into the vector ever after reserve.

另一种解决方法是在phrase_parse函数中添加另一个参数,但这似乎是一个过大的选择.

Another workaround would be to add another argument to phrase_parse function but that seems to be an overkill.

那么,如何在Boost.Spirit中解析某些内容,并且仅执行语义操作而不将结果发送到接收器变量?

即使可以做到这一点,我也不确定这是否是正确的方法.

Even if this can be done I am not really sure if this is the right way to do it.

推荐答案

感谢@sehe和@drus指向我的链接并找到有关qi::omit的信息,我意识到我可以关联一个语义动作,然后省略结果.

Thanks to the links I was pointed to by @sehe and @drus and finding about qi::omit, I realize I can associate a semantic action and then omit the result.

我必须处理的格式是多余的(大小是元素数量的冗余),因此无论如何我都必须 省略.

The format I have to handle is redundant (the size is redundant with the number of elements), so I have to semantically omit something in any case.

    using namespace sqi;
    std::string const v_str = "3 AA BB CC";
    {
        std::vector<std::string> v;
        auto it = begin(v_str);
        bool r = sqi::phrase_parse(
            it, end(v_str), 
            omit[int_] >> *lexeme[+(char_-' ')],
            space, v
        );
        assert( v.size() == 3 and v[2] == "CC" );
    }

但这并不意味着我不能将省略(冗余)的部分用于优化目的或一致性检查.

But doesn't mean that I cannot use the omitted (redundant) part for optimization purposes or consistency check.

    {
        std::vector<std::string> v;
        auto it = begin(v_str);
        bool r = sqi::phrase_parse(
            it, end(v_str), 
            omit[int_[([&](int n){v.reserve(n);})]] >> *lexeme[+(char_-' ')],
            space, v
        );
        assert( v.size() == 3 and v[2] == "CC" );
    }

我同意语义动作是邪恶的,但是在我看来,只有当它们改变接收器对象的状态时,它才是邪恶的. 有人可以说reserve不会改变向量的状态.

I agree that semantic actions are evil, but in my opinion only when they change the state of the sink objects. One can argue that reserve does not change the state of the vector.

事实上,通过这种方式,我可以通过reserve优化内存使用,还可以通过使用repeat而不是无限制的kleene *优化解析器的执行. (显然repeat可能会更有效率).

In fact, this way I can optimize memory usage by reserve and also the parser execution by using repeat instead of the unbounded kleene*. (Apparently repeat can be more efficient).

    {
        std::vector<std::string> v;
        auto it = begin(v_str);
        int n;
        bool r = sqi::phrase_parse(
            it, end(v_str), 
            omit[int_[([&](int nn){v.reserve(n = nn);})]] >> repeat(phx::ref(n))[lexeme[+(char_-' ')]],
            space, v
        );
        assert( n == v.size() and v.size() == 3 and v[2] == "CC" );
    }

(取消phx::ref是基本的,因为必须延迟对n的评估)

(unsing phx::ref is fundamental because the evaluation of n has to be delayed)

这篇关于语义动作后丢弃解析结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆