warming_up.qbk 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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 Warming up]
  8. Learning how to use __karma__ is really simple. We will start from trivial
  9. examples, ramping up as we go.
  10. [heading Trivial Example #1 Generating a number]
  11. Let's create a generator that will output a floating-point number:
  12. double_
  13. Easy huh? The above code actually instantiates a Spirit floating point
  14. generator (a built-in generator). Spirit has many pre-defined generators and
  15. consistent naming conventions will help you finding your way through the maze.
  16. Especially important to note is that things related to identical entities (as
  17. in this case, floating point numbers) are named identically in __karma__ and in
  18. __qi__. Actually, both libraries are using the very same variable instance to
  19. refer to a floating point generator or parser: `double_`.
  20. [heading Trivial Example #2 Generating two numbers]
  21. Now, let's create a generator that will output a line consisting of two
  22. floating-point numbers.
  23. double_ << double_
  24. Here you see the familiar floating-point numeric generator `double_` used twice,
  25. once for each number. If you are used to see the `'>>'` operator for concatenating
  26. two parsers in __qi__ you might wonder, what's that `'<<'` operator doing in
  27. there? We decided to distinguish generating and parsing of sequences the same
  28. way as the std::stream libraries do: we use operator `'>>'` for input (parsing),
  29. and operator `'<<'` for output (generating). Other than that there is no
  30. significant difference. The above program creates a generator from two simpler
  31. generators, glueing them together with the sequence operator. The result is a
  32. generator that is a composition of smaller generators. Whitespace between
  33. numbers can implicitly be inserted depending on how the generator is invoked
  34. (see below).
  35. [note When we combine generators, we end up with a "bigger" generator, but
  36. it's still a generator. Generators can get bigger and bigger, nesting more
  37. and more, but whenever you glue two generators together, you end up with one
  38. bigger generator. This is an important concept.
  39. ]
  40. [heading Trivial Example #3 Generating one or more numbers]
  41. Now, creating output for two numbers is not too interesting. Let's create a
  42. generator that will output zero or more floating-point numbers in a row.
  43. *double_
  44. This is like a regular-expression Kleene Star. We moved the `*` to the front for
  45. the same reasons we did in __qi__: we must work with the syntax rules of C++.
  46. But if you know regular expressions (and for sure you remember those C++ syntax
  47. rules) it will start to look very familiar in a matter of a very short time.
  48. Any expression that evaluates to a generator may be used with the Kleene Star.
  49. Keep in mind, though, that due to C++ operator precedence rules you may need
  50. to put the expression in parentheses for complex expressions. As above,
  51. whitespace can be inserted implicitly in between the generated numbers, if
  52. needed.
  53. [heading Trivial Example #4 Generating a comma-delimited list of numbers]
  54. We follow the lead of __qi__'s warming up section and will create a generator
  55. that produces a comma-delimited list of numbers.
  56. double_ << *(lit(',') << double_)
  57. Notice `lit(',')`. It is a literal character generator that simply generates
  58. the comma `','`. In this case, the Kleene Star is modifying a more complex
  59. generator, namely, the one generated by the expression:
  60. (lit(',') << double_)
  61. Note that this is a case where the parentheses are necessary. The Kleene Star
  62. encloses the complete expression above, repeating the whole pattern in the
  63. generated output zero or more times.
  64. [heading Let's Generate!]
  65. We're done with defining the generator. All that's left is to invoke the
  66. generator to do its work. For now, we will use the `generate_delimited` function.
  67. One overload of this function accepts four arguments:
  68. # An output iterator accepting the generated characters
  69. # The generator expression
  70. # Another generator called the delimiting generator
  71. # The data to format and output
  72. While comparing this minimal example with an equivalent parser example we
  73. notice a significant difference. It is possible (and actually, it makes a lot
  74. of sense) to use a parser without creating any internal representation of the
  75. parsed input (i.e. without 'producing' any data from the parsed input). Using
  76. a parser in this mode checks the provided input against
  77. the given parser expression allowing to verify whether the input is parsable.
  78. For generators this mode doesn't make any sense. What is output generation
  79. without generating any output? So we always will have to supply the data the
  80. output should be generated from. In our example we supply a list of `double`
  81. numbers as the last parameter to the function `generate_delimited` (see code
  82. below).
  83. In this example, we wish to delimit the generated numbers by spaces. Another
  84. generator named `space` is included in Spirit's repertoire of predefined
  85. generators. It is a very trivial generator that simply produces spaces. It is
  86. the equivalent to writing `lit(' ')`, or simply `' '`. It has been
  87. implemented for similarity with the corresponding predefined `space` parser.
  88. We will use `space` as our delimiter. The delimiter is the one responsible for
  89. inserting characters in between generator elements such as the `double_` and
  90. `lit`.
  91. Ok, so now let's generate (for the complete source code of this example please
  92. refer to [@../../example/karma/num_list1.cpp num_list1.cpp]).
  93. [import ../../example/karma/num_list1.cpp]
  94. [tutorial_karma_numlist1]
  95. [note You might wonder how a `vector<double>`, which is actually a single data
  96. structure, can be used as an argument (we call it attribute) to a sequence
  97. of generators. This seems to be counter intuitive and doesn't match with
  98. your experience of using `printf`, where each formatting placeholder has
  99. to be matched with a corresponding argument. Well, we will explain this
  100. behavior in more detail later in this tutorial. For now just consider
  101. this to be a special case, implemented on purpose to allow more flexible
  102. output formatting of STL containers: sequences accept a single container
  103. attribute if all elements of this sequence accept attributes compatible
  104. with the elements held by this container.]
  105. The generate function returns `true` or `false` depending on the result of the
  106. output generation. As outlined in different places of this documentation, a
  107. generator may fail for different reasons. One of the possible reasons is an
  108. error in the underlying output iterator (memory exhausted or disk full, etc.).
  109. Another reason might be that the data doesn't match the requirements of a
  110. particular generator.
  111. [note `char` and `wchar_t` operands
  112. The careful reader may notice that the generator expression has `','` instead
  113. of `lit(',')` as the previous examples did. This is ok due to C++ syntax
  114. rules of conversion. Spirit provides `<<` operators that are overloaded to
  115. accept a `char` or `wchar_t` argument on its left or right (but not both).
  116. An operator may be overloaded if at least one of its parameters is a
  117. user-defined type. In this case, the `double_` is the 2nd argument to
  118. `operator<<`, and so the proper overload of `<<` is used, converting `','`
  119. into a character literal generator.
  120. The problem with omitting the `lit` should be obvious: `'a' << 'b'` is not a
  121. spirit generator, it is a numeric expression, left-shifting the ASCII (or
  122. another encoding) value of `'a'` by the ASCII value of `'b'`. However, both
  123. `lit('a') << 'b'` and `'a' << lit('b')` are Spirit sequence generators
  124. for the letter `'a'` followed by `'b'`. You'll get used to it, sooner or
  125. later.
  126. ]
  127. Note that we inlined the generator directly in the call to `generate_delimited`.
  128. Upon calling this function, the expression evaluates into a temporary,
  129. unnamed generator which is passed into the `generate_delimited` function,
  130. used, and then destroyed.
  131. Here, we chose to make the generate function generic by making it a template,
  132. parameterized by the output iterator type. By doing so, it can put the generated
  133. data into any STL conforming output iterator.
  134. [endsect] [/ Warming up]