I can not manage to have the spirit alternative parser working (or let'say do what I expect).
Here is my MCVE
#include <string>
#include <iostream>
#include <boost/variant.hpp>
#include <boost/spirit/include/qi_parse.hpp>
#include <boost/spirit/include/qi.hpp>
using namespace boost::spirit;
namespace charset = boost::spirit::qi::standard_wide;
using Expr = boost::variant<std::string, int >;
int main(int argc, char ** argv)
{
std::string intToParse = "{int: 45}";
std::string stringToParse = "{string: \"foo\"}";
using It = std::string::const_iterator;
using Sk = qi::space_type;
qi::rule<It, std::string(), Sk> parseString;
qi::rule<It, int(), Sk> parseInt;
qi::rule<It, std::string(),Sk> string_;
qi::rule<It,Expr(),Sk > orParse;
string_ =
qi::lit('"')
> *(charset::char_ - '"')
> '"';
parseString = qi::omit[ qi::string("string")] > qi::lit(':') > string_;
parseInt = qi::omit[ qi::string("int")] > qi::lit(':') > qi::uint_ ;
orParse = qi::omit[qi::lit('{')] > parseString | parseInt > '}';
orParse.name_ = "alternative parser";
parseString.name_ = "string parser";
parseInt.name_= "int parser";
qi::debug(orParse);
qi::debug(parseString);
qi::debug(parseInt);
Expr res2;
qi::phrase_parse(stringToParse.cbegin(), stringToParse.cend(), orParse, qi::space, res2);
std::cout << res2<< std::endl;
Expr res;
qi::phrase_parse(intToParse.cbegin(), intToParse.cend(), orParse, qi::space, res);
std::cout << res << std::endl;
return 0;
}
When the first alternative fails, parsing stop, second rule is not attempted ! What did I get wrong ?
Here is the output showing my issue , for the stringToParse , first alternative fails but then I expect int parser to be exercised which is not the case !
<alternative parser>
<try>{string: "foo"}</try>
<string parser>
<try>string: "foo"}</try>
<success>}</success>
<attributes>[[f, o, o]]</attributes>
</string parser>
<success>}</success>
<attributes>[[f, o, o]]</attributes>
</alternative parser>
foo
<alternative parser>
<try>{int: 45}</try>
<string parser>
<try>int: 45}</try>
<fail/>
</string parser>
<fail/>
</alternative parser>
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::spirit::qi::expectation_failure<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >'
what(): boost::spirit::qi::expectation_failure
Aborted (core dumped)
operator >
is higher in C++ Operator Precedence table than operator |
hence parenthesis are needed:
orParse = qi::omit[qi::lit('{')] > (parseString | parseInt) > '}';
// here ^ and here ^
Result:
<alternative parser>
<try>{string: "foo"}</try>
<string parser>
<try>string: "foo"}</try>
<success>}</success>
<attributes>[[f, o, o]]</attributes>
</string parser>
<success></success>
<attributes>[[f, o, o]]</attributes>
</alternative parser>
foo
<alternative parser>
<try>{int: 45}</try>
<string parser>
<try>int: 45}</try>
<fail/>
</string parser>
<int parser>
<try>int: 45}</try>
<success>}</success>
<attributes>[45]</attributes>
</int parser>
<success></success>
<attributes>[45]</attributes>
</alternative parser>
45