| [/============================================================================== |
| Copyright (C) 2001-2010 Joel de Guzman |
| Copyright (C) 2001-2010 Hartmut Kaiser |
| |
| Distributed under the Boost Software License, Version 1.0. (See accompanying |
| file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| ===============================================================================/] |
| |
| [section Warming up] |
| |
| Learning how to use __karma__ is really simple. We will start from trivial |
| examples, ramping up as we go. |
| |
| |
| [heading Trivial Example #1 Generating a number] |
| |
| Let's create a generator that will output a floating-point number: |
| |
| double_ |
| |
| Easy huh? The above code actually instantiates a Spirit floating point |
| generator (a built-in generator). Spirit has many pre-defined generators and |
| consistent naming conventions will help you finding your way through the maze. |
| Especially important to note is that things related to identical entities (as |
| in this case, floating point numbers) are named identically in __karma__ and in |
| __qi__. Actually, both libraries are using the very same variable instance to |
| refer to a floating point generator or parser: `double_`. |
| |
| |
| [heading Trivial Example #2 Generating two numbers] |
| |
| Now, let's create a generator that will output a line consisting of two |
| floating-point numbers. |
| |
| double_ << double_ |
| |
| Here you see the familiar floating-point numeric generator `double_` used twice, |
| once for each number. If you are used to see the `'>>'` operator for concatenating |
| two parsers in __qi__ you might wonder, what's that `'<<'` operator doing in |
| there? We decided to distinguish generating and parsing of sequences the same |
| way as the std::stream libraries do: we use operator `'>>'` for input (parsing), |
| and operator `'<<'` for output (generating). Other than that there is no |
| significant difference. The above program creates a generator from two simpler |
| generators, glueing them together with the sequence operator. The result is a |
| generator that is a composition of smaller generators. Whitespace between |
| numbers can implicitly be inserted depending on how the generator is invoked |
| (see below). |
| |
| [note When we combine generators, we end up with a "bigger" generator, but |
| it's still a generator. Generators can get bigger and bigger, nesting more |
| and more, but whenever you glue two generators together, you end up with one |
| bigger generator. This is an important concept. |
| ] |
| |
| |
| [heading Trivial Example #3 Generating one or more numbers] |
| |
| Now, creating output for two numbers is not too interesting. Let's create a |
| generator that will output zero or more floating-point numbers in a row. |
| |
| *double_ |
| |
| This is like a regular-expression Kleene Star. We moved the `*` to the front for |
| the same reasons we did in __qi__: we must work with the syntax rules of C++. |
| But if you know regular expressions (and for sure you remember those C++ syntax |
| rules) it will start to look very familiar in a matter of a very short time. |
| |
| Any expression that evaluates to a generator may be used with the Kleene Star. |
| Keep in mind, though, that due to C++ operator precedence rules you may need |
| to put the expression in parentheses for complex expressions. As above, |
| whitespace can be inserted implicitly in between the generated numbers, if |
| needed. |
| |
| |
| [heading Trivial Example #4 Generating a comma-delimited list of numbers] |
| |
| We follow the lead of __qi__'s warming up section and will create a generator |
| that produces a comma-delimited list of numbers. |
| |
| double_ << *(lit(',') << double_) |
| |
| Notice `lit(',')`. It is a literal character generator that simply generates |
| the comma `','`. In this case, the Kleene Star is modifying a more complex |
| generator, namely, the one generated by the expression: |
| |
| (lit(',') << double_) |
| |
| Note that this is a case where the parentheses are necessary. The Kleene Star |
| encloses the complete expression above, repeating the whole pattern in the |
| generated output zero or more times. |
| |
| [heading Let's Generate!] |
| |
| We're done with defining the generator. All that's left is to invoke the |
| generator to do its work. For now, we will use the `generate_delimited` function. |
| One overload of this function accepts four arguments: |
| |
| # An output iterator accepting the generated characters |
| # The generator expression |
| # Another generator called the delimiting generator |
| # The data to format and output |
| |
| While comparing this minimal example with an equivalent parser example we |
| notice a significant difference. It is possible (and actually, it makes a lot |
| of sense) to use a parser without creating any internal representation of the |
| parsed input (i.e. without 'producing' any data from the parsed input). Using |
| a parser in this mode checks the provided input against |
| the given parser expression allowing to verify whether the input is parsable. |
| For generators this mode doesn't make any sense. What is output generation |
| without generating any output? So we always will have to supply the data the |
| output should be generated from. In our example we supply a list of `double` |
| numbers as the last parameter to the function `generate_delimited` (see code |
| below). |
| |
| In this example, we wish to delimit the generated numbers by spaces. Another |
| generator named `space` is included in Spirit's repertoire of predefined |
| generators. It is a very trivial generator that simply produces spaces. It is |
| the equivalent to writing `lit(' ')`, or simply `' '`. It has been |
| implemented for similarity with the corresponding predefined `space` parser. |
| We will use `space` as our delimiter. The delimiter is the one responsible for |
| inserting characters in between generator elements such as the `double_` and |
| `lit`. |
| |
| Ok, so now let's generate (for the complete source code of this example please |
| refer to [@../../example/karma/num_list1.cpp num_list1.cpp]). |
| |
| [import ../../example/karma/num_list1.cpp] |
| [tutorial_karma_numlist1] |
| |
| [note You might wonder how a `vector<double>`, which is actually a single data |
| structure, can be used as an argument (we call it attribute) to a sequence |
| of generators. This seems to be counter intuitive and doesn't match with |
| your experience of using `printf`, where each formatting placeholder has |
| to be matched with a corresponding argument. Well, we will explain this |
| behavior in more detail later in this tutorial. For now just consider |
| this to be a special case, implemented on purpose to allow more flexible |
| output formatting of STL containers: sequences accept a single container |
| attribute if all elements of this sequence accept attributes compatible |
| with the elements held by this container.] |
| |
| The generate function returns `true` or `false` depending on the result of the |
| output generation. As outlined in different places of this documentation, a |
| generator may fail for different reasons. One of the possible reasons is an |
| error in the underlying output iterator (memory exhausted or disk full, etc.). |
| Another reason might be that the data doesn't match the requirements of a |
| particular generator. |
| |
| [note `char` and `wchar_t` operands |
| |
| The careful reader may notice that the generator expression has `','` instead |
| of `lit(',')` as the previous examples did. This is ok due to C++ syntax |
| rules of conversion. Spirit provides `<<` operators that are overloaded to |
| accept a `char` or `wchar_t` argument on its left or right (but not both). |
| An operator may be overloaded if at least one of its parameters is a |
| user-defined type. In this case, the `double_` is the 2nd argument to |
| `operator<<`, and so the proper overload of `<<` is used, converting `','` |
| into a character literal generator. |
| |
| The problem with omitting the `lit` should be obvious: `'a' << 'b'` is not a |
| spirit generator, it is a numeric expression, left-shifting the ASCII (or |
| another encoding) value of `'a'` by the ASCII value of `'b'`. However, both |
| `lit('a') << 'b'` and `'a' << lit('b')` are Spirit sequence generators |
| for the letter `'a'` followed by `'b'`. You'll get used to it, sooner or |
| later. |
| ] |
| |
| Note that we inlined the generator directly in the call to `generate_delimited`. |
| Upon calling this function, the expression evaluates into a temporary, |
| unnamed generator which is passed into the `generate_delimited` function, |
| used, and then destroyed. |
| |
| Here, we chose to make the generate function generic by making it a template, |
| parameterized by the output iterator type. By doing so, it can put the generated |
| data into any STL conforming output iterator. |
| |
| [endsect] [/ Warming up] |