]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [/============================================================================== |
2 | Copyright (C) 2001-2011 Hartmut Kaiser | |
3 | Copyright (C) 2001-2011 Joel de Guzman | |
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 | [/////////////////////////////////////////////////////////////////////////////] | |
10 | [section:karma_complex Complex - A first more complex generator] | |
11 | ||
12 | In this section we will develop a generator for complex numbers, allowing to | |
13 | represent a `std::complex` either as `(real, imag)` (where `real` and `imag` | |
14 | are the real and imaginary parts of the complex number) or as a simple `real` | |
15 | if the imaginary part happens to be equal to zero. This example will highlight | |
16 | the power of __karma__ allowing to combine compile time definition of | |
17 | formatting rules with runtime based decisions which of the rules to apply. | |
18 | Also this time, we're using __boost_phoenix__ to do the semantic actions. | |
19 | ||
20 | Our goal is to allow for two different output formats to be applied depending | |
21 | on whether the imaginary part of the complex number is zero or not. Let's write | |
22 | both as a set of alternatives: | |
23 | ||
24 | '(' << double_ << ", " << double_ << ')' | |
25 | | double_ | |
26 | ||
27 | where the first alternative should be used for numbers having a non-zero | |
28 | imaginary part, while the second is for real numbers. Generally, alternatives | |
29 | are tried in the sequence of their definition as long until one of the | |
30 | expressions (as delimited by `'|'`) succeeds. If no generator expression | |
31 | succeeds the whole alternative fails. | |
32 | ||
33 | If we left this formatting grammar as is our generator would always choose | |
34 | the first alternative. We need to add some additional rules allowing to make the | |
35 | first alternative fail. So, if the first alternative fails the second one will | |
36 | be chosen instead. The decision about whether to choose the first alternative | |
37 | has to be made at runtime as only then we actually know the value of the | |
38 | imaginary part of the complex number. __karma__ provides us with with a | |
39 | primitive generator `eps()`, which is usable as a semantic predicate. It has | |
40 | the property to 'succeed' generating only if its argument is true (while it | |
41 | never generates any output on its own). | |
42 | ||
43 | double imag = ...; // imaginary part | |
44 | ||
45 | eps(imag != 0) << '(' << double_ << ", " << double_ << ')' | |
46 | | double_ | |
47 | ||
48 | If one of the generator elements of a sequence fails the whole sequence will | |
49 | fail. This is exactly what we need, forcing the second alternative to be chosen | |
50 | for complex numbers with imaginary parts equal to zero. | |
51 | ||
52 | [import ../../example/karma/complex_number.cpp] | |
53 | ||
54 | Now on to the full example, this time with the proper semantic actions (the | |
55 | complete cpp file for this example can be found here: | |
56 | [@../../example/karma/complex_number.cpp complex_number.cpp]). | |
57 | ||
58 | We will use the `std::complex` type for this and all subsequent related | |
59 | examples. And here you can see the full code of the generator allowing to | |
60 | output a complex number either as a pair of numbers (if the imaginary part is | |
61 | non-zero) or as a single number (if the complex is a real number): | |
62 | ||
63 | [tutorial_karma_complex_number] | |
64 | ||
65 | The `double_` generators have this semantic action attached: | |
66 | ||
67 | _1 = n | |
68 | ||
69 | which passes `n` to the first element of the s generator's attached | |
70 | semantic action. Remember, semantic actions in __karma__ are called | |
71 | before the corresponding generator is invoked and they are expected | |
72 | to provide the generator with the data to be used. The semantic action | |
73 | above assigns the value to be generated (`n`) to the generator (actually, | |
74 | the attribute of `double_`). `_1` is a Phoenix placeholder referring to | |
75 | the attribute of the semantic action's attached generator. If you need | |
76 | more information about semantic actions, you may want to read about them | |
77 | in this section: __karma_actions__. | |
78 | ||
79 | These semantic actions are easy to understand but have the unexpected side | |
80 | effect of being slightly less efficient than it could be. In addition they tend | |
81 | to make the formatting grammar less readable. We will see in one of the next | |
82 | sections how it is possible to use other, built-in features of __karma__ to get | |
83 | rid of the semantic actions altogether. When writing your grammars in Spirit | |
84 | you should always try to avoid semantic actions which is often possible. | |
85 | Semantic actions are really powerful tools but grammars tend to be more | |
86 | efficient and readable without them. | |
87 | ||
88 | [endsect] | |
89 | ||
90 | [/////////////////////////////////////////////////////////////////////////////] | |
91 | [section:karma_easier_complex Complex - Made easier] | |
92 | ||
93 | [import ../../example/karma/complex_number_easier.cpp] | |
94 | ||
95 | In the previous section we showed how to format a complex number (i.e. | |
96 | a pair of doubles). In this section we will build on this example with the goal | |
97 | to avoid using semantic actions in the format specification. Let's have a look | |
98 | at the resulting code first, trying to understand it afterwards (the full source | |
99 | file for this example can be found here: | |
100 | [@../../example/karma/complex_number_easier.cpp complex_number_easier.cpp]): | |
101 | ||
102 | [tutorial_karma_complex_number_easier] | |
103 | ||
104 | Let's cover some basic library features first. | |
105 | ||
106 | [heading Making Numeric Generators Fail] | |
107 | ||
108 | All __karma_numeric__ (such as `double_`, et.al.) take the value to | |
109 | emit from an attached attribute. | |
110 | ||
111 | double d = 1.5; | |
112 | generate(out, double_, d); // will emit '1.5' (without the quotes) | |
113 | ||
114 | Alternatively, they may be initialized from a literal value. For instance, to | |
115 | emit a constant `1.5` you may write: | |
116 | ||
117 | generate(out, double_(1.5)); // will emit '1.5' as well (without the quotes) | |
118 | ||
119 | The difference to a simple `1.5` or `lit(1.5)` is that the `double_(1.5)` | |
120 | consumes an attribute if one is available. Additionally, it compares its | |
121 | immediate value to the value of the supplied attribute, and fails if those are | |
122 | not equal. | |
123 | ||
124 | double d = 1.5; | |
125 | generate(out, double_(1.5), d); // will emit '1.5' as long as d == 1.5 | |
126 | ||
127 | This feature, namely to succeed generating only if the attribute matches the | |
128 | immediate value, enables numeric generators to be used to dynamically control | |
129 | the way output is generated. | |
130 | ||
131 | [note Quite a few generators will fail if their immediate value is not equal | |
132 | to the supplied attribute. Among those are all __karma_char__ and | |
133 | all [karma_string String Generators]. Generally, | |
134 | all generators having a sibling created by a variant of `lit()` belong | |
135 | into this category.] | |
136 | ||
137 | [heading Predicates - The Conditionals for Output Generators] | |
138 | ||
139 | In addition to the __karma_eps__ generator mentioned earlier __karma__ provides | |
140 | two special operators enabling dynamic flow control: the | |
141 | __karma_and_predicate__ and the __karma_not_predicate__. The main property of | |
142 | both predicates is to discard all output emitted by the attached generator. | |
143 | This is equivalent to the behavior of predicates used for | |
144 | parsing. There the predicates do not consume any input allowing to look ahead | |
145 | in the input stream. In Karma, the and predicate succeeds as long as its | |
146 | associated generator succeeds, while the not predicate succeeds only if its | |
147 | associated generator fails. | |
148 | ||
149 | [note The generator predicates in __karma__ consume an attribute, if | |
150 | available. This makes them behave differently from predicates in __qi__, | |
151 | where they do not expose any attribute. This is because predicates | |
152 | allow to make decisions based on data available only at runtime. While | |
153 | in __qi__ during parsing the decision is made based on looking ahead | |
154 | a few more input tokens, in __karma__ the criteria has to be supplied | |
155 | by the user. The simplest way to do this is by providing an attribute.] | |
156 | ||
157 | As an example, the following generator succeeds generating | |
158 | ||
159 | double d = 1.0; | |
160 | BOOST_ASSERT(generate(out, &double_(1.0), d)); // succeeds as d == 1.0 | |
161 | ||
162 | while this one will fail: | |
163 | ||
164 | double d = 1.0; | |
165 | BOOST_ASSERT(!generate(out, !double_(1.0), d)); // fails as d == 1.0 | |
166 | ||
167 | Neither of these will emit any output. The predicates discard everything | |
168 | emitted by the generators to which they are applied. | |
169 | ||
170 | [heading Ignoring Supplied Attributes] | |
171 | ||
172 | Sometimes it is desirable to 'skip' (i.e. ignore) a provided attribute. This | |
173 | happens for instance in alternative generators, where some of the alternatives | |
174 | need to extract only part of the overall attribute passed to the alternative | |
175 | generator. __karma__ has a special pseudo generator for that: the directive | |
176 | __karma_omit__`[]`. This directive consumes an attribute of the type defined by its | |
177 | embedded generator but it does not emit any output. | |
178 | ||
179 | [note The __karma__ __karma_omit__ directive does the 'opposite' of the | |
180 | directive of the same name in __qi__. While the __qi_omit__ in __qi__ | |
181 | consumes input without exposing an attribute, its __karma__ counterpart | |
182 | consumes an attribute without emitting any output. | |
183 | ] | |
184 | ||
185 | [heading Putting everything together] | |
186 | ||
187 | Very similar to our first example earlier we use two alternatives to allow for | |
188 | the two different output formats depending on whether the imaginary part of the | |
189 | complex number is equal to zero or not. The first alternative is executed if the | |
190 | imaginary part is not zero, the second alternative otherwise. This time we make | |
191 | the decision during runtime using the __karma_not_predicate__ combined with the | |
192 | feature of many Karma primitive generators to /fail/ under certain conditions. | |
193 | Here is the first alternative again for your reference: | |
194 | ||
195 | !double_(0.0) << '(' << double_ << ", " << double_ << ')' | |
196 | ||
197 | The generator `!double_(0.0)` does several things. First, because of the | |
198 | __karma_not_predicate__, it succeeds only if the `double_(0.0)` generator | |
199 | /fails/, making the whole first alternative fail otherwise. Second, the | |
200 | `double_(0.0)` generator succeeds only if the value of its attribute is equal | |
201 | to its immediate parameter (i.e. in this case `0.0`). And third, the | |
202 | not predicate does not emit any output (regardless whether it succeeds or | |
203 | fails), discarding any possibly emitted output from the `double_(0.0)`. | |
204 | ||
205 | As we pass the imaginary part of the complex number as the attribute value for | |
206 | the `!double_(0.0)`, the overall first alternative will be chosen only if | |
207 | it is not equal to zero (the `!double_(0.0)` does not fail). That is exactly | |
208 | what we need! | |
209 | ||
210 | Now, the second alternative has to emit the real part of the complex | |
211 | number only. In order to simplify the overall grammar we strive to unify the | |
212 | attribute types of all alternatives. As the attribute type exposed by the first | |
213 | alternative is `tuple<double, double, double>`, we need to skip the first and | |
214 | last element of the attribute (remember, we pass the real part as the second | |
215 | attribute element). We achieve this by using the `omit[]` directive: | |
216 | ||
217 | omit[double_] << double_ << omit[double_] | |
218 | ||
219 | The overall attribute of this expression is `tuple<double, double, double>`, | |
220 | but the `omit[]` 'eats up' the first and the last element. The output emitted | |
221 | by this expression consist of a single generated double representing the second | |
222 | element of the tuple, i.e. the real part of our complex number. | |
223 | ||
224 | [important Generally, it is preferable to use generator constructs not | |
225 | requiring semantic actions. The reason is that semantic actions | |
226 | often use constructs like: `double_[_1 = c.real()]`. But this | |
227 | assignment is a real one! The data is in fact /copied/ to the | |
228 | attribute value of the generator attached to the action. On the | |
229 | other hand, grammars without any semantic actions usually don't | |
230 | have to copy the attributes, making them more efficient.] | |
231 | ||
232 | [endsect] | |
233 | ||
234 | [/////////////////////////////////////////////////////////////////////////////] | |
235 | [section:karma_adapted_complex Complex - Fully Integrated] | |
236 | ||
237 | [import ../../example/karma/complex_number_adapt.cpp] | |
238 | ||
239 | Until now, we have been working around the fact that `std::complex<>` is not | |
240 | a native __fusion__ sequence. We have not been able to use it with the same | |
241 | simplicity and natural grace of a `fusion::tuple<>` or a similar __fusion__ | |
242 | data structure. Fortunately, starting with Boost V1.43 it is possible to | |
243 | adapt any data structure (not only, as before, structures with publicly | |
244 | accessible members) as a __fusion__ sequence. All we have to do is to employ one | |
245 | of the new `BOOST_FUSION_ADAPT_ADT` macros. | |
246 | ||
247 | [heading Adapting a Class As a Fusion Sequence] | |
248 | ||
249 | Let us start with the code again, following up with the explanations afterwards. | |
250 | ||
251 | Wouldn't it be optimal if we could pass our instance of a `std::complex<>` | |
252 | directly to /Karma's/ `generate()` function: | |
253 | ||
254 | [tutorial_karma_complex_number_adapt] | |
255 | ||
256 | Indeed, this is possible! All we have to supply to make this work is a magic | |
257 | incantation (somewhere in the global namespace): | |
258 | ||
259 | [tutorial_karma_complex_number_adapt_class] | |
260 | ||
261 | Most of the formatting grammar itself has not changed from the last section. We | |
262 | still utilize a very similar scheme. We have an alternative providing the | |
263 | formatting rules for our both use cases: one for the full complex format and | |
264 | one for complex numbers with a zero imaginary part. But instead of selecting | |
265 | the required alternative by comparing the imaginary part to zero in the grammar | |
266 | we assume to receive a boolean attribute carrying this information: | |
267 | ||
268 | &true_ << "(" << double_ << ", " << double_ << ")" | |
269 | ||
270 | This reads as: 'if the first (boolean) element of the supplied fusion sequence | |
271 | is `true`, proceed as specified, else select the next alternative'. The next | |
272 | alternative now accounts for the boolean element as well, but is otherwise | |
273 | (almost) unchanged from the last section's example. | |
274 | ||
275 | Now it should be clear why our adapt construct above exposes a three element | |
276 | __fusion__ sequence: a boolean and two double values (the real and the | |
277 | imaginary part of the complex number). We want it to match the requirements of | |
278 | our formatting grammar, which expects those exact values. The | |
279 | `BOOST_FUSION_ADAPT_ADT` macro allows us to specify an arbitrary accessor | |
280 | construct, not necessarily limited to just calling a member function of the | |
281 | object instance (represented by `obj` in the context of this macro). This | |
282 | allows us to nicely encapsulate the decision logic into the class adaptation. | |
283 | ||
284 | Here is the last new bit of information. If you look closely you realize the | |
285 | second alternative to be 'shorter' than the first one. It consumes only | |
286 | two elements of the supplied fusion sequence: it ignores the boolean and uses | |
287 | the real part of the complex number to generate its output. If there are more | |
288 | elements in our attribute than needed, we now can safely omit them from the | |
289 | grammar (which is a new 'feature' added to __spirit__ in V1.43 as well). | |
290 | Note, we could have written the alternative as | |
291 | ||
292 | &false_ << double_ | |
293 | ||
294 | but this would have been a bit less efficient as we needed to compare the | |
295 | boolean value again, while the final solution provided will just ignore it. | |
296 | ||
297 | [endsect] | |
298 |