提升精神x3:解析为结构

时间:2017-08-14 11:20:55

标签: c++ boost boost-spirit boost-fusion boost-spirit-x3

来自Boost Spirit X3教程:

  

首先,让我们创建一个代表员工的结构:

namespace client { namespace ast
{
   struct employee
   {
       int age;
       std::string surname;
       std::string forename;
       double salary;
   };
}}
     

然后,我们需要告诉Boost.Fusion关于我们的员工结构,使其成为一个   语法可以利用的一流融合公民。

BOOST_FUSION_ADAPT_STRUCT(
    client::ast::employee,
    (int, age)
    (std::string, surname)
    (std::string, forename)
    (double, salary)
)`
     

[...]   在Fusion的视图中,结构只是元组的一种形式。你可以适应任何   struct是一个完全符合的融合元组。   [...]   应用上面的折叠规则,RHS具有以下属性:       fusion::vector<int, std::string, std::string, double>   struct employee IS兼容   融合:: vector的。   因此,start的RHS在原位使用start属性(struct employee)   当它完成它的工作时。

如果我很好理解,这个逻辑很大程度上依赖于属性的顺序。

现在,我处理的情况是我需要解析像

这样的东西
Layer "L1" {
    number = 23
    color = green
    visible = true
}

进入结构

struct LayerInfo
{
    std::string layerName;
    int layerNumber;
    std::string color;
    bool visible;
}

问题是,图层属性的顺序可能会改变,这与上面提到的逻辑相反。

哪种解析成这样的结构的正确方法? 我是否需要使用语义操作?

1 个答案:

答案 0 :(得分:2)

我喜欢@llonesmiz在评论中的做法。

我不得不“使用功能组合尝试我最喜欢的X3方法”。以下是解析和传播值的方法草图。

  

缺少对财产存在/唯一性的检查。 (我认为使用基本上包含x3::with<>的{​​{1}}上下文添加是可行的。当然这样的事情需要(依赖于实现?)强制转换或删除包装。) < / p>

目前,没有发表评论:

<强> Live On Coliru

std::set<V T::*>

打印

#include <iostream>
//#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>

struct LayerInfo
{
    std::string layerName;
    int layerNumber = 0;
    std::string color;
    bool visible = false;
};

namespace Parser {
    namespace x3 = boost::spirit::x3;

    // custom type parsers
    auto quoted = rule<std::string>("quoted", x3::lexeme [ '"' >> *('\\' >> x3::char_ | ~x3::char_('"')) >> '"' ]);
    struct colors_type : x3::symbols<char> {
        colors_type() {
            this->add("red")("blue")("green")("black");
        }
    } static const colors;

    namespace detail {
        template <typename T> auto propagate(T member) {
            return [=](auto& ctx){ x3::traits::move_to(x3::_attr(ctx), x3::_val(ctx).*member); };
        }

        template <typename T> auto make_member_parser(int T::* const member) { return x3::int_ [propagate(member)]; }
        template <typename T> auto make_member_parser(bool T::* const member) { return x3::bool_ [propagate(member)]; }
        template <typename T> auto make_member_parser(std::string T::* const member) { return x3::raw[colors] [propagate(member)]; }

        template <typename T = LayerInfo, typename P>
            auto rule(const char* debug, P p) { return x3::rule<struct _, T> {debug} = x3::skip(x3::space)[p]; };

        auto property = [](auto label, auto member) {
            return rule(label, x3::as_parser(label) >> '=' >> make_member_parser(member));
        };
    }

    using detail::rule;
    using detail::propagate;
    using detail::property;

    auto name       = rule("name", "Layer" >> quoted [propagate(&LayerInfo::layerName)]);

    auto number     = property("number", &LayerInfo::layerNumber);
    auto color      = property("color", &LayerInfo::color);
    auto visible    = property("visible", &LayerInfo::visible);

    auto layer_info = name >> '{' >> +(number | color | visible) >> '}';

    auto grammar    = rule("layer_info", layer_info);
}

std::ostream& operator<<(std::ostream& os, LayerInfo const& li) {
    return os << "LayerInfo \"" << li.layerName << "\"{"
        << "number="  << li.layerNumber   << " "
        << "color="   << li.color         << " "
        << "visible=" << std::boolalpha << li.visible 
        << "}\n";
}

int main() {
    std::string const sample = R"(Layer "L1" {
    number = 23
    color = green
    visible = true
})";

    LayerInfo v;
    auto f = sample.begin(), l = sample.end();
    bool ok = parse(f, l, Parser::grammar, v);


    if (ok)
        std::cout << "Parsed: " << v << "\n";
    else
        std::cout << "Parse failed\n";

    if (f!=l)
        std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}

Wit调试信息: Live On Coliru

Parsed: LayerInfo "L1"{number=23 color=green visible=true}