Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Parser Semantic Actions

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

_val

A reference to the attribute of the innermost rule that directly or indirectly invokes the parser p

_val(ctx) = "Gotya!"

_where

Iterator range to the input stream

_where(ctx).begin()

_attr

A reference to the attribute of the parser p

_val(ctx) += _attr(ctx)

_pass

A reference to a bool flag that can be used to force the p to fail

_pass(ctx) = false


Examples of Semantic Actions

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


PrevUpHomeNext