complex.qbk 15 KB

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