0

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
Max
  • 638
  • 1
  • 4
  • 19
  • 1
    Notice that in the example/tutorial linked they use the `*_class` as the rule ID. [If you use the class that inherits from `error_handler` as your rule ID it works](https://wandbox.org/permlink/yNTisqiiACel43Tn). – llonesmiz Jun 08 '19 at 18:17
  • Now this makes sense. – Max Jun 10 '19 at 15:25

0 Answers0