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

PrevUpHomeNext

Phoenix Expressions

Boilerplate Macros

A Phoenix Expression is a model of the Proto Expression Concept. These expressions are wrapped inside an Actor template. The actor provides the function call operator which evaluates the expressions. The actor is the domain specific wrapper around Phoenix expressions.

By design, Phoenix Expressions do not carry any information on how they will be evaluated later on. They are the data structure on which the Actions will work.

The library provides a convenience template to define expressions:

template <template <typename> Actor, typename Tag, typename A0, ..., typename A1>
struct expr_ext
    : proto::transform<expr_ext<Actor, Tag, A0, ..., A1> >
{
    typedef unspecified base_expr;
    typedef Actor<base_expr> type;

    typedef unspecified proto_grammar;

    static type make(A0 a0, ..., A1 a1);
};

template <typename Tag, typename A0, ..., typename A1>
struct expr : expr_ext<actor, Tag, A0, ..., A1> {};

Notation

A0...AN

Child node types

a0...aN

Child node objects

G0...GN

Boost.Proto grammar types

Expression Semantics

Expression

Semantics

expr<Tag, A0...AN>::type

The type of Expression having tag Tag and A0...AN children

expr<Tag, G0...GN>

A Boost.Proto grammar and Proto Pass Through Transform

expr<Tag, A0...AN>::make(a0...aN)

Returns a Phoenix Expression

[Note] Note

You might have noticed the template template argument Actor used in expr_ext. This can be a user supplied custom Actor adding other member functions or objects than the default actor template. See Extending Actors for more details.

meta_grammar

Defining expressions is only part of the game to make it a valid Phoenix Expression. In order to use the expressions in the Phoenix domain, we need to "register" them to our grammar.

The meta_grammar is a struct for exactly that purpose. It is an openly extendable Boost.Proto Grammar:

struct meta_grammar
    : proto::switch_<meta_grammar>
{
    template <typename Tag, typename Dummy>
    struct case_
        : proto::not_<proto::_>
    {};
};

As you can see, by default the meta_grammar matches nothing. With every Module you include this grammar gets extended by various expressions.

Example

Define an expression:

template <typename Lhs, typename Rhs>
struct plus
    : expr<proto::tag::plus, Lhs, Rhs>
{};

And add it to the grammar:

template <>
struct meta_grammar::case_<proto::tag::plus>
    : enable_rule<
        plus<
            meta_grammar
          , meta_grammar
        >
    >
{};

Define a generator function to make the life of our potential users easier:

template <typename Lhs, typename Rhs>
typename plus<Lhs, Rhs>::type
plus(Lhs const & lhs, Rhs const & rhs)
{
    return expression::plus<Lhs, Rhs>::make(lhs, rhs);
}

Look if it really works:

plus(6, 5)();

returns 11!

proto::display_expr(plus(5, 6));

prints:

plus(
    terminal(6)
  , terminal(5)
)

See define_expression.cpp for the full example.

[Note] Note

The example shown here only works because default_actions knows how to handle an expression having the proto::tag::plus and two children. This is because default_actions uses the proto::_default<meta_grammar> transform to evaluate operators and functions. Learn more about actions here.


PrevUpHomeNext