[/============================================================================== Copyright (C) 2001-2008 Joel de Guzman Copyright (C) 2001-2009 Hartmut Kaiser Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ===============================================================================/] [section Mini XML - Error Handling] A parser will not be complete without error handling. Spirit2 provides some facilities to make it easy to adapt a grammar for error handling. We'll wrap up the Qi tutorial with another version of the mini xml parser, this time, with error handling. [@../../example/qi/mini_xml1.cpp] and here: [@../../example/qi/mini_xml2.cpp] [import ../../example/qi/mini_xml3.cpp] Here's the grammar: [tutorial_xml3_grammar] What's new? [heading Readable Names] First, when we call the base class, we give the grammar a name: : mini_xml_grammar::base_type(xml, "xml") Then, we name all our rules: xml.name("xml"); node.name("node"); text.name("text"); start_tag.name("start_tag"); end_tag.name("end_tag"); [heading On Error] `on_error` declares our error handler: on_error(rule, handler) This will specify what we will do when we get an error. We will print out an error message using phoenix: on_error ( xml , std::cout << val("Error! Expecting ") << _4 // what failed? << val(" here: \"") << construct(_3, _2) // iterators to error-pos, end << val("\"") << std::endl ); we choose to `fail` in our example for the `Action`: Quit and fail. Return a no_match (false). It can be one of: [table [[`Action`] [Description]] [[fail] [Quit and fail. Return a no_match.]] [[retry] [Attempt error recovery, possibly moving the iterator position.]] [[accept] [Force success, moving the iterator position appropriately.]] [[rethrow] [Rethrows the error.]] ] `rule` is the rule we attach the handler to. In our case, we are attaching to the `xml` rule. `handler` is the actual error handling function. It expects 4 arguments: [table [[Arg] [Description]] [[first] [The position of the iterator when the rule with the handler was entered.]] [[last] [The end of input.]] [[error-pos] [The actual position of the iterator where the error occurred.]] [[what] [What failed: a string decribing the failure.]] ] [heading Expectation Points] You might not have noticed it, but some of our expressions changed from using the `>>` to `>`. Look, for example: end_tag = " lit(_r1) > '>' ; What is it? It's the /expectation/ operator. You will have some "deterministic points" in the grammar. Those are the places where backtracking *cannot* occur. For our example above, when you get a `"'` next. Otherwise, there is no point in proceeding forward and trying other branches, regardless where they are. The input is definitely erroneous. When this happens, an expectation_failure exception is thrown. Somewhere outward, the error handler will catch the exception. Try building the parser: [@../../example/qi/mini_xml2.cpp]. You can find some examples in: [@../../example/qi/mini_xml_samples] for testing purposes. "4.toyxml" has an error in it: Running the example with this gives you: Error! Expecting "bar" here: "foo>" Error! Expecting end_tag here: "" ------------------------- Parsing failed ------------------------- [endsect]