As I try to rewrite my Spirit X3 grammar, I put some rules (e.g. char_ > ':' > int_ > '#') into a parser class like this one shown here:
struct item_parser : x3::parser<item_parser> {
using attribute_type = ast::item_type;
template <typename IteratorT, typename ContextT>
bool parse(IteratorT& first, IteratorT const& last, ContextT const& ctx, x3::unused_type,
attribute_type& attribute) const
{
skip_over(first, last, ctx);
auto const grammar_def = x3::lexeme[ x3::char_ > ':' > x3::int_ > '#' ];
auto const grammar = grammar_def.on_error(
[this](auto&f, auto l, auto const& e, auto const& ctx){
return recover_error(f, l, e, ctx); }
);
auto const parse_ok = x3::parse(first, last, grammar, attribute);
return parse_ok;
}
auto recover_error(auto&f, auto l, auto const& e, auto const&) const {
std::cout << "item_parser::recover_error: " << e.which() << '\n';
std::cout << "+++ error_handler in: " << excerpt(f, l) << "\n";
if (auto semicolon = find(f, l, ';'); semicolon == l) {
return x3::error_handler_result::fail;
} else { // move iter behind ';'
f = semicolon + 1;
std::cout << "+++ error_handler out: " << excerpt(f, l) << "\n";
return x3::error_handler_result::accept;
}
}
};
(https://godbolt.org/z/MhjYWbE6x) - which works with good input:
std::string const input = R"(
X := a:42#;
X := b:66#;
X := c:4711#;
)";
as expected. If I change one line in the input to e.g. X := b66#; (note the missing colon : inside the literal) it recovers from parser error as expected, but "failed finally" at the end (https://godbolt.org/z/3zabbsWsP).
Input
std::string const input = R"(
X := a:42#;
X := b66#;
X := c:4711#;
)";
with output:
item_parser::recover_error: ':'
+++ error_handler in: 'b66#;
X := c:4711#;
'
+++ error_handler out: '
X := c:4711#;
'
failure
For the return of parse() (aka parse_ok) I expected true since it's never returned x3::error_handler_result::fail. Nevertheless, I use an error counter in real.
If I further change the outer rule item_assign to x3::eps > "X" > ":=" > item > ';' the program is terminated (uncaught expectation_failure) which I haven't expected since it's guarded with an error_handler (tag), see https://godbolt.org/z/dGcYfbG3r
terminate called after throwing an instance of 'boost::wrapexcept<boost::spirit::x3::expectation_failure<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >'
what(): boost::spirit::x3::expectation_failure
Maybe I don't see my fault ... or I trigger a bug? Note, that I'm using rule's on_error() which mentioned at https://github.com/boostorg/spirit/issues/657 . Thanks in advance for help.