Search code examples
c++boost-spiritboost-spirit-qi

Broken std::cout output when using combined immediate = string|float|int rule using qi::double_ an qi::uint_


i try to get a immediate rule for string, int and float so i can parse the following tests

 //strings
 "\"hello\"",
 "   \"  hello \"  ",
 "  \"  hello \"\"stranger\"\" \"  ",
 //ints
 "1",
 "23",
 "456",
 //floats
 "3.3",
 "34.35"

try online: http://coliru.stacked-crooked.com/a/26fbd691876d9a8f

using

qi::rule<std::string::const_iterator, std::string()> 
  double_quoted_string = '"' >> *("\"\"" >> qi::attr('"') | ~qi::char_('"')) >> '"';

qi::rule<std::string::const_iterator, std::string()> 
  number = (+qi::ascii::digit >> *(qi::char_('.') >> +qi::ascii::digit));

qi::rule<std::string::const_iterator, std::string()>
  immediate = double_quoted_string | number;

gives me the correct result - but i need to use the double_ parse because i want to support eponential notation, NaN etc.

but using

qi::rule<std::string::const_iterator, std::string()>
  immediate = double_quoted_string | qi::uint_ | qi::double_;

prints for the integer values

"1" OK: ''
----
"23" OK: ''
----
"456" OK: '�'

and the double numbers failing completely to parse

tested under Coliru, Win7x64 VS2017 latest, LLVM clang-cl

sometimes Colliru gives too much warnings and the compilation is halted

any idea what happens here?

do warnings in spirit often mean - stop here, something severely broken?

UPDATE: it also happen if i only use double_, before i tested it and the behavior changed with/without the uint_ parser try: https://wandbox.org/permlink/UqgItWkfC2I8tkNF


Solution

  • Use qi::raw on integer and double floating point parsers so that the numbers are converted lexically: qi::raw[qi::uint_] and qi::raw[qi::double_].

    But also the order of parsing is important. If uint_ parser is before double_ like here:

    immediate = double_quoted_string | qi::raw[qi::uint_] | qi::raw[qi::double_];
    BOOST_SPIRIT_DEBUG_NODES((immediate)); // for debug output
    

    then the uint_ parser will partially consume the double floating point number and then the whole parsing will fail:

    <immediate>
      <try>34.35</try>
      <success>.35</success> //<----- this is what is left after uint_ parsed
      <attributes>[[3, 4]]</attributes> // <---- what uint_ parser successfully parsed
    </immediate>
    "34.35" Failed
    Remaining unparsed: "34.35"
    

    After swapping order of uint_ with double_:

    immediate = double_quoted_string | qi::raw[qi::double_] | qi::raw[qi::uint_];

    The result:

    "\"hello\"" OK: 'hello'
    ----
    "   \"  hello \"  " OK: '  hello '
    ----
    "  \"  hello \"\"stranger\"\" \"  " OK: '  hello "stranger" '
    ----
    "1" OK: '1'
    ----
    "64" OK: '64'
    ----
    "456" OK: '456'
    ----
    "3.3" OK: '3.3'
    ----
    "34.35" OK: '34.35'
    ----