actions.qbk 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. [/==============================================================================
  2. Copyright (C) 2001-2011 Joel de Guzman
  3. Copyright (C) 2001-2011 Hartmut Kaiser
  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. [section:semantic_actions Generator Semantic Actions]
  8. In the previous section we mentioned a very important difference between parsers
  9. and generators. While parsers may be used without 'producing' any data,
  10. generators always need data to generate the output from. We mentioned one way
  11. of passing data to the generator by supplying it as a parameter to one of the
  12. main API functions (for instance `generate()` or `generate_delimited()`).
  13. But sometimes this is not possible or not desirable.
  14. Very much like for __qi__ we have semantic actions in __karma__ as well.
  15. Semantic actions may be attached to any point in the grammar specification.
  16. These actions are C++ functions or function objects that are called whenever a
  17. part of the generator is about to be invoked. Say you have a generator `G`,
  18. and a C++ function `F`, you can make the generator call `F` just before it gets
  19. invoked by attaching `F`:
  20. G[F]
  21. The expression above links `F` to the generator, `G`.
  22. Semantic actions in __qi__ are invoked after a parser successfully
  23. matches its input and the matched value is passed into the
  24. semantic action. In __karma__ the opposite happens. Semantic actions are called
  25. before its associated generator is invoked. They may provide the data required
  26. by the generator.
  27. The function/function object signature depends on the type of the generator to
  28. which it is attached. The generator `double_` expects the number to generate.
  29. Thus, if we were to attach a function `F` to `double_`, we need `F` to be
  30. declared as:
  31. void F(double& n);
  32. where the function is expected to initialize the parameter `n` with the value
  33. to generate.
  34. [important Generally, and more formally, the semantic action `F` attached to
  35. a generator `G` needs to take a reference to the generator's
  36. attribute type as its first parameter. For more information about
  37. generator attributes please see the section __karma_attribute__.
  38. In the example above the function F takes a `double&` as its first
  39. parameter as the attribute of the `double_` generator happens to be
  40. a `double`.
  41. ]
  42. There are actually 2 more arguments being passed (the generator context and a
  43. reference to a boolean 'pass' parameter). We don't need these, for now, but
  44. we'll see more on these other arguments later. __karma__ allows us to bind a
  45. single argument function, like above. The other arguments are simply ignored.
  46. To sum up, the possible signatures for semantic actions are:
  47. void f(Attrib&);
  48. void f(Attrib&, Context&);
  49. void f(Attrib&, Context&, bool&);
  50. [heading Examples of Semantic Actions]
  51. In the following example we present various ways to attach semantic actions:
  52. * Using a plain function pointer
  53. * Using a simple function object
  54. * Using __boost_bind__ with a plain function
  55. * Using __boost_bind__ with a member function
  56. * Using __boost_lambda__
  57. [import ../../example/karma/actions.cpp]
  58. Let's assume we have:
  59. [karma_tutorial_semantic_action_functions]
  60. Take note that with function objects, we need to have an `operator()` with 3
  61. arguments. Since we don't care about the other two, we can use `unused_type` for
  62. these. We'll see more of `unused_type` elsewhere. Get used to it. `unused_type`
  63. is a Spirit supplied support class. Most of the time it stands for 'I don't
  64. care, just use the appropriate default'.
  65. All following examples generate outputs of the form:
  66. "{integer}"
  67. An integer inside the curly braces.
  68. The first example shows how to attach a plain function:
  69. [karma_tutorial_attach_actions1]
  70. What's new? Well `int_` is the sibling of `double_`. I'm sure you can guess
  71. what this generator does and what type of attribute it expects.
  72. The next example shows how to attach a simple function object:
  73. [karma_tutorial_attach_actions2]
  74. We can use __boost_bind__ to 'bind' member functions:
  75. [karma_tutorial_attach_actions4]
  76. Likewise, we can also use __boost_bind__ to 'bind' plain functions:
  77. [karma_tutorial_attach_actions3]
  78. And last but not least, we can also use __boost_lambda__:
  79. [karma_tutorial_attach_actions5]
  80. There are more ways to bind semantic action functions, but the examples above
  81. are the most common. Attaching semantic actions is the first hurdle one has
  82. to tackle when getting started with generating with Spirit. If you didn't do so
  83. yet, it is probably a good idea to familiarize yourself with the tools behind
  84. it such as __boost_bind__ and __boost_lambda__.
  85. The examples above can be found here: [@../../example/karma/actions.cpp actions.cpp]
  86. [heading Phoenix]
  87. __phoenix__, a companion library bundled with Spirit, is specifically suited
  88. for binding semantic actions. It is like __boost_lambda__ on steroids, with
  89. special custom features that make it easy to integrate semantic actions with
  90. Spirit. If your requirements go beyond simple to moderate generation, I suggest
  91. you use this library. Examples presented henceforth shall be using the Phoenix
  92. library exclusively.
  93. [important There are different ways to write semantic actions for __karma__:
  94. using plain functions, __boost_bind__, __boost_lambda__, or
  95. __phoenix__. The latter three allow you to use special placeholders
  96. to control parameter placement (`_1`, `_2`, etc.). Each of those
  97. libraries has it's own implementation of the placeholders, all
  98. in different namespaces. You have to make sure not to mix
  99. placeholders with a library they don't belong to and not to
  100. use different libraries while writing a semantic action.
  101. Generally, for __boost_bind__, use `::_1`, `::_2`, etc. (yes, these
  102. placeholders are defined in the global namespace).
  103. For __boost_lambda__ use the placeholders defined in the namespace
  104. `boost::lambda`.
  105. For semantic actions written using __phoenix__ use the placeholders
  106. defined in the namespace `boost::spirit`. Please note that all
  107. existing placeholders for your convenience are also available from
  108. the namespace `boost::spirit::karma`.]
  109. [endsect] [/ Semantic Actions]