Exagon Exagon - 3 months ago 8
C++ Question

parsing a single value into an ast node with a container

My problem is the following. I have an ast node which is defined as like the following:

struct foo_node{
std::vector<std::string> value;
}


and I have a parser like this for parsing into the struct, which works fine:

typedef x3::rule<struct foo_node_class, foo_node> foo_node_type;
const foo_node_type foo_node = "foo_node";
auto const foo_node_def = "(" >> +x3::string("bar") >> ")";


Now I want to achieve that the parser also parses
"bar"
, without brackets, but only if its a single bar. I tried to do it like this:

auto const foo_node_def = x3::string("bar")
| "(" > +x3::string("bar") > ")";


but this gives me a compile time error, since
x3::string("bar")
returns a string and not a
std::vector<std::string>
.
My question is, how can I achieve, that the
x3::string("bar")
parser (and every other parser which returns a string) parses into a vector?

Answer

The way to parse a single element and expose it as a single-element container attribute is x3::repeat(1) [ p ]:

Live On Coliru

#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <iostream>

namespace x3 = boost::spirit::x3;

struct foo_node {
    std::vector<std::string> value;
};

BOOST_FUSION_ADAPT_STRUCT(foo_node, value)

namespace rules {
    auto const bar 
        = x3::string("bar");

    auto const foo_node
        = '(' >> +bar >> ')'
        | x3::repeat(1) [ +bar ]
        ;
}

int main() {
    for (std::string const input : {
            "bar",
            "(bar)",
            "(barbar)",
            })
    {
        auto f = input.begin(), l = input.end();

        foo_node data;
        bool ok = x3::parse(f, l, rules::foo_node, data);

        if (ok) {
            std::cout << "Parse success: " << data.value.size() << " elements\n";
        } else {
            std::cout << "Parse failed\n";
        }

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

Prints

Parse success: 1 elements
Parse success: 1 elements
Parse success: 2 elements