Boost Spirit x3: parse into structs

后端 未结 1 1251
无人共我
无人共我 2020-12-09 23:31

From the Boost Spirit X3 tutorial:

First, let\'s create a struct representing an employee:

namespace client { namespace ast
{
   struc         


        
相关标签:
1条回答
  • 2020-12-10 00:02

    I love @llonesmiz's approach in the comment.

    I "had to" try my favorite approach with X3 using functional composition too, though. Here's a sketch of the approach which does parse and propagate the values.

    Missing are checks on property presence/uniqueness. (I think such a thing is doable using a x3::with<> context addition that basically contains a std::set<V T::*>. Of course such a thing needs (implementation dependent?) casts or an erasure wrapper).

    For now, presented without comment:

    Live On Coliru

    #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";
    }
    

    Prints

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

    Wit debug info: Live On Coliru

    <layer_info>
      <try>Layer "L1" {\n    num</try>
      <name>
        <try>Layer "L1" {\n    num</try>
        <quoted>
          <try> "L1" {\n    number =</try>
          <success> {\n    number = 23\n </success>
          <attributes>[L, 1]</attributes>
        </quoted>
        <success> {\n    number = 23\n </success>
        <attributes>LayerInfo "L1"{number=0 color= visible=false}
    </attributes>
      </name>
      <number>
        <try>\n    number = 23\n   </try>
        <success>\n    color = green\n </success>
        <attributes>LayerInfo "L1"{number=23 color= visible=false}
    </attributes>
      </number>
      <number>
        <try>\n    color = green\n </try>
        <fail/>
      </number>
      <color>
        <try>\n    color = green\n </try>
        <success>\n    visible = true\n</success>
        <attributes>LayerInfo "L1"{number=23 color=green visible=false}
    </attributes>
      </color>
      <number>
        <try>\n    visible = true\n</try>
        <fail/>
      </number>
      <color>
        <try>\n    visible = true\n</try>
        <fail/>
      </color>
      <visible>
        <try>\n    visible = true\n</try>
        <success>\n}</success>
        <attributes>LayerInfo "L1"{number=23 color=green visible=true}
    </attributes>
      </visible>
      <number>
        <try>\n}</try>
        <fail/>
      </number>
      <color>
        <try>\n}</try>
        <fail/>
      </color>
      <visible>
        <try>\n}</try>
        <fail/>
      </visible>
      <success></success>
      <attributes>LayerInfo "L1"{number=23 color=green visible=true}
    </attributes>
    </layer_info>
    
    0 讨论(0)
提交回复
热议问题