1[/============================================================================== 2 Copyright (C) 2001-2011 Joel de Guzman 3 Copyright (C) 2001-2011 Hartmut Kaiser 4 5 Distributed under the Boost Software License, Version 1.0. (See accompanying 6 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7===============================================================================/] 8 9[section Mini XML - Error Handling] 10 11A parser will not be complete without error handling. Spirit2 provides some 12facilities to make it easy to adapt a grammar for error handling. We'll wrap up 13the Qi tutorial with another version of the mini xml parser, this time, with 14error handling. 15 16The full cpp file for this example can be found here: 17[@../../example/qi/mini_xml3.cpp] 18 19[import ../../example/qi/mini_xml3.cpp] 20 21Here's the grammar: 22 23[tutorial_xml3_grammar] 24 25What's new? 26 27[heading Readable Names] 28 29First, when we call the base class, we give the grammar a name: 30 31 : mini_xml_grammar::base_type(xml, "xml") 32 33Then, we name all our rules: 34 35 xml.name("xml"); 36 node.name("node"); 37 text.name("text"); 38 start_tag.name("start_tag"); 39 end_tag.name("end_tag"); 40 41[heading On Success] 42 43`on_success` declares a handler that is applied when a rule is 44succesfully matched. 45 46 on_success(rule, handler) 47 48This specifies that the handler will be called when a rule is 49matched successfully. The handler has the following signature: 50 51 void handler( 52 fusion::vector< 53 Iterator& first, 54 Iterator const& last, 55 Iterator const& i> args, 56 Context& context) 57 58`first` points to the position in the input sequence before the rule 59is matched. `last` points to the last position in the input sequence. 60`i` points to the position in the input sequence following the last 61character that was consumed by the rule. 62 63A success handler can be used to annotate each matched rule in the 64grammar with additional information about the portion of the input 65that matched the rule. In a compiler application, this can be a 66combination of file, line number and column number from the input 67stream for reporting diagnostics or other messages. 68 69[heading On Error] 70 71`on_error` declares our error handler: 72 73 on_error<Action>(rule, handler) 74 75This will specify what we will do when we get an error. We will print out an 76error message using phoenix: 77 78 on_error<fail> 79 ( 80 xml 81 , std::cout 82 << val("Error! Expecting ") 83 << _4 // what failed? 84 << val(" here: \"") 85 << construct<std::string>(_3, _2) // iterators to error-pos, end 86 << val("\"") 87 << std::endl 88 ); 89 90we choose to `fail` in our example for the `Action`: Quit and fail. Return a 91no_match (false). It can be one of: 92 93[table 94 [[`Action`] [Description]] 95 [[fail] [Quit and fail. Return a no_match.]] 96 [[retry] [Attempt error recovery, possibly moving the iterator position.]] 97 [[accept] [Force success, moving the iterator position appropriately.]] 98 [[rethrow] [Rethrows the error.]] 99] 100 101 102`rule` is the rule to which the handler is attached. In our case, we are attaching to the 103`xml` rule. 104 105`handler` is the actual error handling function. It expects 4 arguments: 106 107[table 108 [[Arg] [Description]] 109 [[first] [The position of the iterator when the rule with the handler was entered.]] 110 [[last] [The end of input.]] 111 [[error-pos] [The actual position of the iterator where the error occurred.]] 112 [[what] [What failed: a string describing the failure.]] 113] 114 115[heading Expectation Points] 116 117You might not have noticed it, but some of our expressions changed from using 118the `>>` to `>`. Look, for example: 119 120 end_tag = 121 "</" 122 > lit(_r1) 123 > '>' 124 ; 125 126What is it? It's the /expectation/ operator. You will have some "deterministic 127points" in the grammar. Those are the places where backtracking *cannot* occur. 128For our example above, when you get a `"</"`, you definitely must see a valid 129end-tag label next. It should be the one you got from the start-tag. After that, 130you definitely must have a `'>'` next. Otherwise, there is no point in 131proceeding and trying other branches, regardless where they are. The 132input is definitely erroneous. When this happens, an expectation_failure 133exception is thrown. Somewhere outward, the error handler will catch the 134exception. 135 136Try building the parser: [@../../example/qi/mini_xml3.cpp]. You can find some 137examples in: [@../../example/qi/mini_xml_samples] for testing purposes. 138"4.toyxml" has an error in it: 139 140 <foo><bar></foo></bar> 141 142Running the example with this gives you: 143 144 Error! Expecting "bar" here: "foo></bar>" 145 Error! Expecting end_tag here: "<bar></foo></bar>" 146 ------------------------- 147 Parsing failed 148 ------------------------- 149 150[endsect] 151