Search code examples
c++boostc++14boost-spiritboost-spirit-x3

Parsing into structs with containers


How can use boost.spirit x3 to parse into structs like:

struct person{
    std::string name;
    std::vector<std::string> friends;
}

Coming from boost.spirit v2 I would use a grammar but since X3 doesnt support grammars I have no idea how to do this clean.

EDIT: It would be nice if someone could help me writing a parser parsing a list of strings and returns a person with the first string is the name and the res of the strings are in the friends vector.


Solution

  • Parsing with x3 is much simpler than it was with v2, so you shouldn't have too much trouble moving over. Grammars being gone is a good thing!

    Here's how you can parse into a vector of strings:

    //#define BOOST_SPIRIT_X3_DEBUG
    
    #include <fstream>
    #include <iostream>
    #include <string>
    #include <type_traits>
    #include <vector>
    
    #include <boost/fusion/include/adapt_struct.hpp>
    #include <boost/fusion/include/io.hpp>
    #include <boost/spirit/home/x3.hpp>
    #include <boost/spirit/home/x3/support/ast/variant.hpp>
    
    namespace x3 = boost::spirit::x3;
    
    struct person
    {
        std::string name;
        std::vector<std::string> friends;
    };
    
    BOOST_FUSION_ADAPT_STRUCT(
        person,
        (std::string, name)
        (std::vector<std::string>, friends)
    );
    
    auto const name = x3::rule<struct name_class, std::string> { "name" }
                    = x3::raw[x3::lexeme[x3::alpha >> *x3::alnum]];
    
    auto const root = x3::rule<struct person_class, person> { "person" }
                    = name >> *name;
    
    int main(int, char**)
    {
        std::string const input = "bob john ellie";
        auto it = input.begin();
        auto end = input.end();
    
        person p;
        if (phrase_parse(it, end, root >> x3::eoi, x3::space, p))
        {
            std::cout << "parse succeeded" << std::endl;
            std::cout << p.name << " has " << p.friends.size() << " friends." << std::endl;
        }
        else
        {
            std::cout << "parse failed" << std::endl;
            if (it != end)
                std::cout << "remaining: " << std::string(it, end) << std::endl;
        }
    
        return 0;
    }
    

    As you can see on Coliru, the output is :

    parse succeeded bob has 2 friends.