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, &sectioninfo::number);      auto visible = property(visible_attr, &sectioninfo::visible);      auto pitch = property(pitch_attr, &sectioninfo::pitch);      auto mincutstblsize = property(min_cuts_tbl_size_attr, &sectioninfo::mincutstblsize);      auto lengthprecision = property(length_precision_attr, &sectioninfo::lengthprecision);      auto gridresolution = property(grid_resolution_attr, &sectioninfo::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(&sectioninfo::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(&sectioninfo::name)] >> start_section >> x3::eol              >> *( (number | visible | pitch | mincutstblsize | lengthprecision | gridresolution ) >> +x3::eol )              >> end_section; 

becomes

auto layer_def = layer_section >> quoted[propagate(&sectioninfo::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

live on coliru

#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,            &sectioninfo::number);     auto visible         = property(visible_attr,           &sectioninfo::visible);     auto pitch           = property(pitch_attr,             &sectioninfo::pitch);     auto mincutstblsize  = property(min_cuts_tbl_size_attr, &sectioninfo::mincutstblsize);     auto lengthprecision = property(length_precision_attr,  &sectioninfo::lengthprecision);     auto gridresolution  = property(grid_resolution_attr,   &sectioninfo::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(&sectioninfo::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

Popular posts from this blog

Is there a better way to structure post methods in Class Based Views -

performance - Why is XCHG reg, reg a 3 micro-op instruction on modern Intel architectures? -

jquery - Responsive Navbar with Sub Navbar -