1 /*=============================================================================
2     Copyright (c) 2001-2010 Joel de Guzman
3     Copyright (c) 2001-2010 Hartmut Kaiser
4 
5     Distributed under the Boost Software License, Version 1.0. (See accompanying
6     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 =============================================================================*/
8 ///////////////////////////////////////////////////////////////////////////////
9 //
10 //  A Calculator example demonstrating generation of AST which gets dumped into
11 //  a human readable format afterwards.
12 //
13 //  [ JDG April 28, 2008 ]
14 //  [ HK April 28, 2008 ]
15 //
16 ///////////////////////////////////////////////////////////////////////////////
17 
18 #if !defined(SPIRIT_EXAMPLE_CALC2_AST_APR_30_2008_1011AM)
19 #define SPIRIT_EXAMPLE_CALC2_AST_APR_30_2008_1011AM
20 
21 #include <boost/variant.hpp>
22 #include <boost/spirit/include/phoenix_operator.hpp>
23 #include <boost/spirit/include/phoenix_function.hpp>
24 #include <boost/spirit/include/phoenix_statement.hpp>
25 #include <boost/spirit/include/karma_domain.hpp>
26 #include <boost/spirit/include/support_attributes_fwd.hpp>
27 
28 ///////////////////////////////////////////////////////////////////////////////
29 //  Our AST
30 ///////////////////////////////////////////////////////////////////////////////
31 struct binary_op;
32 struct unary_op;
33 struct nil {};
34 
35 struct expression_ast
36 {
37     typedef
38         boost::variant<
39             nil // can't happen!
40           , int
41           , boost::recursive_wrapper<binary_op>
42           , boost::recursive_wrapper<unary_op>
43         >
44     type;
45 
46     // expose variant types
47     typedef type::types types;
48 
49     // expose variant functionality
whichexpression_ast50     int which() const { return expr.which(); }
51 
52     // constructors
expression_astexpression_ast53     expression_ast()
54       : expr(nil()) {}
55 
expression_astexpression_ast56     expression_ast(unary_op const& expr)
57       : expr(expr) {}
58 
expression_astexpression_ast59     expression_ast(binary_op const& expr)
60       : expr(expr) {}
61 
expression_astexpression_ast62     expression_ast(unsigned int expr)
63       : expr(expr) {}
64 
expression_astexpression_ast65     expression_ast(type const& expr)
66       : expr(expr) {}
67 
68     expression_ast& operator+=(expression_ast const& rhs);
69     expression_ast& operator-=(expression_ast const& rhs);
70     expression_ast& operator*=(expression_ast const& rhs);
71     expression_ast& operator/=(expression_ast const& rhs);
72 
73     type expr;
74 };
75 
76 // expose variant functionality
77 namespace boost
78 {
79     // this function has to live in namespace boost for ADL to correctly find it
80     template <typename T>
get(expression_ast const & expr)81     inline T get(expression_ast const& expr)
82     {
83         return boost::get<T>(expr.expr);
84     }
85 
86     // the specialization below tells Spirit to handle expression_ast as if it
87     // where a 'real' variant
88     namespace spirit { namespace traits
89     {
90         // the specialization below tells Spirit to handle expression_ast as
91         // if it where a 'real' variant (if used with Spirit.Karma)
92         template <>
93         struct not_is_variant<expression_ast, karma::domain>
94           : mpl::false_ {};
95 
96         // the specialization of variant_which allows to generically extract
97         // the current type stored in the given variant like type
98         template <>
99         struct variant_which<expression_ast>
100         {
callboost::spirit::traits::variant_which101             static int call(expression_ast const& v)
102             {
103                 return v.which();
104             }
105         };
106     }}
107 }
108 
109 enum byte_code
110 {
111     op_neg = 1,     //  negate the top stack entry
112     op_pos,         //  essentially a no-op (unary plus)
113     op_add,         //  add top two stack entries
114     op_sub,         //  subtract top two stack entries
115     op_mul,         //  multiply top two stack entries
116     op_div,         //  divide top two stack entries
117     op_int,         //  push constant integer into the stack
118 };
119 
120 ///////////////////////////////////////////////////////////////////////////////
121 struct binary_op
122 {
binary_opbinary_op123     binary_op() {}
124 
binary_opbinary_op125     binary_op(
126         int op
127       , expression_ast const& left
128       , expression_ast const& right)
129       : op(op), left(left), right(right) {}
130 
131     int op;
132     expression_ast left;
133     expression_ast right;
134 };
135 
136 struct unary_op
137 {
unary_opunary_op138     unary_op(
139         int op
140       , expression_ast const& right)
141     : op(op), right(right) {}
142 
143     int op;
144     expression_ast right;
145 };
146 
operator +=(expression_ast const & rhs)147 inline expression_ast& expression_ast::operator+=(expression_ast const& rhs)
148 {
149     expr = binary_op(op_add, expr, rhs);
150     return *this;
151 }
152 
operator -=(expression_ast const & rhs)153 inline expression_ast& expression_ast::operator-=(expression_ast const& rhs)
154 {
155     expr = binary_op(op_sub, expr, rhs);
156     return *this;
157 }
158 
operator *=(expression_ast const & rhs)159 inline expression_ast& expression_ast::operator*=(expression_ast const& rhs)
160 {
161     expr = binary_op(op_mul, expr, rhs);
162     return *this;
163 }
164 
operator /=(expression_ast const & rhs)165 inline expression_ast& expression_ast::operator/=(expression_ast const& rhs)
166 {
167     expr = binary_op(op_div, expr, rhs);
168     return *this;
169 }
170 
171 // We should be using expression_ast::operator-. There's a bug
172 // in phoenix type deduction mechanism that prevents us from
173 // doing so. Phoenix will be switching to BOOST_TYPEOF. In the
174 // meantime, we will use a phoenix::function below:
175 template <char Op>
176 struct unary_expr
177 {
178     template <typename T>
179     struct result { typedef T type; };
180 
operator ()unary_expr181     expression_ast operator()(expression_ast const& expr) const
182     {
183         return unary_op(Op, expr);
184     }
185 };
186 
187 boost::phoenix::function<unary_expr<op_pos> > pos;
188 boost::phoenix::function<unary_expr<op_neg> > neg;
189 
190 #endif
191