Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

libs/spirit/doc/x3/tutorial/actions.qbk

[/==============================================================================
    Copyright (C) 2001-2015 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:semantic_actions 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 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`]]
]

[heading 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: [@../../../example/x3/actions.cpp actions.cpp]

[endsect]