]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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: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 C++ functions or function objects that are called whenever a | |
19 | part of the parser successfully recognizes a portion of the input. Say you have | |
20 | a parser `P`, and a C++ function `F`. You can make the parser call `F` whenever | |
21 | it matches an input by attaching `F`: | |
22 | ||
23 | P[F] | |
24 | ||
25 | The expression above links `F` to the parser, `P`. | |
26 | ||
27 | The function/function object signature depends on the type of the parser to | |
28 | which it is attached. The parser `double_` passes the parsed number. Thus, if we | |
29 | were to attach a function `F` to `double_`, we need `F` to be declared as: | |
30 | ||
31 | void F(double n); | |
32 | ||
33 | There are actually 2 more arguments being passed (the parser context and a | |
34 | reference to a boolean 'hit' parameter). We don't need these, for now, but we'll | |
35 | see more on these other arguments later. Spirit.Qi allows us to bind a single | |
36 | argument function, like above. The other arguments are simply ignored. | |
37 | ||
38 | [heading Examples of Semantic Actions] | |
39 | ||
40 | Presented are various ways to attach semantic actions: | |
41 | ||
42 | * Using plain function pointer | |
43 | * Using simple function object | |
44 | * Using __boost_bind__ with a plain function | |
45 | * Using __boost_bind__ with a member function | |
46 | * Using __boost_lambda__ | |
47 | ||
48 | [import ../../example/qi/actions.cpp] | |
49 | ||
50 | Given: | |
51 | ||
52 | [tutorial_semantic_action_functions] | |
53 | ||
54 | Take note that with function objects, we need to have an `operator()` with 3 | |
55 | arguments. Since we don't care about the other two, we can use `unused_type` for | |
56 | these. We'll see more of `unused_type` elsewhere. `unused_type` is a Spirit | |
57 | supplied support class. | |
58 | ||
59 | All examples parse inputs of the form: | |
60 | ||
61 | "{integer}" | |
62 | ||
63 | An integer inside the curly braces. | |
64 | ||
65 | The first example shows how to attach a plain function: | |
66 | ||
67 | [tutorial_attach_actions1] | |
68 | ||
69 | What's new? Well `int_` is the sibling of `double_`. I'm sure you can guess | |
70 | what this parser does. | |
71 | ||
72 | The next example shows how to attach a simple function object: | |
73 | ||
74 | [tutorial_attach_actions2] | |
75 | ||
76 | We can use __boost_bind__ to 'bind' member functions: | |
77 | ||
78 | [tutorial_attach_actions4] | |
79 | ||
80 | Likewise, we can also use __boost_bind__ to 'bind' plain functions: | |
81 | ||
82 | [tutorial_attach_actions3] | |
83 | ||
84 | Yep, we can also use __boost_lambda__: | |
85 | ||
86 | [tutorial_attach_actions5] | |
87 | ||
88 | There are more ways to bind semantic action functions, but the examples above | |
89 | are the most common. Attaching semantic actions is the first hurdle one has | |
90 | to tackle when getting started with parsing with Spirit. Familiarize yourself | |
91 | with this task and get intimate with the tools behind it such as __boost_bind__ | |
92 | and __boost_lambda__. | |
93 | ||
94 | The examples above can be found here: [@../../example/qi/actions.cpp] | |
95 | ||
96 | [heading Phoenix] | |
97 | ||
98 | __phoenix__, a companion library bundled with Spirit, is specifically suited | |
99 | for binding semantic actions. It is like __boost_lambda__ on steroids, with | |
100 | special custom features that make it easy to integrate semantic actions with | |
101 | Spirit. If your requirements go beyond simple to moderate parsing, it is | |
102 | suggested that you use this library. All the following examples in this tutorial | |
103 | will use __phoenix__ for semantic actions. | |
104 | ||
105 | [important There are different ways to write semantic actions for __qi__: | |
106 | using plain functions, __boost_bind__, __boost_lambda__, or | |
107 | __phoenix__. The latter three allow you to use special placeholders | |
108 | to control parameter placement (`_1`, `_2`, etc.). Each of those | |
109 | libraries has it's own implementation of the placeholders, all | |
110 | in different namespaces. You have to make sure not to mix | |
111 | placeholders with a library they don't belong to and not to | |
112 | use different libraries while writing a semantic action. | |
113 | ||
114 | Generally, for __boost_bind__, use `::_1`, `::_2`, etc. (yes, these | |
115 | placeholders are defined in the global namespace). | |
116 | ||
117 | For __boost_lambda__ use the placeholders defined in the namespace | |
118 | `boost::lambda`. | |
119 | ||
120 | For semantic actions written using __phoenix__ use the placeholders | |
121 | defined in the namespace `boost::spirit`. Please note that all | |
122 | existing placeholders for your convenience are also available from | |
123 | the namespace `boost::spirit::qi`.] | |
124 | ||
125 | [endsect] |