]>
Commit | Line | Data |
---|---|---|
1 | [/============================================================================== | |
2 | Copyright (C) 2001-2010 Joel de Guzman | |
3 | Copyright (C) 2001-2005 Dan Marsden | |
4 | Copyright (C) 2001-2010 Thomas Heller | |
5 | ||
6 | Distributed under the Boost Software License, Version 1.0. (See accompanying | |
7 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
8 | ===============================================================================/] | |
9 | ||
10 | [section Transforming the Expression Tree] | |
11 | ||
12 | This example will show how to write __phoenix_actions__ that transform the | |
13 | Phoenix AST. | |
14 | ||
15 | [: | |
16 | "/Lisp macros transform the program structure itself, with the full language | |
17 | available to express such transformations./" | |
18 | ||
19 | [@http://en.wikipedia.org/wiki/Lisp_macro#Lisp_macros Wikipedia] | |
20 | ] | |
21 | ||
22 | What we want to do is to invert some arithmetic operators, i.e. plus will be | |
23 | transformed to minus, minus to plus, multiplication to division and division to | |
24 | multiplication. | |
25 | ||
26 | Let's start with defining our default action: | |
27 | ||
28 | struct invert_actions | |
29 | { | |
30 | template <typename Rule> | |
31 | struct when | |
32 | : proto::_ // the default is proto::_ | |
33 | {}; | |
34 | }; | |
35 | ||
36 | By default, we don't want to do anything, well, not exactly nothing, but just | |
37 | return the expression. This is done by | |
38 | [@http://www.boost.org/doc/libs/release/doc/html/boost/proto/_.html proto::_] | |
39 | which, used as a transform, just passes the current expression along. Making this | |
40 | action an identity transform. | |
41 | ||
42 | [def __proto_make_expr__ [@http://www.boost.org/doc/libs/release/doc/html/boost/proto/functional/make_expr.html `proto::functional::make_expr`]] | |
43 | ||
44 | So, after the basics are set up, we can start by writing the transformations we | |
45 | want to have on our tree: | |
46 | ||
47 | // Transform plus to minus | |
48 | template <> | |
49 | struct invert_actions::when<phoenix::rule::plus> | |
50 | : __proto_call__< | |
51 | __proto_make_expr__<proto::tag::minus>( | |
52 | phoenix::evaluator(proto::_left, phoenix::_context) | |
53 | , phoenix::evaluator(proto::_right, phoenix::_context) | |
54 | ) | |
55 | > | |
56 | {}; | |
57 | ||
58 | Wow, this looks complicated! Granted you need to know a little bit about __proto__ | |
59 | (For a good introduction read through the | |
60 | [@http://cpp-next.com/archive/2010/08/expressive-c-introduction/ Expressive C++] series). | |
61 | ||
62 | What is done is the following: | |
63 | ||
64 | * The left expression is passed to evaluator (with the current context, that contains our invert_actions) | |
65 | * The right expression is passed to evaluator (with the current context, that contains our invert_actions) | |
66 | * The result of these two __proto_transforms__ is passed to __proto_make_expr__ which returns the freshly created expression | |
67 | ||
68 | After you know what is going on, maybe the rest doesn't look so scary anymore: | |
69 | ||
70 | // Transform minus to plus | |
71 | template <> | |
72 | struct invert_actions::when<phoenix::rule::minus> | |
73 | : __proto_call__< | |
74 | __proto_make_expr__<proto::tag::plus>( | |
75 | phoenix::evaluator(proto::_left, phoenix::_context) | |
76 | , phoenix::evaluator(proto::_right, phoenix::_context) | |
77 | ) | |
78 | > | |
79 | {}; | |
80 | ||
81 | // Transform multiplies to divides | |
82 | template <> | |
83 | struct invert_actions::when<phoenix::rule::multiplies> | |
84 | : __proto_call__< | |
85 | __proto_make_expr__<proto::tag::divides>( | |
86 | phoenix::evaluator(proto::_left, phoenix::_context) | |
87 | , phoenix::evaluator(proto::_right, phoenix::_context) | |
88 | ) | |
89 | > | |
90 | {}; | |
91 | ||
92 | // Transform divides to multiplies | |
93 | template <> | |
94 | struct invert_actions::when<phoenix::rule::divides> | |
95 | : __proto_call__< | |
96 | __proto_make_expr__<proto::tag::multiplies>( | |
97 | phoenix::evaluator(proto::_left, phoenix::_context) | |
98 | , phoenix::evaluator(proto::_right, phoenix::_context) | |
99 | ) | |
100 | > | |
101 | {}; | |
102 | ||
103 | That's it! Now that we have our actions defined, we want to evaluate some of our expressions with them: | |
104 | ||
105 | template <typename Expr> | |
106 | // Calculate the result type: our transformed AST | |
107 | typename boost::result_of< | |
108 | phoenix::evaluator( | |
109 | Expr const& | |
110 | , phoenix::result_of::context<int, invert_actions>::type | |
111 | ) | |
112 | >::type | |
113 | invert(Expr const & expr) | |
114 | { | |
115 | return | |
116 | // Evaluate it with our actions | |
117 | phoenix::eval( | |
118 | expr | |
119 | , phoenix::context( | |
120 | int() | |
121 | , invert_actions() | |
122 | ) | |
123 | ); | |
124 | } | |
125 | ||
126 | Run some tests to see if it is working: | |
127 | ||
128 | invert(_1); // --> _1 | |
129 | invert(_1 + _2); // --> _1 - _2 | |
130 | invert(_1 + _2 - _3); // --> _1 - _2 + _3 | |
131 | invert(_1 * _2); // --> _1 / _2 | |
132 | invert(_1 * _2 / _3); // --> _1 / _2 * _3 | |
133 | invert(_1 * _2 + _3); // --> _1 / _2 - _3 | |
134 | invert(_1 * _2 - _3); // --> _1 / _2 + _2 | |
135 | invert(if_(_1 * _4)[_2 - _3]); // --> if_(_1 / _4)[_2 + _3] | |
136 | _1 * invert(_2 - _3)); // --> _1 * _2 + _3 | |
137 | ||
138 | __note__ The complete example can be found here: [@../../example/invert.cpp example/invert.cpp] | |
139 | ||
140 | /Pretty simple .../ | |
141 | ||
142 | [endsect] |