123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- [/==============================================================================
- 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]
|