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