Home > Blockchain >  Using boost spirit expression
Using boost spirit expression

Time:10-05

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

Your program exhibits enter image description here


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

Live On Coliru

#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

  1. 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";
    }
    
  2. You might actually want

    qi::uint_parser<int, 10, 4, 4> i4;
    // or
    x3::uint_parser<int, 10, 4, 4> i4;
    
  3. 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.

  • Related