c++ - Boost Spirit X3 eol unexpected behaviour -
this question in strictly related boost-spirit-x3-parse-into-structs
i have grammar
#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 sectioninfo { std::string name; int number = 0; float pitch = 0.0f; int visible = 0; float mincutstblsize = 0.0f; //technology section attributes float gridresolution = 0.0f; float lengthprecision = 0.0f; }; const char start_section = '{'; const char end_section = '}'; const char quote = '"'; const char equals = '='; const char* layer_section = "layer"; const char* technology_section = "technology"; const char* number_attr = "layernumber"; const char* visible_attr = "visible"; const char* color_attr = "color"; const char* pitch_attr = "pitch"; const char* min_cuts_tbl_size_attr = "mincutstblsize"; const char* grid_resolution_attr = "gridresolution"; const char* length_precision_attr = "lengthprecision"; namespace parser { namespace x3 = boost::spirit::x3; 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 = sectioninfo, typename p> auto rule(const char* debug, p p) { return x3::rule<struct _, t> {debug} = x3::skip(x3::space)[p]; }; auto quoted = rule<std::string>("quoted", x3::lexeme[quote >> +(x3::char_ - quote) >> quote]); template <typename t> auto make_member_parser(bool t::* const member) { return x3::bool_[propagate(member)]; } template <typename t> auto make_member_parser(int t::* const member) { return x3::int_[propagate(member)]; } template <typename t> auto make_member_parser(double t::* const member) { return x3::double_[propagate(member)]; } template <typename t> auto make_member_parser(float t::* const member) { return x3::double_[propagate(member)]; } template <typename t> auto make_member_parser(std::string t::* const member) { return quoted[propagate(member)]; } auto property = [](auto label, auto member) { return x3::as_parser(label) >> equals >> make_member_parser(member); }; } using detail::rule; using detail::propagate; using detail::property; using detail::quoted; auto number = property(number_attr, §ioninfo::number); auto visible = property(visible_attr, §ioninfo::visible); auto pitch = property(pitch_attr, §ioninfo::pitch); auto mincutstblsize = property(min_cuts_tbl_size_attr, §ioninfo::mincutstblsize); auto lengthprecision = property(length_precision_attr, §ioninfo::lengthprecision); auto gridresolution = property(grid_resolution_attr, §ioninfo::gridresolution); auto skipline = *(x3::char_ - x3::eol); x3::rule<struct sectioninfoid, sectioninfo> const layer = "layer"; x3::rule<struct mainruleid, std::vector<sectioninfo>> const mainrule = "mainrule"; auto layer_def = layer_section >> quoted[propagate(§ioninfo::name)] >> start_section >> x3::eol >> *( (number | visible | pitch | mincutstblsize | lengthprecision | gridresolution) >> +x3::eol ) >> end_section; auto skipper = x3::blank; auto mainrule_def = *(*x3::eol >> layer >> *x3::eol); boost_spirit_define(layer, mainrule); } std::ostream& operator<<(std::ostream& os, const sectioninfo& s) { os << "name=" << " " << s.name << "\n" << "number=" << " " << s.number << "\n" << "visible=" << " " << s.visible << "\n" << "pitch=" << " " << s.pitch << "\n" << "mincutstblsize=" << " " << s.mincutstblsize << "\n" << "lengthprecision=" << " " << s.lengthprecision << "\n" << "gridresolution=" << " " << s.gridresolution << "\n\n"; return os; } int main() { std::stringstream ss; ss <<"\r\nlayer \"ubmb\" {\r\n" << " layernumber = 170\r\n" << " pitch = 33.6\r\n" << "}\r\n" << "\r\n" << "layer \"rv\" {\r\n" << " gridresolution = 0.34\r\n" << " mincutstblsize = 22.7\r\n" << " layernumber = 85\r\n" << " visible = 2\r\n" << " pitch = 331\r\n" << "}\r\n" << " \r\n" << "layer \"foffo\" {\r\n" << " layernumber = 125\r\n" << " pitch = 0.005\r\n" << " gridresolution = 21.7\r\n" << " lengthprecision = 0.15\r\n" << "}\r\n" << "\r\n"; std::vector<sectioninfo> sections; auto sample = ss.str(); auto f = sample.begin(), l = sample.end(); bool ok = boost::spirit::x3::phrase_parse( f, l, parser::mainrule, parser::skipper, sections ); if (ok && f==l) { std::cout << "\n\n parsed \n\n"; for(auto& s : sections) { std::cout << s; } } else std::cout << "parse failed\n"; }
which parses input:
output is:
name= ubmb number= 170 visible= 0 pitch= 33.6 mincutstblsize= 0 lengthprecision= 0 gridresolution= 0
name= rv number= 85 visible= 2 pitch= 331 mincutstblsize= 22.7 lengthprecision= 0 gridresolution= 0.34
name= foffo number= 125 visible= 0 pitch= 0.005 mincutstblsize= 0 lengthprecision= 0.15 gridresolution= 21.7
the problem arises because need skip lines, i.e. lines properties not of interest (not defined in grammar)
edit: example, there may property dummy = "foo" want skip.
to achieve this, layer rule
auto layer_def = layer_section >> quoted[propagate(§ioninfo::name)] >> start_section >> x3::eol >> *( (number | visible | pitch | mincutstblsize | lengthprecision | gridresolution ) >> +x3::eol ) >> end_section;
becomes
auto layer_def = layer_section >> quoted[propagate(§ioninfo::name)] >> start_section >> x3::eol >> *( (number | visible | pitch | mincutstblsize | lengthprecision | gridresolution | skipline) >> +x3::eol ) >> end_section;
the parser succeeds, output now
name= ubmb number= 125 visible= 2 pitch= 0.005 mincutstblsize= 22.7 lengthprecision= 0.15 gridresolution= 21.7
which wrong (only 1 section, properties taken here , there...)
it evident problem resides in skipline rule
auto skipline = *(x3::char_ - x3::eol);
and can't figure out why. thought obvious rule *(char - eol) >> eol match line, guess isn't..
any clues?
firstly, i'd simplify skipping. skipper doesn't belong in call-site because it's important grammar. encapsulate mainrule, , simplify:
auto mainrule_def = x3::skip(x3::blank) [ -layer % x3::eol ];
the -layer
expression trick accepts empty lines. using parser becomes:
bool ok = boost::spirit::x3::parse(f, l, parser::mainrule, sections);
next: skipline
eats '}'
well, making fall apart: after taken (invalid) properties same layer, , there no end_section
grammar fails match.
simply:
auto skipline = *(x3::char_ - x3::eol - end_section);
pro tip:
when in doubt, debug: live on coliru
// debug auto skipline = x3::rule<struct skipline_> {"skipline"} = *(x3::char_ - x3::eol/* - end_section*/);
full demo
with minor simplifications
#include <iostream> #define boost_spirit_x3_debug #include <boost/fusion/include/adapt_struct.hpp> #include <boost/fusion/include/io.hpp> #include <boost/spirit/home/x3.hpp> struct sectioninfo { std::string name; int number = 0; float pitch = 0.0f; int visible = 0; float mincutstblsize = 0.0f; // technology section attributes float gridresolution = 0.0f; float lengthprecision = 0.0f; }; char const start_section = '{'; char const end_section = '}'; char const quote = '"'; char const equals = '='; char const* layer_section = "layer"; char const* technology_section = "technology"; char const* number_attr = "layernumber"; char const* visible_attr = "visible"; char const* color_attr = "color"; char const* pitch_attr = "pitch"; char const* min_cuts_tbl_size_attr = "mincutstblsize"; char const* grid_resolution_attr = "gridresolution"; char const* length_precision_attr = "lengthprecision"; namespace parser { namespace x3 = boost::spirit::x3; 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 = sectioninfo, typename p> auto rule(const char *debug, p p) { return x3::rule<struct _, t>{ debug } = x3::skip(x3::space)[p]; }; auto quoted = rule<std::string>("quoted", x3::lexeme[quote >> +(x3::char_ - quote) >> quote]); #define mmp_(t, p) template <typename u> auto make_member_parser(t u::*const member) { return (p)[propagate(member)]; } mmp_(bool, x3::bool_); mmp_(int, x3::int_); mmp_(double, x3::double_); mmp_(float, x3::double_); mmp_(std::string, quoted); #undef mmp_ auto property = [](auto label, auto member) { return x3::as_parser(label) >> equals >> make_member_parser(member); }; } using detail::rule; using detail::propagate; using detail::property; using detail::quoted; auto number = property(number_attr, §ioninfo::number); auto visible = property(visible_attr, §ioninfo::visible); auto pitch = property(pitch_attr, §ioninfo::pitch); auto mincutstblsize = property(min_cuts_tbl_size_attr, §ioninfo::mincutstblsize); auto lengthprecision = property(length_precision_attr, §ioninfo::lengthprecision); auto gridresolution = property(grid_resolution_attr, §ioninfo::gridresolution); auto skipline = *(x3::char_ - x3::eol - end_section); x3::rule<struct sectioninfoid, sectioninfo> const layer = "layer"; x3::rule<struct mainruleid, std::vector<sectioninfo> > const mainrule = "mainrule"; auto layer_def = layer_section >> quoted[propagate(§ioninfo::name)] >> start_section >> x3::eol >> *((number | visible | pitch | mincutstblsize | lengthprecision | gridresolution | skipline) >> +x3::eol) >> end_section ; auto mainrule_def = x3::skip(x3::blank) [ -layer % x3::eol ]; boost_spirit_define(layer, mainrule); } std::ostream &operator<<(std::ostream &os, const sectioninfo &s) { return os << "name=" << " " << s.name << "\n" << "number=" << " " << s.number << "\n" << "visible=" << " " << s.visible << "\n" << "pitch=" << " " << s.pitch << "\n" << "mincutstblsize=" << " " << s.mincutstblsize << "\n" << "lengthprecision=" << " " << s.lengthprecision << "\n" << "gridresolution=" << " " << s.gridresolution << "\n\n"; } int main() { std::string const sample = "\r\nlayer \"ubmb\" {\r\n" " layernumber = 170\r\n" " pitch = 33.6\r\n" "}\r\n" "\r\n" "layer \"rv\" {\r\n" " gridresolution = 0.34\r\n" " mincutstblsize = 22.7\r\n" " layernumber = 85\r\n" " visible = 2\r\n" " pitch = 331\r\n" "}\r\n" " \r\n" "layer \"foffo\" {\r\n" " layernumber = 125\r\n" " pitch = 0.005\r\n" " gridresolution = 21.7\r\n" " lengthprecision = 0.15\r\n" "}\r\n" "\r\n"; std::vector<sectioninfo> sections; { auto f = sample.begin(), l = sample.end(); bool ok = boost::spirit::x3::parse(f, l, parser::mainrule, sections); if (ok && f == l) { std::cout << "\n\n parsed \n\n"; (auto &s : sections) { std::cout << s; } } else std::cout << "parse failed\n"; } }
prints
parsed name= ubmb number= 170 visible= 0 pitch= 33.6 mincutstblsize= 0 lengthprecision= 0 gridresolution= 0 name= rv number= 85 visible= 2 pitch= 331 mincutstblsize= 22.7 lengthprecision= 0 gridresolution= 0.34 name= foffo number= 125 visible= 0 pitch= 0.005 mincutstblsize= 0 lengthprecision= 0.15 gridresolution= 21.7
Comments
Post a Comment