mirror of
https://github.com/boostorg/spirit.git
synced 2026-01-19 04:42:11 +00:00
error handling docs
This commit is contained in:
@@ -199,6 +199,8 @@ pages and pages of reference documentation.
|
||||
|
||||
[[__x3_raw__`[a]`] [__boost_iterator_range__`<I>`] [Presents the transduction of `a` as an iterator range]]
|
||||
|
||||
[[__x3_expectd__`[a]`] [`A`] [Throw an exception if parsing `a` fails]]
|
||||
|
||||
[[[x3_repeat `repeat[a]`]] [`vector<A>`] [Repeat `a` zero or more times]]
|
||||
[[[x3_repeat `repeat(N)[a]`]] [`vector<A>`] [Repeat `a` `N` times]]
|
||||
[[[x3_repeat `repeat(N, M)[a]`]] [`vector<A>`] [Repeat `a` `N` to `M` times]]
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
===============================================================================/]
|
||||
|
||||
[article Spirit
|
||||
[article Spirit X3
|
||||
[quickbook 1.5]
|
||||
[version 3.0.1]
|
||||
[authors [de Guzman, Joel], [Kaiser, Hartmut]]
|
||||
[copyright 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 Joel de Guzman, Hartmut Kaiser]
|
||||
[copyright 2001-2018 Joel de Guzman, Hartmut Kaiser]
|
||||
[/ purpose Parser Library]
|
||||
[license
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
@@ -21,18 +21,14 @@
|
||||
|
||||
[/ May 12, 2015 ]
|
||||
|
||||
[/==============================================================================
|
||||
[/=============================================================================
|
||||
Some links and defines
|
||||
===============================================================================/]
|
||||
=============================================================================/]
|
||||
|
||||
[def __version__ V3.0.1]
|
||||
|
||||
[/ external]
|
||||
|
||||
[def __boost__ [@http://www.boost.org/ Boost]]
|
||||
[def __spirit__ [@http://boost-spirit.com Spirit]]
|
||||
[def __spirit_list__ [@https://lists.sourceforge.net/lists/listinfo/spirit-general Spirit Mailing List]]
|
||||
[def __spirit_general__ [@news://news.gmane.org/gmane.comp.spirit.general Spirit General NNTP news portal]]
|
||||
[def __gmane__ [@http://www.gmane.org Gmane]]
|
||||
[def __mlist_archive__ [@http://news.gmane.org/gmane.comp.parsers.spirit.general]]
|
||||
[def __boost_tools__ [@http://www.boost.org/tools/index.html Boost Tools]]
|
||||
@@ -53,7 +49,7 @@
|
||||
[def __caution__ [$./images/caution.png]]
|
||||
[def __danger__ [$./images/alert.png]]
|
||||
|
||||
[def __x3__ /Spirit.X3/]
|
||||
[def __x3__ /spirit_x3/]
|
||||
|
||||
[def __sd_start_stop__ [$./images/start_stop.png]]
|
||||
[def __sd_terminals__ [$./images/terminal.png]]
|
||||
@@ -68,115 +64,138 @@
|
||||
[def __sd_not_predicate__ [$./images/not_predicate.png]]
|
||||
[def __pascal_string__ [$./images/pascal_string.png]]
|
||||
|
||||
[def __rd__ Recursive Descent] [/$$$ TODO: link me $$$]
|
||||
[def __syntax_diagrams__ [link spirit.abstracts.syntax_diagrams Syntax Diagram]]
|
||||
[def __peg__ [link spirit.abstracts.parsing_expression_grammar Parsing Expression Grammar]]
|
||||
[def __ast__ Abstract Syntax Tree] [/$$$ TODO: link me $$$]
|
||||
|
||||
[def __sec_x3_reference__ [/ link spirit.x3.reference] X3 Reference]
|
||||
[def __sec_x3_primitive__ [/ link spirit.x3.quick_reference.x3_parsers] X3 Parsers]
|
||||
[def __sec_x3_compound__ [/ link spirit.x3.quick_reference.compound_attribute_rules] Parser Compound Attribute Rules]
|
||||
[def __sec_x3_reference__ [/ link spirit_x3.reference] X3 Reference]
|
||||
[def __sec_x3_primitive__ [/ link spirit_x3.quick_reference.x3_parsers] X3 Parsers]
|
||||
[def __sec_x3_compound__ [/ link spirit_x3.quick_reference.compound_attribute_rules] Parser Compound Attribute Rules]
|
||||
|
||||
[/ support]
|
||||
[def __info__ `info`] [/ TODO Link Me]
|
||||
[def __x3_error_handler__ Error Handler] [/ TODO Link Me]
|
||||
[def __unused_type__ `unused_type`] [/$$$ TODO: link me $$$]
|
||||
[def __unused__ `unused`] [/$$$ TODO: link me $$$]
|
||||
[def __char_class_types__ Character Class Types] [/$$$ TODO: link me $$$]
|
||||
|
||||
[/ quick-ref]
|
||||
[def __x3_quickref__ [link spirit.x3.quick_reference X3 Quick Reference]]
|
||||
[def __x3_comp_attr_notation__ [link spirit.x3.quick_reference.compound_attribute_rules.notation Compound Attribute Notation]]
|
||||
[def __x3_quickref__ [link spirit_x3.quick_reference X3 Quick Reference]]
|
||||
[def __x3_comp_attr_notation__ [link spirit_x3.quick_reference.compound_attribute_rules.notation Compound Attribute Notation]]
|
||||
|
||||
[/ concepts]
|
||||
[def __parser_concept__ [/ link spirit.x3.reference.parser_concepts.parser] `Parser`]
|
||||
[def __primitive_parser_concept__ [/ link spirit.x3.reference.parser_concepts.primitiveparser] `PrimitiveParser`]
|
||||
[def __unary_parser_concept__ [/ link spirit.x3.reference.parser_concepts.unaryparser] `UnaryParser`]
|
||||
[def __binary_parser_concept__ [/ link spirit.x3.reference.parser_concepts.binaryparser] `BinaryParser`]
|
||||
[def __nary_parser_concept__ [/ link spirit.x3.reference.parser_concepts.naryparser] `NaryParser`]
|
||||
[def __x3_nonterminal__ [/ link spirit.x3.reference.parser_concepts.nonterminal] `Nonterminal`]
|
||||
[def __x3_nonterminal_attribute__ [/ link spirit.x3.reference.parser_concepts.nonterminal.attributes] `Attribute`]
|
||||
[def __parser_concept__ [/ link spirit_x3.reference.parser_concepts.parser] `Parser`]
|
||||
[def __primitive_parser_concept__ [/ link spirit_x3.reference.parser_concepts.primitiveparser] `PrimitiveParser`]
|
||||
[def __unary_parser_concept__ [/ link spirit_x3.reference.parser_concepts.unaryparser] `UnaryParser`]
|
||||
[def __binary_parser_concept__ [/ link spirit_x3.reference.parser_concepts.binaryparser] `BinaryParser`]
|
||||
[def __nary_parser_concept__ [/ link spirit_x3.reference.parser_concepts.naryparser] `NaryParser`]
|
||||
[def __x3_nonterminal__ [/ link spirit_x3.reference.parser_concepts.nonterminal] `Nonterminal`]
|
||||
[def __x3_nonterminal_attribute__ [/ link spirit_x3.reference.parser_concepts.nonterminal.attributes] `Attribute`]
|
||||
|
||||
[/ basics]
|
||||
[def __x3_lazy_argument__ [/ link spirit.x3.reference.basics.lazy_argument] Lazy Argument]
|
||||
[def __x3_lazy_arguments__ [/ link spirit.x3.reference.basics.lazy_argument] Lazy Arguments]
|
||||
[def __char_encoding_namespace__ [/ link spirit.x3.reference.basics.character_encoding_namespace] Character Encoding Namespace]
|
||||
[def __x3_basics_examples__ [/ link spirit.x3.reference.basics.examples] Basics Examples]
|
||||
[def __x3_lazy_argument__ [/ link spirit_x3.reference.basics.lazy_argument] Lazy Argument]
|
||||
[def __x3_lazy_arguments__ [/ link spirit_x3.reference.basics.lazy_argument] Lazy Arguments]
|
||||
[def __char_encoding_namespace__ [/ link spirit_x3.reference.basics.character_encoding_namespace] Character Encoding Namespace]
|
||||
[def __x3_basics_examples__ [/ link spirit_x3.reference.basics.examples] Basics Examples]
|
||||
|
||||
[/ string]
|
||||
[template x3_lit_string[str] [[/ link spirit.x3.reference.string.string] str]]
|
||||
[def __string__ [/ link spirit.x3.reference.basics.string] String]
|
||||
[def __x3_symbols__ [/ link spirit.x3.reference.string.symbols] `symbols<T>`]
|
||||
[template x3_lit_string[str] [[/ link spirit_x3.reference.string.string] str]]
|
||||
[def __string__ [/ link spirit_x3.reference.basics.string] String]
|
||||
[def __x3_symbols__ [/ link spirit_x3.reference.string.symbols] `symbols<T>`]
|
||||
|
||||
[/ action]
|
||||
[def __x3_semantic_actions__ Semantic Actions] [/ TODO Link Me]
|
||||
|
||||
[/ char]
|
||||
[template x3_char[str] [/ link spirit.x3.reference.char.char] [str]]
|
||||
[template x3_char_class[str] [/ link spirit.x3.reference.char.char_class] [str]]
|
||||
[template x3_lit_char[char] [/ link spirit.x3.reference.char.char] [char]]
|
||||
[template x3_char[str] [/ link spirit_x3.reference.char.char] [str]]
|
||||
[template x3_char_class[str] [/ link spirit_x3.reference.char.char_class] [str]]
|
||||
[template x3_lit_char[char] [/ link spirit_x3.reference.char.char] [char]]
|
||||
|
||||
[/ numerics]
|
||||
[template x3_signed_int[str] [/ link spirit.x3.reference.numeric.int] [str]]
|
||||
[template x3_unsigned_int[str] [/ link spirit.x3.reference.numeric.uint] [str]]
|
||||
[template x3_real_number[str] [/ link spirit.x3.reference.numeric.real] [str]]
|
||||
[template x3_boolean[str] [/ link spirit.x3.reference.numeric.boolean] [str]]
|
||||
[template x3_signed_int[str] [/ link spirit_x3.reference.numeric.int] [str]]
|
||||
[template x3_unsigned_int[str] [/ link spirit_x3.reference.numeric.uint] [str]]
|
||||
[template x3_real_number[str] [/ link spirit_x3.reference.numeric.real] [str]]
|
||||
[template x3_boolean[str] [/ link spirit_x3.reference.numeric.boolean] [str]]
|
||||
|
||||
[/ binary]
|
||||
[template x3_native_binary[str] [/ link spirit.x3.reference.binary.binary_native] [str]]
|
||||
[template x3_little_binary[str] [/ link spirit.x3.reference.binary.binary_little] [str]]
|
||||
[template x3_big_binary[str] [/ link spirit.x3.reference.binary.binary_big] [str]]
|
||||
[template x3_native_binary[str] [/ link spirit_x3.reference.binary.binary_native] [str]]
|
||||
[template x3_little_binary[str] [/ link spirit_x3.reference.binary.binary_little] [str]]
|
||||
[template x3_big_binary[str] [/ link spirit_x3.reference.binary.binary_big] [str]]
|
||||
|
||||
[/ auxiliary]
|
||||
[def __x3_attr__ [/ link spirit.x3.reference.auxiliary.attr] `attr(attrib)`]
|
||||
[def __x3_eol__ [/ link spirit.x3.reference.auxiliary.eol] `eol`]
|
||||
[def __x3_eoi__ [/ link spirit.x3.reference.auxiliary.eoi] `eoi`]
|
||||
[def __x3_eps__ [/ link spirit.x3.reference.auxiliary.eps] `eps`]
|
||||
[def __x3_lazy__ [/ link spirit.x3.reference.auxiliary.lazy] `lazy`]
|
||||
[def __x3_attr__ [/ link spirit_x3.reference.auxiliary.attr] `attr(attrib)`]
|
||||
[def __x3_eol__ [/ link spirit_x3.reference.auxiliary.eol] `eol`]
|
||||
[def __x3_eoi__ [/ link spirit_x3.reference.auxiliary.eoi] `eoi`]
|
||||
[def __x3_eps__ [/ link spirit_x3.reference.auxiliary.eps] `eps`]
|
||||
[def __x3_lazy__ [/ link spirit_x3.reference.auxiliary.lazy] `lazy`]
|
||||
|
||||
[/ directives]
|
||||
[def __x3_lexeme__ [/ link spirit.x3.reference.directive.lexeme] `lexeme`]
|
||||
[def __x3_no_case__ [/ link spirit.x3.reference.directive.no_case] `no_case`]
|
||||
[def __x3_omit__ [/ link spirit.x3.reference.directive.omit] `omit`]
|
||||
[def __x3_matches__ [/ link spirit.x3.reference.directive.matches] `matches`]
|
||||
[def __x3_raw__ [/ link spirit.x3.reference.directive.raw] `raw`]
|
||||
[def __x3_repeat__ [/ link spirit.x3.reference.directive.repeat] `repeat`]
|
||||
[template x3_repeat[str] [[/ link spirit.x3.reference.directive.repeat] str]]
|
||||
[def __x3_skip__ [/ link spirit.x3.reference.directive.skip] `skip`]
|
||||
[template x3_no_skip[str] [[/ link spirit.x3.reference.directive.no_skip] str]]
|
||||
[def __x3_hold__ [/ link spirit.x3.reference.directive.hold] `hold`]
|
||||
[def __x3_lexeme__ [/ link spirit_x3.reference.directive.lexeme] `lexeme`]
|
||||
[def __x3_no_case__ [/ link spirit_x3.reference.directive.no_case] `no_case`]
|
||||
[def __x3_omit__ [/ link spirit_x3.reference.directive.omit] `omit`]
|
||||
[def __x3_matches__ [/ link spirit_x3.reference.directive.matches] `matches`]
|
||||
[def __x3_raw__ [/ link spirit_x3.reference.directive.raw] `raw`]
|
||||
[def __x3_expectd__ [/ link spirit_x3.reference.directive.expect] `expect`]
|
||||
[def __x3_repeat__ [/ link spirit_x3.reference.directive.repeat] `repeat`]
|
||||
[template x3_repeat[str] [[/ link spirit_x3.reference.directive.repeat] str]]
|
||||
[def __x3_skip__ [/ link spirit_x3.reference.directive.skip] `skip`]
|
||||
[template x3_no_skip[str] [[/ link spirit_x3.reference.directive.no_skip] str]]
|
||||
[def __x3_hold__ [/ link spirit_x3.reference.directive.hold] `hold`]
|
||||
|
||||
[/ operator]
|
||||
[def __x3_alternative__ [/ link spirit.x3.reference.operator.alternative] `a | b`]
|
||||
[def __x3_and_predicate__ [/ link spirit.x3.reference.operator.and_predicate] `&a`]
|
||||
[def __x3_difference__ [/ link spirit.x3.reference.operator.difference] `a - b`]
|
||||
[def __x3_expect__ [/ link spirit.x3.reference.operator.expect] `a > b`]
|
||||
[def __x3_expectation_failure__ [/ link spirit.x3.reference.operator.expect.expectation_failure] `expectation_failure`]
|
||||
[def __x3_kleene__ [/ link spirit.x3.reference.operator.kleene] `*a`]
|
||||
[def __x3_list__ [/ link spirit.x3.reference.operator.list] `a % b`]
|
||||
[def __x3_not_predicate__ [/ link spirit.x3.reference.operator.not_predicate] `!a`]
|
||||
[def __x3_optional__ [/ link spirit.x3.reference.operator.optional] `-a`]
|
||||
[def __x3_plus__ [/ link spirit.x3.reference.operator.plus] `+a`]
|
||||
[def __x3_sequence__ [/ link spirit.x3.reference.operator.sequence] `a >> b`]
|
||||
[def __x3_alternative__ [/ link spirit_x3.reference.operator.alternative] `a | b`]
|
||||
[def __x3_and_predicate__ [/ link spirit_x3.reference.operator.and_predicate] `&a`]
|
||||
[def __x3_difference__ [/ link spirit_x3.reference.operator.difference] `a - b`]
|
||||
[def __x3_expect__ [/ link spirit_x3.reference.operator.expect] `a > b`]
|
||||
[def __x3_expectation_failure__ [/ link spirit_x3.reference.operator.expect.expectation_failure] `expectation_failure`]
|
||||
[def __x3_kleene__ [/ link spirit_x3.reference.operator.kleene] `*a`]
|
||||
[def __x3_list__ [/ link spirit_x3.reference.operator.list] `a % b`]
|
||||
[def __x3_not_predicate__ [/ link spirit_x3.reference.operator.not_predicate] `!a`]
|
||||
[def __x3_optional__ [/ link spirit_x3.reference.operator.optional] `-a`]
|
||||
[def __x3_plus__ [/ link spirit_x3.reference.operator.plus] `+a`]
|
||||
[def __x3_sequence__ [/ link spirit_x3.reference.operator.sequence] `a >> b`]
|
||||
|
||||
[def __x3_stream__ [/ link spirit.x3.reference.stream.stream] `stream`]
|
||||
[def __x3_stream__ [/ link spirit_x3.reference.stream.stream] `stream`]
|
||||
|
||||
[/ nonterminal]
|
||||
[def __x3_rule__ [/ link spirit.x3.reference.nonterminal.rule] rule]
|
||||
[def __x3_rules__ [/ link spirit.x3.reference.nonterminal.rule] rules]
|
||||
[def __x3_grammar__ [/ link spirit.x3.reference.nonterminal.grammar] grammar]
|
||||
[def __x3_grammars__ [/ link spirit.x3.reference.nonterminal.grammar] grammars]
|
||||
[def __x3_rule__ [/ link spirit_x3.reference.nonterminal.rule] rule]
|
||||
[def __x3_rules__ [/ link spirit_x3.reference.nonterminal.rule] rules]
|
||||
[def __x3_grammar__ [/ link spirit_x3.reference.nonterminal.grammar] grammar]
|
||||
[def __x3_grammars__ [/ link spirit_x3.reference.nonterminal.grammar] grammars]
|
||||
|
||||
[/ stream]
|
||||
[template x3_match[str] [/ link spirit.x3.reference.parse_api.stream_api] str]
|
||||
[template x3_auto[str] [/ link spirit.x3.reference.auto] str]
|
||||
[def __create_parser__ [/ link spirit.x3.reference.parse_api.create_parser] `create_parser`]
|
||||
[template x3_match[str] [/ link spirit_x3.reference.parse_api.stream_api] str]
|
||||
[template x3_auto[str] [/ link spirit_x3.reference.auto] str]
|
||||
[def __create_parser__ [/ link spirit_x3.reference.parse_api.create_parser] `create_parser`]
|
||||
|
||||
[def __parse_api__ [/ link spirit.x3.reference.parse_api] The Parse API]
|
||||
[def __parse_api__ [/ link spirit_x3.reference.parse_api] The Parse API]
|
||||
|
||||
[/==============================================================================
|
||||
[/=============================================================================
|
||||
Better Links (March 7, 2018)
|
||||
=============================================================================/]
|
||||
|
||||
[/ external --------------------]
|
||||
|
||||
[def __boost__ [@http://www.boost.org/ Boost]]
|
||||
[def __spirit__ [@http://boost-spirit.com Spirit]]
|
||||
[def __spirit_list__ [@https://lists.sourceforge.net/lists/listinfo/spirit-general Spirit Mailing List]]
|
||||
[def __spirit_general__ [@news://news.gmane.org/gmane.comp.spirit.general Spirit General NNTP news portal]]
|
||||
[def __clang__ [@https://clang.llvm.org/ Clang]]
|
||||
[def __rd__ [@https://en.wikipedia.org/wiki/Recursive_descent_parser Recursive Descent]]
|
||||
|
||||
[/ Sections --------------------]
|
||||
|
||||
[/ Tutorials -------------------]
|
||||
|
||||
[template tutorial_employee[str] [link spirit_x3.tutorials.employee [str]]]
|
||||
[template tutorial_annotation[str] [link spirit_x3.tutorials.annotation [str]]]
|
||||
|
||||
[/ support ---------------------]
|
||||
|
||||
[def __x3_error_handler__ [/ link fix.me] error_handler]
|
||||
|
||||
[/=============================================================================
|
||||
Documentation Start
|
||||
===============================================================================/]
|
||||
=============================================================================/]
|
||||
|
||||
This is the documentation of the newest version of __spirit__ (currently,
|
||||
__version__).
|
||||
@@ -199,6 +218,7 @@ __version__).
|
||||
[include tutorial/employee.qbk]
|
||||
[include tutorial/annotation.qbk]
|
||||
[include tutorial/rexpr.qbk]
|
||||
[include tutorial/error_handling.qbk]
|
||||
[endsect]
|
||||
|
||||
[section Quick Reference]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
[/==============================================================================
|
||||
Copyright (C) 2001-2015 Joel de Guzman
|
||||
Copyright (C) 2001-2011 Hartmut Kaiser
|
||||
Copyright (C) 2001-2018 Joel de Guzman
|
||||
|
||||
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)
|
||||
@@ -9,34 +8,39 @@
|
||||
for sponsoring this work and donating it to the community.
|
||||
===============================================================================/]
|
||||
|
||||
[section Annotations - Decorating the ASTs]
|
||||
[section:annotation Annotations - Decorating the ASTs]
|
||||
|
||||
Stop and think about it... We're actually generating ASTs (abstract
|
||||
syntax trees) in our previoius examples. We parsed a single structure and
|
||||
generated an in-memory representation of it in the form of a struct: the
|
||||
struct employee. If we changed the implementation to parse one or more
|
||||
employees, the result would be a std::vector<employee>. We can go on and
|
||||
add more hierarchy: teams, departments, corporations. Then we'll have an
|
||||
AST representation of it all.
|
||||
As a prerequisite in understanding this tutorial, please review the previous
|
||||
[tutorial_employee employee example]. This example builds on top of that
|
||||
example.
|
||||
|
||||
This example shows how to annotate the AST with the iterator positions
|
||||
for access to the source code when post processing using a client supplied
|
||||
`on_success` handler. The example will show how to get the position in
|
||||
input source stream that corresponds to a given element in the AST.
|
||||
Stop and think about it... We're actually generating ASTs (abstract syntax
|
||||
trees) in our previoius examples. We parsed a single structure and generated
|
||||
an in-memory representation of it in the form of a struct: the struct
|
||||
employee. If we changed the implementation to parse one or more employees,
|
||||
the result would be a std::vector<employee>. We can go on and add more
|
||||
hierarchy: teams, departments, corporations, etc. We can have an AST
|
||||
representation of it all.
|
||||
|
||||
In addition, This example also shows how to "inject" client data, using
|
||||
the "with" directive, that the `on_success` handler can access as it is
|
||||
called within the parse traversal through the parser's context.
|
||||
This example shows how to annotate the AST with the iterator positions for
|
||||
access to the source code when post processing using a client supplied
|
||||
`on_success` handler. The example will show how to get the position in input
|
||||
source stream that corresponds to a given element in the AST.
|
||||
|
||||
The full cpp file for this example can be found here: [@../../../example/x3/annotation.cpp]
|
||||
In addition, This example also shows how to "inject" client data, using the
|
||||
"with" directive, that the `on_success` handler can access as it is called
|
||||
within the parse traversal through the parser's context.
|
||||
|
||||
The full cpp file for this example can be found here:
|
||||
[@../../../example/x3/annotation.cpp]
|
||||
|
||||
[heading The AST]
|
||||
|
||||
First, we'll update our previous employee struct, this time separating
|
||||
the person into its own struct. So now, we have two structs, the `person`
|
||||
and the `employee`. Take note too that we now inherit `person` and `employee`
|
||||
from `x3::position_tagged` which provides positional information that we
|
||||
can use to tell the AST's position in the input stream anytime.
|
||||
First, we'll update our previous employee struct, this time separating the
|
||||
person into its own struct. So now, we have two structs, the `person` and the
|
||||
`employee`. Take note too that we now inherit `person` and `employee` from
|
||||
`x3::position_tagged` which provides positional information that we can use
|
||||
to tell the AST's position in the input stream anytime.
|
||||
|
||||
namespace client { namespace ast
|
||||
{
|
||||
@@ -61,8 +65,8 @@ can use to tell the AST's position in the input stream anytime.
|
||||
};
|
||||
}}
|
||||
|
||||
Like before, we need to tell __fusion__ about our structs to make them first-class
|
||||
fusion citizens that the grammar can utilize:
|
||||
Like before, we need to tell __fusion__ about our structs to make them
|
||||
first-class fusion citizens that the grammar can utilize:
|
||||
|
||||
BOOST_FUSION_ADAPT_STRUCT(client::ast::person,
|
||||
first_name, last_name
|
||||
@@ -74,40 +78,41 @@ fusion citizens that the grammar can utilize:
|
||||
|
||||
[heading x3::position_cache]
|
||||
|
||||
Before we proceed, let me introduce a helper class called the `position_cache`.
|
||||
It is a simple class that collects iterator ranges that point to where each
|
||||
element in the AST are located in the input stream. Given an AST, you can
|
||||
ask the position_cache about its position. For example:
|
||||
Before we proceed, let me introduce a helper class called the
|
||||
`position_cache`. It is a simple class that collects iterator ranges that
|
||||
point to where each element in the AST are located in the input stream. Given
|
||||
an AST, you can query the position_cache about AST's position. For example:
|
||||
|
||||
auto pos = positions.position_of(my_ast);
|
||||
|
||||
Where `my_ast` is the AST, `positions` and is the `position_cache`, `position_of`
|
||||
returns an iterator range that points to the start and end (`pos.begin()`
|
||||
and `pos.end()`) positions where the AST was parsed from. `positions.begin()`
|
||||
and `positions.end()` points to the start and end of the entire input stream.
|
||||
Where `my_ast` is the AST, `positions` and is the `position_cache`,
|
||||
`position_of` returns an iterator range that points to the start and end
|
||||
(`pos.begin()` and `pos.end()`) positions where the AST was parsed from.
|
||||
`positions.begin()` and `positions.end()` points to the start and end of the
|
||||
entire input stream.
|
||||
|
||||
[heading on_success]
|
||||
|
||||
The `on_success` gives you everything you want from semantic actions without
|
||||
the visual clutter. Declarative code can and should be free from imperative
|
||||
code. `on_success` as a concept and mechanism is an important departure
|
||||
from how things are done in Spirit's previous version: Qi.
|
||||
code. `on_success` as a concept and mechanism is an important departure from
|
||||
how things are done in Spirit's previous version: Qi.
|
||||
|
||||
As demonstrated in the previous employee example, the preferred way to
|
||||
extract data from an input source is by having the parser collect the data
|
||||
for us into C++ structs as it traverses the input stream. Ideally, Spirit
|
||||
X3 grammars are fully attributed and declared in such a way that you do
|
||||
not have to add any imperative code and there should be no need for semantic
|
||||
actions at all. The parser simply works as declared and you get your data
|
||||
back as a result.
|
||||
As demonstrated in the previous [tutorial_employee employee example], the
|
||||
preferred way to extract data from an input source is by having the parser
|
||||
collect the data for us into C++ structs as it traverses the input stream.
|
||||
Ideally, Spirit X3 grammars are fully attributed and declared in such a way
|
||||
that you do not have to add any imperative code and there should be no need
|
||||
for semantic actions at all. The parser simply works as declared and you get
|
||||
your data back as a result.
|
||||
|
||||
However, there are certain cases where there's no way to avoid introducing
|
||||
imperative code. Yet, if we want to keep our code clean and free from semantic
|
||||
actions that messes up our clean declarative grammars, `on_success` handlers
|
||||
are alternative means to provide hooks to client code that is executed by the
|
||||
parser upon successful parse without polluting the grammar. Like semantic
|
||||
actions, `on_success` handlers also have access to the AST, the iterators,
|
||||
and context. But, unlike semantic actions, `on_success` handlers are cleanly
|
||||
imperative code. But semantic actions messes up our clean declarative
|
||||
grammars. If we care to keep our code clean, `on_success` handlers are
|
||||
alternative callback hooks to client code that are executed by the parser
|
||||
after a successful parse without polluting the grammar. Like semantic
|
||||
actions, `on_success` handlers have access to the AST, the iterators, and
|
||||
context. But, unlike semantic actions, `on_success` handlers are cleanly
|
||||
separated from the actual grammar.
|
||||
|
||||
[heading Annotation Handler]
|
||||
@@ -133,18 +138,19 @@ our `on_success` handler:
|
||||
actual `position_cache`, client data that we will inject at very start, when
|
||||
we call parse. More on that later.
|
||||
|
||||
Our `on_success` handler gets a reference to the actual `position_cache`
|
||||
and calls its `annotate` member function, passing in the AST and the iterators.
|
||||
`position_cache.annotate(ast, first, last)` annotates the AST with information
|
||||
required by `x3::position_tagged`.
|
||||
Our `on_success` handler gets a reference to the actual `position_cache` and
|
||||
calls its `annotate` member function, passing in the AST and the iterators.
|
||||
`position_cache.annotate(ast, first, last)` annotates the AST with
|
||||
information required by `x3::position_tagged`.
|
||||
|
||||
[heading The Parser]
|
||||
|
||||
Now we'll write a parser for our employee. Like before, inputs will
|
||||
be of the form:
|
||||
Now we'll write a parser for our employee. To simplify, inputs will be of the
|
||||
form:
|
||||
|
||||
employee{ age, "forename", "surname", salary }
|
||||
{ age, "forename", "surname", salary }
|
||||
|
||||
[#__tutorial_annotated_employee_parser__]
|
||||
Here we go:
|
||||
|
||||
namespace parser
|
||||
@@ -178,9 +184,6 @@ Here we go:
|
||||
BOOST_SPIRIT_DEFINE(quoted_string, person, employee);
|
||||
}
|
||||
|
||||
Take a step back and look at the previous Employee example. We are incrementally
|
||||
building on top of that.
|
||||
|
||||
[heading Rule Declarations]
|
||||
|
||||
struct quoted_string_class;
|
||||
@@ -191,6 +194,7 @@ building on top of that.
|
||||
x3::rule<person_class, ast::person> const person = "person";
|
||||
x3::rule<employee_class, ast::employee> const employee = "employee";
|
||||
|
||||
Go back and review the original [link __tutorial_employee_parser__ employee parser].
|
||||
What has changed?
|
||||
|
||||
* We split the single employee rule into three smaller rules: `quoted_string`,
|
||||
@@ -200,35 +204,34 @@ What has changed?
|
||||
|
||||
[heading Rule Classes]
|
||||
|
||||
In this example, the rule classes, `quoted_string_class`, `person_class`, and
|
||||
`employee_class` provide statically known IDs for the rules required by X3 to
|
||||
perform its tasks. In addition from that, the rule class can also be extended
|
||||
to have some user-defined customization hooks that are called:
|
||||
Like before, in this example, the rule classes, `quoted_string_class`,
|
||||
`person_class`, and `employee_class` provide statically known IDs for the
|
||||
rules required by X3 to perform its tasks. In addition to that, the rule
|
||||
class can also be extended to have some user-defined customization hooks that
|
||||
are called:
|
||||
|
||||
* On success: After a rule sucessfully parses an input.
|
||||
* On Error: After a rule fails to parse.
|
||||
|
||||
By subclassing the rule class from a client supplied handler such as
|
||||
our our `annotate_position` handler above:
|
||||
By subclassing the rule class from a client supplied handler such as our
|
||||
`annotate_position` handler above:
|
||||
|
||||
struct person_class : annotate_position {};
|
||||
struct employee_class : annotate_position {};
|
||||
|
||||
The code above tells X3 to check the rule class if it has an `on_success`
|
||||
or `on_error` member functions and calls appropriately calls them on
|
||||
such events.
|
||||
The code above tells X3 to check the rule class if it has an `on_success` or
|
||||
`on_error` member functions and appropriately calls them on such events.
|
||||
|
||||
[#__tutorial_with_directive__]
|
||||
[heading The with Directive]
|
||||
|
||||
With any parser `'p`, one can inject any data into that the that semantic
|
||||
actions and handlers can access later on when they are called. The general
|
||||
syntax is:
|
||||
For any parser `p`, one can inject supplementary data that semantic actions
|
||||
and handlers can access later on when they are called. The general syntax is:
|
||||
|
||||
with<tag>(data)[p]
|
||||
|
||||
For our particular example, we use to inject the `position_cache` into
|
||||
the parse for our `annotate_position` on_success handler to have access
|
||||
to:
|
||||
For our particular example, we use to inject the `position_cache` into the
|
||||
parse for our `annotate_position` on_success handler to have access to:
|
||||
|
||||
auto const parser =
|
||||
// we pass our position_cache to the parser so we can access
|
||||
@@ -239,16 +242,16 @@ to:
|
||||
];
|
||||
|
||||
Typically this is done just before calling `x3::parse` or `x3::phrase_parse`.
|
||||
`with` is a very lightwight operation. It is possible to inject as much
|
||||
data as you want, even multiple `with` directives:
|
||||
`with` is a very lightwight operation. It is possible to inject as much data
|
||||
as you want, even multiple `with` directives:
|
||||
|
||||
with<tag1>(data1)
|
||||
[
|
||||
with<tag2>(data2)[p]
|
||||
]
|
||||
|
||||
Multiple `with` directives can (perhaps not obviously) be injected from the
|
||||
outside caller function. Here's an outline:
|
||||
Multiple `with` directives can (perhaps not obviously) be injected from
|
||||
outside the called function. Here's an outline:
|
||||
|
||||
template <typename Parser>
|
||||
void bar(Parser const& p)
|
||||
@@ -267,7 +270,7 @@ outside caller function. Here's an outline:
|
||||
|
||||
[heading Let's Parse]
|
||||
|
||||
Now we have the complete parse mechanism:
|
||||
Now we have the complete parse mechanism with support for annotations:
|
||||
|
||||
using iterator_type = std::string::const_iterator;
|
||||
using position_cache = boost::spirit::x3::position_cache<std::vector<iterator_type>>;
|
||||
@@ -305,15 +308,15 @@ Now we have the complete parse mechanism:
|
||||
Let's walk through the code.
|
||||
|
||||
First, we have some typedefs for 1) The iterator type we are using for the
|
||||
parser, `iterator_type` and 2) For the `position_cache` type. The latter
|
||||
is a template that accepts the type of container it will hold. In this case,
|
||||
a `std::vector<iterator_type>`.
|
||||
parser, `iterator_type` and 2) For the `position_cache` type. The latter is a
|
||||
template that accepts the type of container it will hold. In this case, a
|
||||
`std::vector<iterator_type>`.
|
||||
|
||||
The main parse function accepts an input, a std::string and a reference
|
||||
to a position_cache, and retuns an AST: `std::vector<client::ast::employee>`.
|
||||
The main parse function accepts an input, a std::string and a reference to a
|
||||
position_cache, and retuns an AST: `std::vector<client::ast::employee>`.
|
||||
|
||||
Inside the parse function, we first create an AST where parsed data will
|
||||
be stored:
|
||||
Inside the parse function, we first create an AST where parsed data will be
|
||||
stored:
|
||||
|
||||
std::vector<client::ast::employee> ast;
|
||||
|
||||
@@ -338,8 +341,8 @@ On successful parse, the AST, `ast`, will contain the actual parsed data.
|
||||
[heading Getting The Source Positions]
|
||||
|
||||
Now that we have our main parse function, let's have an example sourcefile to
|
||||
parse and show how we can obtain the position of an AST element, returned on
|
||||
a successful parse.
|
||||
parse and show how we can obtain the position of an AST element, returned
|
||||
after a successful parse.
|
||||
|
||||
Given this input:
|
||||
|
||||
@@ -376,18 +379,18 @@ Given this input:
|
||||
}
|
||||
)";
|
||||
|
||||
We call our parse function after instantiating a `position_cache` object
|
||||
that will hold the source stream positions:
|
||||
We call our parse function after instantiating a `position_cache` object that
|
||||
will hold the source stream positions:
|
||||
|
||||
position_cache positions{input.begin(), input.end()};
|
||||
auto ast = parse(input, positions);
|
||||
|
||||
We now have an AST, `ast`, that contains the parsed results. Let us get
|
||||
the source positions of the 2nd employee:
|
||||
We now have an AST, `ast`, that contains the parsed results. Let us get the
|
||||
source positions of the 2nd employee:
|
||||
|
||||
auto pos = positions.position_of(ast[1]); // zero based of course!
|
||||
|
||||
`pos` is an iterator range that contians iterators to the start and
|
||||
end of `ast[1]` in the input stream.
|
||||
`pos` is an iterator range that contians iterators to the start and end of
|
||||
`ast[1]` in the input stream.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
===============================================================================/]
|
||||
|
||||
[section Employee - Parsing into structs]
|
||||
[section:employee Employee - Parsing into structs]
|
||||
|
||||
It's a common question in the __spirit_list__: How do I parse and place
|
||||
the results into a C++ struct? Of course, at this point, you already
|
||||
@@ -51,6 +51,7 @@ Now we'll write a parser for our employee. Inputs will be of the form:
|
||||
|
||||
employee{ age, "forename", "surname", salary }
|
||||
|
||||
[#__tutorial_employee_parser__]
|
||||
Here goes:
|
||||
|
||||
namespace parser
|
||||
|
||||
344
doc/x3/tutorial/error_handling.qbk
Normal file
344
doc/x3/tutorial/error_handling.qbk
Normal file
@@ -0,0 +1,344 @@
|
||||
[/==============================================================================
|
||||
Copyright (C) 2001-2018 Joel de Guzman
|
||||
|
||||
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)
|
||||
|
||||
I would like to thank Rainbowverse, llc (https://primeorbial.com/)
|
||||
for sponsoring this work and donating it to the community.
|
||||
===============================================================================/]
|
||||
|
||||
[section Error Handling]
|
||||
|
||||
As a prerequisite in understanding this tutorial, please review the previous
|
||||
[tutorial_employee employee] and [tutorial_annotation annotations] examples.
|
||||
This example builds on top of these previous examples.
|
||||
|
||||
This tutorial wouldn't be complete without touching on error handling. for
|
||||
this example, we will continue and expand on the [tutorial_employee employee
|
||||
example].
|
||||
|
||||
The full cpp file for this example can be found here:
|
||||
[@../../../example/x3/error_handling.cpp]
|
||||
|
||||
Please review the previous [tutorial_annotation annotations example]. The
|
||||
information there will be very helpful in understanding error handling.
|
||||
|
||||
[heading The AST]
|
||||
|
||||
Our AST is exactly the same as what we had before in the [tutorial_annotation
|
||||
annotations]:
|
||||
|
||||
namespace client { namespace ast
|
||||
{
|
||||
struct person : x3::position_tagged
|
||||
{
|
||||
person(
|
||||
std::string const& first_name = ""
|
||||
, std::string const& last_name = ""
|
||||
)
|
||||
: first_name(first_name)
|
||||
, last_name(last_name)
|
||||
{}
|
||||
|
||||
std::string first_name, last_name;
|
||||
};
|
||||
|
||||
struct employee : x3::position_tagged
|
||||
{
|
||||
int age;
|
||||
person who;
|
||||
double salary;
|
||||
};
|
||||
}}
|
||||
|
||||
We have two structs, the `person` and the `employee`. Each inherits from
|
||||
`x3::position_tagged` which provides positional information that we can use
|
||||
to tell the AST's position in the input stream anytime. We will need these
|
||||
information for error handling and reporting.
|
||||
|
||||
Like before, we need to tell __fusion__ about our structs to make them
|
||||
first-class fusion citizens that the grammar can utilize:
|
||||
|
||||
BOOST_FUSION_ADAPT_STRUCT(client::ast::person,
|
||||
first_name, last_name
|
||||
)
|
||||
|
||||
BOOST_FUSION_ADAPT_STRUCT(client::ast::employee,
|
||||
age, who, salary
|
||||
)
|
||||
|
||||
[heading Expectations]
|
||||
|
||||
There are occasions in which it is expected that the input must match a
|
||||
particular parser or the input is invalid. Such cases generally arise after
|
||||
matching a portion of a grammar, such that the context is fully known. In
|
||||
such a situation, failure to match should result in an exception. For
|
||||
example, when parsing an e-mail address, a name, an "@" and a domain name
|
||||
must be matched or the address is invalid.
|
||||
|
||||
Two X3 mechanisms facilitate parser expectations:
|
||||
|
||||
# The expectation operator (__x3_expect__)
|
||||
# The expect directive (__x3_expectd__`[p]`)
|
||||
|
||||
The expectation operator (__x3_expect__) requires that the following parser
|
||||
(`b`) match the input or an __x3_expectation_failure__ is emitted. Using a
|
||||
client supplied `on_error` handler, the exception can be serviced by calling
|
||||
the handler with the source iterators and context at which the parsing failed
|
||||
can be reported.
|
||||
|
||||
By contrast, the sequence operator (__x3_sequence__) does not require that
|
||||
the following parser match the input, which allows for backtracking or simply
|
||||
returning false from the parse function with no exceptions.
|
||||
|
||||
The expect directive (__x3_expectd__`[p]`) requires that the argument parser
|
||||
matches the input or an exception is emitted. Using on_error(), that
|
||||
exception can be handled by calling a handler with the context at which the
|
||||
parsing failed can be reported.
|
||||
|
||||
[heading on_error]
|
||||
|
||||
`on_error` is the counterpart of `on_success`, as discussed in the
|
||||
[tutorial_annotation annotations example]. While `on_success` handlers are
|
||||
callback hooks to client code that are executed by the parser after a
|
||||
/successful/ parse, `on_error` handlers are callback hooks to client code
|
||||
that are executed by the parser when an __x3_expectation_failure__ is thrown
|
||||
via the expect operator or directive. `on_error` handlers have access to the
|
||||
iterators, the context and the exception that was thrown.
|
||||
|
||||
[heading Error Handling]
|
||||
|
||||
Before we proceed, let me introduce a helper class, the
|
||||
x3::__x3_error_handler__. It is utility class that provides __clang__ style
|
||||
error reporting which gives you nice reports such as the following:
|
||||
|
||||
[pre
|
||||
In line 16:
|
||||
Error! Expecting: person here:
|
||||
'I am not a person!' <--- this should be a person
|
||||
____^_
|
||||
]
|
||||
|
||||
We'll see later that this error message is exactly what this example emits.
|
||||
|
||||
Here's our `on_error` handler:
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
`x3::error_handler_tag` is a special tag we will use to get a reference to
|
||||
the actual x3::__x3_error_handler__ that we will inject at very start, when
|
||||
we call parse. We get the x3::__x3_error_handler__ here:
|
||||
|
||||
auto& error_handler = x3::get<error_handler_tag>(context).get();
|
||||
|
||||
The x3::__x3_error_handler__ handles all the nitty gritty details such as
|
||||
determining the line number and actual column position, and formatting the
|
||||
error message printed. All we have to do is provide the actual error string
|
||||
which we extract from the __x3_expectation_failure__ exception:
|
||||
|
||||
std::string message = "Error! Expecting: " + x.which() + " here:";
|
||||
|
||||
Then, we return `x3::error_handler_result::fail` to tell X3 that we want to
|
||||
fail the parse when such an event is caught. You can return 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.]]
|
||||
]
|
||||
|
||||
[heading The Parser]
|
||||
|
||||
Now we'll rewrite employee parser with error handling in mind. Like the
|
||||
[tutorial_annotation annotations] example, inputs will be of the form:
|
||||
|
||||
{ age, "forename", "surname", salary }
|
||||
|
||||
Here we go:
|
||||
|
||||
namespace parser
|
||||
{
|
||||
using x3::int_;
|
||||
using x3::double_;
|
||||
using x3::lexeme;
|
||||
using ascii::char_;
|
||||
|
||||
struct quoted_string_class;
|
||||
struct person_class;
|
||||
struct employee_class;
|
||||
|
||||
x3::rule<quoted_string_class, std::string> const quoted_string = "quoted_string";
|
||||
x3::rule<person_class, ast::person> const person = "person";
|
||||
x3::rule<employee_class, ast::employee> const employee = "employee";
|
||||
|
||||
auto const quoted_string_def = lexeme['"' >> +(char_ - '"') >> '"'];
|
||||
auto const person_def = quoted_string > ',' > quoted_string;
|
||||
|
||||
auto const employee_def =
|
||||
'{'
|
||||
> int_ > ','
|
||||
> person > ','
|
||||
> double_
|
||||
> '}'
|
||||
;
|
||||
|
||||
auto const employees = employee >> *(',' >> employee);
|
||||
|
||||
BOOST_SPIRIT_DEFINE(quoted_string, person, employee);
|
||||
|
||||
struct quoted_string_class {};
|
||||
struct person_class : x3::annotate_on_success {};
|
||||
struct employee_class : error_handler, x3::annotate_on_success {};
|
||||
}
|
||||
|
||||
Go back and review the [link __tutorial_annotated_employee_parser__ annotated
|
||||
employee parser]. What has changed? It is almost identical, except:
|
||||
|
||||
Where appropriate, we're using the expectation operator (__x3_expect__) in
|
||||
place of the sequence operator (__x3_sequence__):
|
||||
|
||||
auto const person_def = quoted_string > ',' > quoted_string;
|
||||
|
||||
auto const employee_def =
|
||||
'{'
|
||||
> int_ > ','
|
||||
> person > ','
|
||||
> double_
|
||||
> '}'
|
||||
;
|
||||
|
||||
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 an `int_` next. After that, you definitely
|
||||
must have a `','` next and then a `person` and so on until the final `'}'`.
|
||||
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. In our case, it is caught in our
|
||||
`on_error` handler.
|
||||
|
||||
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).
|
||||
|
||||
[heading Let's Parse]
|
||||
|
||||
Now we have the complete parse mechanism with error handling:
|
||||
|
||||
void parse(std::string const& input)
|
||||
{
|
||||
using boost::spirit::x3::ascii::space;
|
||||
typedef std::string::const_iterator iterator_type;
|
||||
|
||||
std::vector<client::ast::employee> ast;
|
||||
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::cerr);
|
||||
|
||||
// Our parser
|
||||
using client::parser::employees;
|
||||
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))
|
||||
[
|
||||
employees
|
||||
];
|
||||
|
||||
bool r = phrase_parse(iter, end, parser, space, ast);
|
||||
|
||||
// ... Some final reports here
|
||||
}
|
||||
|
||||
Prior to calling `phrase_parse`, we first create an AST where parsed data will be
|
||||
stored:
|
||||
|
||||
std::vector<client::ast::employee> ast;
|
||||
|
||||
We also create the actual error handler, sending message to `std::cerr`:
|
||||
|
||||
error_handler_type error_handler(iter, end, std::cerr);
|
||||
|
||||
Then, we inject a reference to `error_handler`, using the `with` directive
|
||||
similar to what we did in the [link __tutorial_with_directive__ annotations
|
||||
example]:
|
||||
|
||||
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))
|
||||
[
|
||||
employees
|
||||
];
|
||||
|
||||
Now, if we give the parser an erroneous input:
|
||||
|
||||
std::string bad_input = R"(
|
||||
{
|
||||
23,
|
||||
"Amanda",
|
||||
"Stefanski",
|
||||
1000.99
|
||||
},
|
||||
{
|
||||
35,
|
||||
"Angie",
|
||||
"Chilcote",
|
||||
2000.99
|
||||
},
|
||||
{
|
||||
43,
|
||||
'I am not a person!' <--- this should be a person
|
||||
3000.99
|
||||
},
|
||||
{
|
||||
22,
|
||||
"Dorene",
|
||||
"Dole",
|
||||
2500.99
|
||||
},
|
||||
{
|
||||
38,
|
||||
"Rossana",
|
||||
"Rafferty",
|
||||
5000.99
|
||||
}
|
||||
)";
|
||||
|
||||
The parser will compplain as expected:
|
||||
|
||||
[pre
|
||||
-------------------------
|
||||
Now we have some errors
|
||||
In line 16:
|
||||
Error! Expecting: person here:
|
||||
'I am not a person!' <--- this should be a person
|
||||
____^_
|
||||
-------------------------
|
||||
Parsing failed
|
||||
-------------------------
|
||||
]
|
||||
|
||||
[endsect]
|
||||
@@ -82,21 +82,15 @@ namespace client
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Our error handler
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
template <typename Iterator>
|
||||
using error_handler = x3::error_handler<Iterator>;
|
||||
|
||||
// tag used to get our error handler from the context
|
||||
using error_handler_tag = x3::error_handler_tag;
|
||||
|
||||
struct error_handler_base
|
||||
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:";
|
||||
auto& error_handler = x3::get<error_handler_tag>(context).get();
|
||||
error_handler(x.where(), message);
|
||||
return x3::error_handler_result::fail;
|
||||
}
|
||||
@@ -136,7 +130,7 @@ namespace client
|
||||
|
||||
struct quoted_string_class {};
|
||||
struct person_class : x3::annotate_on_success {};
|
||||
struct employee_class : error_handler_base, x3::annotate_on_success {};
|
||||
struct employee_class : error_handler, x3::annotate_on_success {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,8 +152,8 @@ void parse(std::string const& input)
|
||||
iterator_type const end = input.end();
|
||||
|
||||
using boost::spirit::x3::with;
|
||||
using error_handler_type = client::parser::error_handler<iterator_type>;
|
||||
using client::parser::error_handler_tag;
|
||||
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::cerr);
|
||||
|
||||
Reference in New Issue
Block a user