I have some troubles getting the error handler to work with boost spirit x3. I was looking at the documentation (https://www.boost.org/doc/libs/1_70_0/libs/spirit/doc/x3/html/spirit_x3/tutorials/error_handling.html) but I don't understand the part:
"Notice too that we subclass the employee_class from our error_handler. By doing so, we tell X3 that we want to call our error_handler whenever an exception is thrown somewhere inside the employee rule and whatever else it calls (i.e. the person and quoted_string rules)."
What has the type <ruleID>_class todo with the registration?
I started with the the functional composition described in the answer Spirit X3: parser with internal state. But I cannot register the error handler. Here is my example:
#include <iostream>
#include <iomanip>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/position_tagged.hpp>
#include <boost/spirit/home/x3/support/utility/error_reporting.hpp>
#include <boost/spirit/home/x3/support/utility/annotate_on_success.hpp>
namespace Parser {
namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
struct error_handler {
template<typename Iterator, typename Exception, typename Context>
x3::error_handler_result on_error(
Iterator &first, Iterator const &last, Exception const &x, Context const &context) {
auto &error_handler = x3::get<x3::error_handler_tag>(context).get();
std::string message = "Error! Expecting: " + x.which() + " here:";
error_handler(x.where(), message);
return x3::error_handler_result::fail;
}
};
struct CSVLine;
static inline auto line_parser() {
auto delim = ',' | &(x3::eoi | x3::eol);
return x3::rule<CSVLine>{"line"} = (as_parser(x3::int_) > delim > as_parser(x3::int_) > x3::eps);
}
struct CSVLine_class : error_handler, x3::annotate_on_success {};
}
void parse(std::string const &input) {
using iterator_type = std::string::const_iterator;
iterator_type iter = input.begin();
iterator_type const end = input.end();
using boost::spirit::x3::with;
using boost::spirit::x3::error_handler_tag;
using error_handler_type = boost::spirit::x3::error_handler<iterator_type>;
// Our error handler
error_handler_type error_handler(iter, end, std::cout);
// Our parser
const auto p = Parser::line_parser();
auto const parser =
// we pass our error handler to the parser so we can access
// it later in our on_error and on_sucess handlers
with<error_handler_tag>(std::ref(error_handler))
[
p
];
if (parse(iter, end, parser))
std::cout << "Parsed" << std::endl;
else
std::cout << "Failed" << std::endl;
if (iter!=end)
std::cout << "Remaining: " << std::quoted(std::string(iter,end)) << std::endl;
}
int main() {
parse("1,x2.6");
return 0;
}
Since the error handler is not recognized it yields:
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<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