![]() |
Home | Libraries | People | FAQ | More |
The example in the previous section was very simplistic. It only recognized data, but did nothing with it. It answered the question: "Did the input match?". Now, we want to extract information from what was parsed. For example, we would want to store the parsed number after a successful match. To do this, you will need semantic actions.
Semantic actions may be attached to any point in the grammar specification.
These actions are polymorphic function objects that are called whenever a
part of the parser successfully recognizes a portion of the input. Say you
have a parser p
, and a polymorphic
C++ function object f
. You
can make the parser call f
whenever it matches an input by attaching f
:
p[f]
The expression above links f
to the parser, p
. f
is expected to be a polymorphic function
object with the signature:
template <typename Context> void operator()(Context const& ctx) const;
We can also use C++14 generic lambdas of the form:
[](auto& ctx) { /*...*/ }
From the context, we can extract relevant information:
Table 2. Parse Context Access Functions
Function |
Description |
Example |
---|---|---|
|
A reference to the attribute of the innermost rule that directly
or indirectly invokes the parser |
|
|
Iterator range to the input stream |
|
|
A reference to the attribute of the parser |
|
|
A reference to a |
|
Given:
struct print_action { template <typename Context> void operator()(Context const& ctx) const { std::cout << _attr(ctx) << std::endl; } };
Take note that with function objects, we need to have an operator()
with the Context argument. If we don't
care about the context, we can use unused_type
.
We'll see more of unused_type
elsewhere. unused_type
is
a Spirit supplied support class.
All examples parse inputs of the form:
"{NNN}"
Where NNN is an integer inside the curly braces (e.g. {44}).
The first example shows how to attach a function object:
parse(first, last, '{' >> int_[print_action()] >> '}');
What's new? Well int_
is
the sibling of double_
. I'm
sure you can guess what this parser does.
The next example shows how use C++14 lambda:
auto f = [](auto& ctx){ std::cout << _attr(ctx) << std::endl; }; parse(first, last, '{' >> int_[f] >> '}');
Attaching semantic actions is the first hurdle one has to tackle when getting started with parsing with Spirit. Familiarize yourself with this task.
The examples above can be found here: actions.cpp