I have a problem with boost spirit expression.The original code is more complicated and I made a small snapshot of it. This code works as expected in debug mode and doesn't in release, parse returns false, but should return true ( I'm testing it on Visual Studio 2019)
int main() {
namespace qi = boost::spirit::qi;
auto X19 = qi::lit(" ") | qi::lit(" 0.000000000000D 00");
auto i4 = qi::uint_;
string str = "1234 1234";
auto f = str.cbegin();
auto l = str.cend();
bool ret = qi::parse(f, l, ( i4 >> X19 >> i4 ));
}
The next snapshot works well in both modes:
int main() {
namespace qi = boost::spirit::qi;
auto i4 = qi::uint_;
string str = "1234 1234";
auto f = str.cbegin();
auto l = str.cend();
bool ret = qi::parse(f, l, ( i4 >> (qi::lit(" ") | qi::lit(" 0.000000000000D 00")) >> i4 ));
cout << ret << endl;
return ret;
}
What I do wrong, dividing long expression this way ? Thank you
CodePudding user response:
You ran headlong into the the dangling temporaries trap with Spirit's Proto expressions. The short rule is:
Don't use
auto
with Spirit expressions
The workarounds involve BOOST_SPIRIT_AUTO
or qi::copy
(which used to be available only as boost::proto::deep_copy
before recent boost releases).
Fixed
#include <boost/spirit/include/qi.hpp>
int main() {
namespace qi = boost::spirit::qi;
auto i4 = qi::copy(qi::uint_);
auto X19 = qi::copy( //
qi::lit(" ") //
| qi::lit(" 0.000000000000D 00")//
);
std::string str = "1234 1234";
auto f = str.cbegin(), l = str.cend();
bool ret = qi::parse(f, l, (i4 >> X19 >> i4));
std::cout << std::boolalpha << ret << "\n";
}
Prints
true
BONUS
Note that Spirit X3 no longer has this restriction/problem: Live On Coliru
#include <boost/spirit/home/x3.hpp> int main() { namespace x3 = boost::spirit::x3; auto i4 = x3::uint_; auto X19 = // x3::lit(" ") // | x3::lit(" 0.000000000000D 00") // ; std::string str = "1234 1234"; auto f = str.cbegin(), l = str.cend(); bool ret = parse(f, l, (i4 >> X19 >> i4)); std::cout << std::boolalpha << ret << "\n"; }
You might actually want
qi::uint_parser<int, 10, 4, 4> i4; // or x3::uint_parser<int, 10, 4, 4> i4;
It looks a lot as if you're parsing COBOL like (fixed-width) records, in which case I think there are much better ways to organize your grammar to make it reliable.