83a792d7ed
[SVN r67619]
177 lines
8.4 KiB
Plaintext
177 lines
8.4 KiB
Plaintext
[/==============================================================================
|
|
Copyright (C) 2001-2011 Joel de Guzman
|
|
Copyright (C) 2001-2011 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]
|