From the Boost Spirit X3 tutorial:
First, let\'s create a struct representing an employee:
namespace client { namespace ast { struc
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 astd::set
. Of course such a thing needs (implementation dependent?) casts or an erasure wrapper).
For now, presented without comment:
Live On Coliru
#include
//#define BOOST_SPIRIT_X3_DEBUG
#include
#include
#include
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("quoted", x3::lexeme [ '"' >> *('\\' >> x3::char_ | ~x3::char_('"')) >> '"' ]);
struct colors_type : x3::symbols {
colors_type() {
this->add("red")("blue")("green")("black");
}
} static const colors;
namespace detail {
template auto propagate(T member) {
return [=](auto& ctx){ x3::traits::move_to(x3::_attr(ctx), x3::_val(ctx).*member); };
}
template auto make_member_parser(int T::* const member) { return x3::int_ [propagate(member)]; }
template auto make_member_parser(bool T::* const member) { return x3::bool_ [propagate(member)]; }
template auto make_member_parser(std::string T::* const member) { return x3::raw[colors] [propagate(member)]; }
template
auto rule(const char* debug, P p) { return x3::rule {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 "L1" {\n num
Layer "L1" {\n num
"L1" {\n number =
{\n number = 23\n
[L, 1]
{\n number = 23\n
LayerInfo "L1"{number=0 color= visible=false}
\n number = 23\n
\n color = green\n
LayerInfo "L1"{number=23 color= visible=false}
\n color = green\n
\n color = green\n
\n visible = true\n
LayerInfo "L1"{number=23 color=green visible=false}
\n visible = true\n
\n visible = true\n
\n visible = true\n
\n}
LayerInfo "L1"{number=23 color=green visible=true}
\n}
\n}
\n}
LayerInfo "L1"{number=23 color=green visible=true}