c++ - inconsistent behavior of boost spirit grammar -
this question has answer here:
i have little grammar want use work project. minimum executable example is:
#pragma gcc diagnostic push #pragma gcc diagnostic ignored "-wunused-local-typedefs" #pragma gcc diagnostic ignored "-wmaybe-uninitialized" #pragma gcc diagnostic ignored "-wunused-variable" #include <boost/spirit/include/karma.hpp> #include <boost/spirit/include/qi_grammar.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/support_istream_iterator.hpp> #pragma gcc diagnostic pop // pops #include <iostream> int main() { typedef unsigned long long ull; std::string curline = "1;2;;3,4;5"; std::cout << "parsing: " << curline << "\n"; namespace qi = boost::spirit::qi; auto ids = -qi::ulong_long % ','; // '-' allows empty vecs. auto match_type_res = ids % ';' ; std::vector<std::vector<ull> > r; qi::parse(curline.begin(), curline.end(), match_type_res, r); std::cout << "got: "; (auto v: r){ (auto : v) std::cout << << ","; std::cout << ";"; } std::cout <<"\n"; } on personal machine produces correct output: parsing: 1;2;;3,4;5 got: 1,;2,;;3,4,;5,;
but @ work produces: parsing: 1;2;;3,4;5 got: 1,;2,;;3,
in other words, fails parse vector of long integers there's more 1 element in it.
now, have identified work system using boost 1.56, while private computer using 1.57. cause?
knowning have real spirit experts here on stack overflow, hoping might know issue coming from, or can @ least narrow down number of things need check.
if boost version problem, can convince company upgrade, workaround welcome in case.
you're invoking undefined behaviour in code.
specifically use auto store parser expression. expression template contains references temporaries become dangling @ end of containing full-expression¹.
ub implies can happen. both compilers right! , best part is, see varying behaviour depending on compiler flags used.
fix either using:
qi::copy(orboost::proto::deep_copybefore v.1.55 iirc)- use
boost_spirit_autoinstead ofboost_auto(mostly helpful iff support c++03) use
qi::rule<>,qi::grammar<>(the non-terminals) type-erase , expressions. has performance impact too, gives more features like- recursive rules
- locals , inherited attributes
- declared skippers (handy because rules can implicitly
lexeme[](see here) - better code organization.
note spirit x3 promises drop there restrictions on use auto. it's whole lot more lightweight due use of c++14 features. keep in mind it's not stable yet.
showing gcc -o2 shows undefined results; live on coliru
the fixed version:
//#pragma gcc diagnostic push //#pragma gcc diagnostic ignored "-wunused-local-typedefs" //#pragma gcc diagnostic ignored "-wmaybe-uninitialized" //#pragma gcc diagnostic ignored "-wunused-variable" #include <boost/spirit/include/karma.hpp> #include <boost/spirit/include/qi.hpp> //#pragma gcc diagnostic pop // pops #include <iostream> int main() { typedef unsigned long long ull; std::string const curline = "1;2;;3,4;5"; std::cout << "parsing: '" << curline << "'\n"; namespace qi = boost::spirit::qi; #if 0 // undefined behaviour: auto ids = -qi::ulong_long % ','; // '-' allows empty vecs. auto grammar = ids % ';'; #else // correct: auto ids = qi::copy(-qi::ulong_long % ','); // '-' allows empty vecs. auto grammar = qi::copy(ids % ';'); #endif std::vector<std::vector<ull> > r; qi::parse(curline.begin(), curline.end(), grammar, r); std::cout << "got: "; (auto v: r){ (auto : v) std::cout << << ","; std::cout << ";"; } std::cout <<"\n"; } printing (also gcc -o2!):
parsing: '1;2;;3,4;5' got: 1,;2,;;3,4,;5,; ¹ (that's "at next semicolon" here; in standardese)
Comments
Post a Comment