本文介绍了Boost Spirit Qi自定义合成属性(通过语义动作设置struct属性的特定成员)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个要与Spirit Qi一起解析的结构,其定义如下:

Suppose I have a structure that I want to parse into with Spirit Qi, that is defined as such:

struct data_
{
    bool export;
    std::wstring name;

    data_() : export(false) {}
};

此外,假设该结构已适应如下融合:

Also, suppose the struct has been adapted to fusion like this:

BOOST_FUSION_ADAPT_STRUCT(
    data_,
    (bool, export)
    (std::wstring, name)
)

关联的规则是:

qi::rule<Iterator, data_(), skipper<Iterator> > rule_data;

rule_data = -lexeme["SpecialText" >> !(alnum | '_')] [ boost::phoenix::at_c<0> = true ] // If this string is found, , set "export" to true
            > lexeme["Name" >> !(alnum | '_')] // this is supposed to go into the "name" member

到目前为止,它可以编译的很好.但是,名称"现在保持为空!

This compiles, so far, so good. However, "name" stays empty now!

从本质上讲,我在问:鉴于"SpecialText"在"Name"之前,我该如何正确地为"export"而不是字符串合成一个布尔属性?

So essentially, I am asking: Given that "SpecialText" precedes "Name", how would I synthesize a boolean attribute for "export" properly, rather than a string?

编辑拔掉头发之后,我偶然发现了"matches []"解析器,它似乎可以满足我的要求.

EDITAfter pulling my hair out on this, I randomly stumbled upon the "matches[]" parser, which seems to do what I want.

尽管如此,例如,如果我想返回某个字符串或其他数据类型而不是布尔值,该问题仍然以常规形式存在.本质上,如何通过语义动作设置struct属性的特定成员.

Nonetheless, the question still exists in the general form, for example, if I wanted to return a certain string or other data type instead of a bool.Essentially, how to set a specific member of a struct attribute via a semantic action.

推荐答案

如何设置结构成员.

给出一个结构S

struct S
{
    int         field1;
    std::string field2;
    int         target_field;
    bool        field3;
};

您可以像这样分配一个字段(例如target_field):

You can assign to a field (e.g. target_field) like so:

rule<It, S()> p = int_ [ phx::bind(&S::target_field, _val) = _1 ];

现在,您可以通过执行以下操作来使bind更具可读性:

Now, you can make the bind more readable, by doing something like:

auto target_field_ = phx::bind(&S::target_field, _val);

p = int_ [ target_field_ = _1 ];

概念证明: 在Coliru上直播

Proof of concept: live on Coliru

#include "boost/spirit/include/qi.hpp"
#include "boost/spirit/include/phoenix.hpp"

namespace qi  = boost::spirit::qi;
namespace phx = boost::phoenix;
typedef std::string::const_iterator It;

struct S
{
    int         field1;
    std::string field2;
    int         target_field;
    bool        field3;
};

int main()
{
    const std::string input("42");
    It f(begin(input)), l(end(input));

    S instance;

    using namespace qi;
    rule<It, S()> p = int_ [ phx::bind(&S::target_field, _val) = _1 ];

    // or, alternatively:
    auto target_field_ = phx::bind(&S::target_field, _val);
    p = int_ [ target_field_ = _1 ];

    if (parse(f, l, p, instance))
        std::cout << "Parsed: " << instance.target_field;
}

选项2(融合序列)

您可以使用 adaptation

#include "boost/fusion/adapted/struct.hpp"

BOOST_FUSION_ADAPT_STRUCT(S, (int, field1)(std::string, field2)(int, target_field)(bool, field3))

现在,您可以在语义操作中对这些序列使用凤凰号 lazy 函数:

Now you can use phoenix lazy functions on these sequences in your semantic action:

rule<It, S()> p = int_ [ phx::at_c<2>(_val) = _1 ];

我不喜欢这种风格(因为它会把表达结构降级"为……元组),但是它可能派上用场. 在Coliru上直播

I don't prefer this style (because it 'degrades' an expressive struct to ... a tuple of sorts), but it might come in handy. Live on Coliru

这篇关于Boost Spirit Qi自定义合成属性(通过语义动作设置struct属性的特定成员)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-13 12:55