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