]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [/============================================================================== |
2 | Copyright (C) 2001-2015 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:semantic_actions Parser Semantic Actions] | |
10 | ||
11 | The example in the previous section was very simplistic. It only recognized | |
12 | data, but did nothing with it. It answered the question: "Did the input match?". | |
13 | Now, we want to extract information from what was parsed. For example, we would | |
14 | want to store the parsed number after a successful match. To do this, you will | |
15 | need ['semantic actions]. | |
16 | ||
17 | Semantic actions may be attached to any point in the grammar specification. | |
18 | These actions are polymorphic function objects that are called whenever a part | |
19 | of the parser successfully recognizes a portion of the input. Say you have a | |
20 | parser `p`, and a polymorphic C++ function object `f`. You can make the parser | |
21 | call `f` whenever it matches an input by attaching `f`: | |
22 | ||
23 | p[f] | |
24 | ||
25 | The expression above links `f` to the parser, `p`. `f` is expected to be a | |
26 | polymorphic function object with the signature: | |
27 | ||
28 | template <typename Context> | |
29 | void operator()(Context const& ctx) const; | |
30 | ||
31 | We can also use C++14 generic lambdas of the form: | |
32 | ||
33 | [](auto& ctx) { /*...*/ } | |
34 | ||
35 | From the context, we can extract relevant information: | |
36 | ||
37 | [table Parse Context Access Functions | |
38 | [[Function] [Description] [Example]] | |
39 | [[`_val`] [A reference to the attribute of the | |
40 | innermost rule that directly or indirectly | |
41 | invokes the parser `p`] [`_val(ctx) = "Gotya!"`]] | |
42 | [[`_where`] [Iterator range to the input stream] [`_where(ctx).begin()`]] | |
43 | [[`_attr`] [A reference to the attribute of the | |
44 | parser `p`] [`_val(ctx) += _attr(ctx)`]] | |
45 | [[`_pass`] [A reference to a `bool` flag that | |
46 | can be used to force the `p` to fail] [`_pass(ctx) = false`]] | |
47 | ] | |
48 | ||
49 | [heading Examples of Semantic Actions] | |
50 | ||
51 | Given: | |
52 | ||
53 | struct print_action | |
54 | { | |
55 | template <typename Context> | |
56 | void operator()(Context const& ctx) const | |
57 | { | |
58 | std::cout << _attr(ctx) << std::endl; | |
59 | } | |
60 | }; | |
61 | ||
62 | Take note that with function objects, we need to have an `operator()` with | |
63 | the Context argument. If we don't care about the context, we can use | |
64 | `unused_type`. We'll see more of `unused_type` elsewhere. `unused_type` is a | |
65 | Spirit supplied support class. | |
66 | ||
67 | All examples parse inputs of the form: | |
68 | ||
69 | "{NNN}" | |
70 | ||
71 | Where NNN is an integer inside the curly braces (e.g. {44}). | |
72 | ||
73 | The first example shows how to attach a function object: | |
74 | ||
75 | parse(first, last, '{' >> int_[print_action()] >> '}'); | |
76 | ||
77 | What's new? Well `int_` is the sibling of `double_`. I'm sure you can guess | |
78 | what this parser does. | |
79 | ||
80 | The next example shows how use C++14 lambda: | |
81 | ||
82 | auto f = [](auto& ctx){ std::cout << _attr(ctx) << std::endl; }; | |
83 | parse(first, last, '{' >> int_[f] >> '}'); | |
84 | ||
85 | Attaching semantic actions is the first hurdle one has to tackle when getting | |
86 | started with parsing with Spirit. Familiarize yourself with this task. | |
87 | ||
88 | The examples above can be found here: [@../../../example/x3/actions.cpp] | |
89 | ||
90 | [endsect] |