c++boostboost-spirit-qi

boost::qi rule with double, howto parse a signed int8?


Boost::qi: I can't parse signed int8_t into double:

template <typename Iterator>
struct test : qi::grammar<Iterator, double()> {
  test() : test::base_type(start) {

    number =
      parse_number    [ _val = _1 ]
    
    parse_number =
      qi::int_parser<int8_t>() [ _val = boost::phoenix::static_cast_<double>(_1) ];

    start = qi::skip(qi::space)[number];
  }

  private:
    qi::rule<Iterator, double()> start;
    qi::rule<Iterator, double()> number;
    qi::rule<Iterator, double()> parse_number;
}

I need to parse "255" as int8_t into number which is double. But, as int8_t, 255 shall be parsed as -1.

Later I wish to expand this to support typename prefixes, so that parse_number can parse them:

255     : 255
(u8)255 : 255
(s8)255 : -1

Current error messages:

../src/StringTest.cpp:129:106: error: expected ‘{’ before ‘;’ token
  129 |             parse_prefix = (qi::int_parser<int8_t>()) [ _val = boost::phoenix::static_cast_<double>(_1) ];
      |                                                                                                          ^

../src/StringTest.cpp:129:28: error: invalid cast to function type ‘boost::spirit::qi::int_parser<signed char>()’
  129 |             parse_prefix = (qi::int_parser<int8_t>()) [ _val = boost::phoenix::static_cast_<double>(_1) ];
      |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

What is the (correct) way of doing this?


Solution

  • It works for me: Live On Coliru

    But you can simplify all the way down to

    template <typename It> struct test : qi::grammar<It, double()> {
        test() : test::base_type(start) { //
            start = qi::int_parser<int8_t>{};
        }
    
      private:
        qi::rule<It, double()> start;
    };
    

    Here's a generalized test-bed: Live On Coliru

    BONUS: type prefixes

    To get your type prefixes, I'd consider something like this:

    qi::rule<std::string::const_iterator, long double()> parser //
        = "(s8)"   >> qi::int_parser<int8_t>{}       
        | "(u8)"   >> qi::uint_parser<uint8_t>{}     
        | "(s16)"  >> qi::int_parser<int16_t>{}      
        | "(u16)"  >> qi::uint_parser<uint16_t>{}    
        | "(s32)"  >> qi::int_parser<int32_t>{}      
        | "(u32)"  >> qi::uint_parser<uint32_t>{}    
        | "(s64)"  >> qi::int_parser<int64_t>{}      
        | "(u64)"  >> qi::uint_parser<uint64_t>{}    
        | "(s128)" >> qi::int_parser<__int128_t>{}   
        | "(u128)" >> qi::uint_parser<__uint128_t>{} 
        | "(c)"    >> qi::int_parser<char>{}         
        | qi::real_parser<long double>{};
    

    Note that I switched to long double because otherwise large 64-bit integers aren't being represented exactly anymore (double has only 53 bits of significand precision).

    Another, pretty exhaustive, test-bed:

    Live On Coliru

    #include <boost/spirit/include/qi.hpp>
    #include <iomanip>
    #include <iostream>
    using namespace std::string_literals;
    
    namespace qi = boost::spirit::qi;
    
    void testWithPrefix() {
        qi::rule<std::string::const_iterator, long double()> parser //
            = "(s8)"   >> qi::int_parser<int8_t>{}       //
            | "(u8)"   >> qi::uint_parser<uint8_t>{}     //
            | "(s16)"  >> qi::int_parser<int16_t>{}      //
            | "(u16)"  >> qi::uint_parser<uint16_t>{}    //
            | "(s32)"  >> qi::int_parser<int32_t>{}      //
            | "(u32)"  >> qi::uint_parser<uint32_t>{}    //
            | "(s64)"  >> qi::int_parser<int64_t>{}      //
            | "(u64)"  >> qi::uint_parser<uint64_t>{}    //
            | "(s128)" >> qi::int_parser<__int128_t>{}   //
            | "(u128)" >> qi::uint_parser<__uint128_t>{} //
            | "(c)"    >> qi::int_parser<char>{}         //
            | qi::real_parser<long double>{};
    
        for (auto prefix : {"(s8)", "(u8)", "(c)", "(i16)", "(u16)", "(s32)", "(u32)", //
                            "(s64)", "(u64)", "(s128)", "(u128)", ""})
            for (auto sign : {""/*, "+"*/, "-"})
                for (std::string literal :
                     {
                         "0",
                         "1",                                       // 2^0
                         "127",                                     // 2^7-1
                         "128",                                     // 2^7
                         "255",                                     // 2^8-1
                         "256",                                     // 2^8
                         "32767",                                   // 2^15-1
                         "32768",                                   // 2^15
                         "65535",                                   // 2^16-1
                         "65536",                                   // 2^16
                         "2147483647",                              // 2^31-1
                         "2147483648",                              // 2^31
                         "4294967295",                              // 2^32-1
                         "4294967296",                              // 2^32
                         "9223372036854775807",                     // 2^63-1
                         "9223372036854775808",                     // 2^63
                         "18446744073709551615",                    // 2^64-1
                         "18446744073709551616",                    // 2^64
                         "170141183460469231731687303715884105727", // 2^127-1
                         "170141183460469231731687303715884105728", // 2^127
                         "123e+45",
                     }) //
                {
                    std::string const input = prefix + (sign + literal);
                    long double       actual, expected = std::strtold((sign + literal).c_str(), nullptr);
    
                    if (qi::parse(                      //
                            input.begin(), input.end(), //
                            parser >> qi::eoi, actual)) //
                    {
                        std::cout << "Parsed: " << std::setw(43) << quoted(input) << " -> " << actual << "\n";
                        if (expected != actual)
                            std::cout << "  (mismatch: " << expected << "\n";
                    } else {
                        std::cout << " -- (Failing to parse " << quoted(input) << ")\n";
                        break;
                    }
                }
    }
    
    int main() {
        std::cout << std::fixed << std::setprecision(0);
        testWithPrefix();
    }
    

    Printing

    
    Parsed:                                     "(s8)0" -> 0
    Parsed:                                     "(s8)1" -> 1
    Parsed:                                   "(s8)127" -> 127
     -- (Failing to parse "(s8)128")
    Parsed:                                    "(s8)-0" -> 0
    Parsed:                                    "(s8)-1" -> -1
    Parsed:                                  "(s8)-127" -> -127
    Parsed:                                  "(s8)-128" -> -128
     -- (Failing to parse "(s8)-255")
    Parsed:                                     "(u8)0" -> 0
    Parsed:                                     "(u8)1" -> 1
    Parsed:                                   "(u8)127" -> 127
    Parsed:                                   "(u8)128" -> 128
    Parsed:                                   "(u8)255" -> 255
     -- (Failing to parse "(u8)256")
     -- (Failing to parse "(u8)-0")
    Parsed:                                      "(c)0" -> 0
    Parsed:                                      "(c)1" -> 1
    Parsed:                                    "(c)127" -> 127
     -- (Failing to parse "(c)128")
    Parsed:                                     "(c)-0" -> 0
    Parsed:                                     "(c)-1" -> -1
    Parsed:                                   "(c)-127" -> -127
    Parsed:                                   "(c)-128" -> -128
     -- (Failing to parse "(c)-255")
     -- (Failing to parse "(i16)0")
     -- (Failing to parse "(i16)-0")
    Parsed:                                    "(u16)0" -> 0
    Parsed:                                    "(u16)1" -> 1
    Parsed:                                  "(u16)127" -> 127
    Parsed:                                  "(u16)128" -> 128
    Parsed:                                  "(u16)255" -> 255
    Parsed:                                  "(u16)256" -> 256
    Parsed:                                "(u16)32767" -> 32767
    Parsed:                                "(u16)32768" -> 32768
    Parsed:                                "(u16)65535" -> 65535
     -- (Failing to parse "(u16)65536")
     -- (Failing to parse "(u16)-0")
    Parsed:                                    "(s32)0" -> 0
    Parsed:                                    "(s32)1" -> 1
    Parsed:                                  "(s32)127" -> 127
    Parsed:                                  "(s32)128" -> 128
    Parsed:                                  "(s32)255" -> 255
    Parsed:                                  "(s32)256" -> 256
    Parsed:                                "(s32)32767" -> 32767
    Parsed:                                "(s32)32768" -> 32768
    Parsed:                                "(s32)65535" -> 65535
    Parsed:                                "(s32)65536" -> 65536
    Parsed:                           "(s32)2147483647" -> 2147483647
     -- (Failing to parse "(s32)2147483648")
    Parsed:                                   "(s32)-0" -> 0
    Parsed:                                   "(s32)-1" -> -1
    Parsed:                                 "(s32)-127" -> -127
    Parsed:                                 "(s32)-128" -> -128
    Parsed:                                 "(s32)-255" -> -255
    Parsed:                                 "(s32)-256" -> -256
    Parsed:                               "(s32)-32767" -> -32767
    Parsed:                               "(s32)-32768" -> -32768
    Parsed:                               "(s32)-65535" -> -65535
    Parsed:                               "(s32)-65536" -> -65536
    Parsed:                          "(s32)-2147483647" -> -2147483647
    Parsed:                          "(s32)-2147483648" -> -2147483648
     -- (Failing to parse "(s32)-4294967295")
    Parsed:                                    "(u32)0" -> 0
    Parsed:                                    "(u32)1" -> 1
    Parsed:                                  "(u32)127" -> 127
    Parsed:                                  "(u32)128" -> 128
    Parsed:                                  "(u32)255" -> 255
    Parsed:                                  "(u32)256" -> 256
    Parsed:                                "(u32)32767" -> 32767
    Parsed:                                "(u32)32768" -> 32768
    Parsed:                                "(u32)65535" -> 65535
    Parsed:                                "(u32)65536" -> 65536
    Parsed:                           "(u32)2147483647" -> 2147483647
    Parsed:                           "(u32)2147483648" -> 2147483648
    Parsed:                           "(u32)4294967295" -> 4294967295
     -- (Failing to parse "(u32)4294967296")
     -- (Failing to parse "(u32)-0")
    Parsed:                                    "(s64)0" -> 0
    Parsed:                                    "(s64)1" -> 1
    Parsed:                                  "(s64)127" -> 127
    Parsed:                                  "(s64)128" -> 128
    Parsed:                                  "(s64)255" -> 255
    Parsed:                                  "(s64)256" -> 256
    Parsed:                                "(s64)32767" -> 32767
    Parsed:                                "(s64)32768" -> 32768
    Parsed:                                "(s64)65535" -> 65535
    Parsed:                                "(s64)65536" -> 65536
    Parsed:                           "(s64)2147483647" -> 2147483647
    Parsed:                           "(s64)2147483648" -> 2147483648
    Parsed:                           "(s64)4294967295" -> 4294967295
    Parsed:                           "(s64)4294967296" -> 4294967296
    Parsed:                  "(s64)9223372036854775807" -> 9223372036854775807
     -- (Failing to parse "(s64)9223372036854775808")
    Parsed:                                   "(s64)-0" -> 0
    Parsed:                                   "(s64)-1" -> -1
    Parsed:                                 "(s64)-127" -> -127
    Parsed:                                 "(s64)-128" -> -128
    Parsed:                                 "(s64)-255" -> -255
    Parsed:                                 "(s64)-256" -> -256
    Parsed:                               "(s64)-32767" -> -32767
    Parsed:                               "(s64)-32768" -> -32768
    Parsed:                               "(s64)-65535" -> -65535
    Parsed:                               "(s64)-65536" -> -65536
    Parsed:                          "(s64)-2147483647" -> -2147483647
    Parsed:                          "(s64)-2147483648" -> -2147483648
    Parsed:                          "(s64)-4294967295" -> -4294967295
    Parsed:                          "(s64)-4294967296" -> -4294967296
    Parsed:                 "(s64)-9223372036854775807" -> -9223372036854775807
    Parsed:                 "(s64)-9223372036854775808" -> -9223372036854775808
     -- (Failing to parse "(s64)-18446744073709551615")
    Parsed:                                    "(u64)0" -> 0
    Parsed:                                    "(u64)1" -> 1
    Parsed:                                  "(u64)127" -> 127
    Parsed:                                  "(u64)128" -> 128
    Parsed:                                  "(u64)255" -> 255
    Parsed:                                  "(u64)256" -> 256
    Parsed:                                "(u64)32767" -> 32767
    Parsed:                                "(u64)32768" -> 32768
    Parsed:                                "(u64)65535" -> 65535
    Parsed:                                "(u64)65536" -> 65536
    Parsed:                           "(u64)2147483647" -> 2147483647
    Parsed:                           "(u64)2147483648" -> 2147483648
    Parsed:                           "(u64)4294967295" -> 4294967295
    Parsed:                           "(u64)4294967296" -> 4294967296
    Parsed:                  "(u64)9223372036854775807" -> 9223372036854775807
    Parsed:                  "(u64)9223372036854775808" -> 9223372036854775808
    Parsed:                 "(u64)18446744073709551615" -> 18446744073709551615
     -- (Failing to parse "(u64)18446744073709551616")
     -- (Failing to parse "(u64)-0")
    Parsed:                                   "(s128)0" -> 0
    Parsed:                                   "(s128)1" -> 1
    Parsed:                                 "(s128)127" -> 127
    Parsed:                                 "(s128)128" -> 128
    Parsed:                                 "(s128)255" -> 255
    Parsed:                                 "(s128)256" -> 256
    Parsed:                               "(s128)32767" -> 32767
    Parsed:                               "(s128)32768" -> 32768
    Parsed:                               "(s128)65535" -> 65535
    Parsed:                               "(s128)65536" -> 65536
    Parsed:                          "(s128)2147483647" -> 2147483647
    Parsed:                          "(s128)2147483648" -> 2147483648
    Parsed:                          "(s128)4294967295" -> 4294967295
    Parsed:                          "(s128)4294967296" -> 4294967296
    Parsed:                 "(s128)9223372036854775807" -> 9223372036854775807
    Parsed:                 "(s128)9223372036854775808" -> 9223372036854775808
    Parsed:                "(s128)18446744073709551615" -> 18446744073709551615
    Parsed:                "(s128)18446744073709551616" -> 18446744073709551616
    Parsed: "(s128)170141183460469231731687303715884105727" -> 170141183460469231731687303715884105728
     -- (Failing to parse "(s128)170141183460469231731687303715884105728")
    Parsed:                                  "(s128)-0" -> 0
    Parsed:                                  "(s128)-1" -> -1
    Parsed:                                "(s128)-127" -> -127
    Parsed:                                "(s128)-128" -> -128
    Parsed:                                "(s128)-255" -> -255
    Parsed:                                "(s128)-256" -> -256
    Parsed:                              "(s128)-32767" -> -32767
    Parsed:                              "(s128)-32768" -> -32768
    Parsed:                              "(s128)-65535" -> -65535
    Parsed:                              "(s128)-65536" -> -65536
    Parsed:                         "(s128)-2147483647" -> -2147483647
    Parsed:                         "(s128)-2147483648" -> -2147483648
    Parsed:                         "(s128)-4294967295" -> -4294967295
    Parsed:                         "(s128)-4294967296" -> -4294967296
    Parsed:                "(s128)-9223372036854775807" -> -9223372036854775807
    Parsed:                "(s128)-9223372036854775808" -> -9223372036854775808
    Parsed:               "(s128)-18446744073709551615" -> -18446744073709551615
    Parsed:               "(s128)-18446744073709551616" -> -18446744073709551616
    Parsed: "(s128)-170141183460469231731687303715884105727" -> -170141183460469231731687303715884105728
    Parsed: "(s128)-170141183460469231731687303715884105728" -> -170141183460469231731687303715884105728
     -- (Failing to parse "(s128)--123e+45")
    Parsed:                                   "(u128)0" -> 0
    Parsed:                                   "(u128)1" -> 1
    Parsed:                                 "(u128)127" -> 127
    Parsed:                                 "(u128)128" -> 128
    Parsed:                                 "(u128)255" -> 255
    Parsed:                                 "(u128)256" -> 256
    Parsed:                               "(u128)32767" -> 32767
    Parsed:                               "(u128)32768" -> 32768
    Parsed:                               "(u128)65535" -> 65535
    Parsed:                               "(u128)65536" -> 65536
    Parsed:                          "(u128)2147483647" -> 2147483647
    Parsed:                          "(u128)2147483648" -> 2147483648
    Parsed:                          "(u128)4294967295" -> 4294967295
    Parsed:                          "(u128)4294967296" -> 4294967296
    Parsed:                 "(u128)9223372036854775807" -> 9223372036854775807
    Parsed:                 "(u128)9223372036854775808" -> 9223372036854775808
    Parsed:                "(u128)18446744073709551615" -> 18446744073709551615
    Parsed:                "(u128)18446744073709551616" -> 18446744073709551616
    Parsed: "(u128)170141183460469231731687303715884105727" -> 170141183460469231731687303715884105728
    Parsed: "(u128)170141183460469231731687303715884105728" -> 170141183460469231731687303715884105728
     -- (Failing to parse "(u128)-123e+45")
     -- (Failing to parse "(u128)-0")
    Parsed:                                         "0" -> 0
    Parsed:                                         "1" -> 1
    Parsed:                                       "127" -> 127
    Parsed:                                       "128" -> 128
    Parsed:                                       "255" -> 255
    Parsed:                                       "256" -> 256
    Parsed:                                     "32767" -> 32767
    Parsed:                                     "32768" -> 32768
    Parsed:                                     "65535" -> 65535
    Parsed:                                     "65536" -> 65536
    Parsed:                                "2147483647" -> 2147483647
    Parsed:                                "2147483648" -> 2147483648
    Parsed:                                "4294967295" -> 4294967295
    Parsed:                                "4294967296" -> 4294967296
    Parsed:                       "9223372036854775807" -> 9223372036854775807
    Parsed:                       "9223372036854775808" -> 9223372036854775808
    Parsed:                      "18446744073709551615" -> 18446744073709551615
    Parsed:                      "18446744073709551616" -> 18446744073709551616
    Parsed:   "170141183460469231731687303715884105727" -> 170141183460469231731687303715884105728
    Parsed:   "170141183460469231731687303715884105728" -> 170141183460469231731687303715884105728
    Parsed:                                  "-123e+45" -> -123000000000000000005919784386968639946966958080
      (mismatch: -122999999999999999996016264072685597747773964288
    Parsed:                                        "-0" -> -0
    Parsed:                                        "-1" -> -1
    Parsed:                                      "-127" -> -127
    Parsed:                                      "-128" -> -128
    Parsed:                                      "-255" -> -255
    Parsed:                                      "-256" -> -256
    Parsed:                                    "-32767" -> -32767
    Parsed:                                    "-32768" -> -32768
    Parsed:                                    "-65535" -> -65535
    Parsed:                                    "-65536" -> -65536
    Parsed:                               "-2147483647" -> -2147483647
    Parsed:                               "-2147483648" -> -2147483648
    Parsed:                               "-4294967295" -> -4294967295
    Parsed:                               "-4294967296" -> -4294967296
    Parsed:                      "-9223372036854775807" -> -9223372036854775807
    Parsed:                      "-9223372036854775808" -> -9223372036854775808
    Parsed:                     "-18446744073709551615" -> -18446744073709551615
    Parsed:                     "-18446744073709551616" -> -18446744073709551616
    Parsed:  "-170141183460469231731687303715884105727" -> -170141183460469231731687303715884105728
    Parsed:  "-170141183460469231731687303715884105728" -> -170141183460469231731687303715884105728
     -- (Failing to parse "--123e+45")