2

If I have a struct:

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

or

enum class gender_t{male, female}
struct person{
        gender_t gender;
        std::string name;
        std::vector<std::string> friends;
}

how can I parse into this struct using boost.spirit X3? how would a rule look like to parse a string like "alice male bob" and the parser returning a object with name alice, which is male and has one friend bob. How would it look like if the gender is only explicit said if the person isnt female?

Exagon
  • 4,798
  • 6
  • 25
  • 53
  • 3
    I don't get the problem... What code have you written in an attempt to solve this? It's just splitting a space delimited string. – Christopher Schneider Jun 10 '16 at 13:33
  • What have you tried? I think you are unlikely to find someone willing to write the code for you, but if you show us what you have tried so far someone is likely willing to help you along then. – SirGuy Jun 10 '16 at 15:24
  • parsing into structs is not the problem but I have no idea how to parse into a struct with a enum, thats the problem I dont even have an idea – Exagon Jun 10 '16 at 15:27

2 Answers2

7

This is exactly what Spirit's symbol table is for – indeed, it is one of the primary tutorials in the Spirit documentation (Spirit.X3: Roman Numerals).

First you need to adapt your type appropriately:

struct person {
    std::string name;
    gender_t gender;
    std::vector<std::string> friends;
};
BOOST_FUSION_ADAPT_STRUCT(person, name, gender, friends)

N.b. I've changed the order of the members – since we want to parse name -> gender -> friends, it's easiest if we structure our type that way as well. Now, the parsing:

person parse_person(std::string const& str) {
    namespace x3 = boost::spirit::x3;

    struct gender_table : x3::symbols<gender_t> {
        gender_table() {
            add ("male"   , gender_t::male)
                ("female" , gender_t::female);
        }
    } const gender;
    auto const word = x3::lexeme[+~x3::space];
    auto const parser
      =    word                                  // name
        >> (gender | x3::attr(gender_t::female)) // gender
        >> *word;                                // friends

    person ret{};
    x3::phrase_parse(str.cbegin(), str.cend(), parser, x3::space, ret);
    return ret;
}

Online Demo

(If you don't want to change the order of your data members to accommodate ease of parsing, then here is one approach to make all of this non-intrusive.)

ildjarn
  • 62,044
  • 9
  • 127
  • 211
  • 3
    I think `parser = word >> (genders | x3::attr(gender_t::female)) >> +word` could also work. – llonesmiz Jun 10 '16 at 18:54
  • @jv_ : Yes, much improved, thanks! My solution didn't satisfy me but I couldn't think of an alternative offhand that didn't involve `x3::rule`. It's so obvious now... ;-] – ildjarn Jun 10 '16 at 19:11
  • Wow with the x3::attr() this answer is perfect, exactly what I was looking for. Thank you – Exagon Jun 10 '16 at 22:40
0

For using boost spirit x3 as parser, visit this link.

The documentation of boost::Spirit

For the question:

How would it look like if the gender is only explicit said if the person is not female?

I think is more flexible use enum class Gender : uint8_t, because you can add unspecified gender for example.

Community
  • 1
  • 1
chema989
  • 3,962
  • 2
  • 20
  • 33
  • 2
    I am actually interested in parsing with boost spirit x3 direct into a struct with an enum or a bool member, my example is just a MCVE – Exagon Jun 10 '16 at 15:12