blob: 6794c15a62ae7b0c8f53e08c5fdbb0eacca436c6 [file] [log] [blame]
[/==============================================================================
Copyright (C) 2001-2010 Joel de Guzman
Copyright (C) 2001-2010 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.
The full cpp file for this example can be found here:
[@../../example/qi/mini_xml3.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<Action>(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<fail>
(
xml
, std::cout
<< val("Error! Expecting ")
<< _4 // what failed?
<< val(" here: \"")
<< construct<std::string>(_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 to which the handler is attached. 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 describing 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 `"</"`, you definitely must see a valid
end-tag label next. It should be the one you got from the start-tag. After that,
you definitely must have a `'>'` next. Otherwise, there is no point in
proceeding 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_xml3.cpp]. You can find some
examples in: [@../../example/qi/mini_xml_samples] for testing purposes.
"4.toyxml" has an error in it:
<foo><bar></foo></bar>
Running the example with this gives you:
Error! Expecting "bar" here: "foo></bar>"
Error! Expecting end_tag here: "<bar></foo></bar>"
-------------------------
Parsing failed
-------------------------
[endsect]