| [/============================================================================== |
| Copyright (C) 2001-2010 Joel de Guzman |
| Copyright (C) 2001-2005 Dan Marsden |
| Copyright (C) 2001-2010 Thomas Heller |
| |
| 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 Transforming the Expression Tree] |
| |
| This example will show how to write __phoenix_actions__ that transform the |
| Phoenix AST. |
| |
| [: |
| "/Lisp macros transform the program structure itself, with the full language |
| available to express such transformations./" |
| |
| [@http://en.wikipedia.org/wiki/Lisp_macro#Lisp_macros Wikipedia] |
| ] |
| |
| What we want to do is to invert some arithmetic operators, i.e. plus will be |
| transformed to minus, minus to plus, multiplication to division and division to |
| multiplication. |
| |
| Let's start with defining our default action: |
| |
| [def __proto_nary_expr__ [@http://www.boost.org/doc/libs/release/doc/html/boost/proto/nary_expr.html `proto::nary_expr`]] |
| [def __proto_vararg__ [@http://www.boost.org/doc/libs/release/doc/html/boost/proto/vararg.html `proto::vararg`]] |
| [def __proto_when__ [@http://www.boost.org/doc/libs/release/doc/html/boost/proto/when.html `proto::when`]] |
| [def __proto_underscore__ [@http://www.boost.org/doc/libs/release/doc/html/boost/proto/_.html `proto::_`]] |
| [def __proto_make_expr__ [@http://www.boost.org/doc/libs/release/doc/html/boost/proto/functional/make_expr.html `proto::functional::make_expr`]] |
| |
| struct invert_actions |
| { |
| template <typename Rule> |
| struct when |
| : __proto_nary_expr__ |
| __proto_underscore__ |
| , __proto_vararg__ |
| __proto_when__<__proto_underscore__, phoenix::evaluator(__proto_underscore__, phoenix::_context) |
| > |
| > |
| {}; |
| }; |
| |
| Wow, this looks complicated! Granted you need to know a little bit about __proto__ |
| (For a good introduction read through the |
| [@http://cpp-next.com/archive/2010/08/expressive-c-introduction/ Expressive C++] series). |
| |
| By default, we don't want to do anything, well, not exactly nothing, but just |
| continue transformation into its arguments. |
| |
| So, it is done by the following: |
| |
| * For each arguments are passed to evaluator (with the current context, that contains our invert_actions) |
| * Create new expression using current expression tag, what is done by __proto_underscore__, with the result of evaluated arguments |
| |
| So, after the basics are set up, we can start by writing the transformations we |
| want to have on our tree: |
| |
| // Transform plus to minus |
| template <> |
| struct invert_actions::when<phoenix::rule::plus> |
| : __proto_call__< |
| __proto_make_expr__<proto::tag::minus>( |
| phoenix::evaluator(proto::_left, phoenix::_context) |
| , phoenix::evaluator(proto::_right, phoenix::_context) |
| ) |
| > |
| {}; |
| |
| What is done is the following: |
| |
| * The left expression is passed to evaluator (with the current context, that contains our invert_actions) |
| * The right expression is passed to evaluator (with the current context, that contains our invert_actions) |
| * The result of these two __proto_transforms__ are passed to __proto_make_expr__ which returns the freshly created expression |
| |
| After you know what is going on, maybe the rest doesn't look so scary anymore: |
| |
| // Transform minus to plus |
| template <> |
| struct invert_actions::when<phoenix::rule::minus> |
| : __proto_call__< |
| __proto_make_expr__<proto::tag::plus>( |
| phoenix::evaluator(proto::_left, phoenix::_context) |
| , phoenix::evaluator(proto::_right, phoenix::_context) |
| ) |
| > |
| {}; |
| |
| // Transform multiplies to divides |
| template <> |
| struct invert_actions::when<phoenix::rule::multiplies> |
| : __proto_call__< |
| __proto_make_expr__<proto::tag::divides>( |
| phoenix::evaluator(proto::_left, phoenix::_context) |
| , phoenix::evaluator(proto::_right, phoenix::_context) |
| ) |
| > |
| {}; |
| |
| // Transform divides to multiplies |
| template <> |
| struct invert_actions::when<phoenix::rule::divides> |
| : __proto_call__< |
| __proto_make_expr__<proto::tag::multiplies>( |
| phoenix::evaluator(proto::_left, phoenix::_context) |
| , phoenix::evaluator(proto::_right, phoenix::_context) |
| ) |
| > |
| {}; |
| |
| That's it! Now that we have our actions defined, we want to evaluate some of our expressions with them: |
| |
| template <typename Expr> |
| // Calculate the result type: our transformed AST |
| typename boost::result_of< |
| phoenix::evaluator( |
| Expr const& |
| , phoenix::result_of::context<int, invert_actions>::type |
| ) |
| >::type |
| invert(Expr const & expr) |
| { |
| return |
| // Evaluate it with our actions |
| phoenix::eval( |
| expr |
| , phoenix::context( |
| int() |
| , invert_actions() |
| ) |
| ); |
| } |
| |
| Run some tests to see if it is working: |
| |
| invert(_1); // --> _1 |
| invert(_1 + _2); // --> _1 - _2 |
| invert(_1 + _2 - _3); // --> _1 - _2 + _3 |
| invert(_1 * _2); // --> _1 / _2 |
| invert(_1 * _2 / _3); // --> _1 / _2 * _3 |
| invert(_1 * _2 + _3); // --> _1 / _2 - _3 |
| invert(_1 * _2 - _3); // --> _1 / _2 + _2 |
| invert(if_(_1 * _4)[_2 - _3]); // --> if_(_1 / _4)[_2 + _3] |
| _1 * invert(_2 - _3)); // --> _1 * _2 + _3 |
| |
| __note__ The complete example can be found here: [@../../example/invert.cpp example/invert.cpp] |
| |
| /Pretty simple .../ |
| |
| [endsect] |