• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     namespace spirit { namespace traits
87     {
88         // the specialization below tells Spirit to handle expression_ast as
89         // if it where a 'real' variant (if used with Spirit.Karma)
90         template <>
91         struct not_is_variant<expression_ast, karma::domain>
92           : mpl::false_ {};
93 
94         // the specialization of variant_which allows to generically extract
95         // the current type stored in the given variant like type
96         template <>
97         struct variant_which<expression_ast>
98         {
callboost::spirit::traits::variant_which99             static int call(expression_ast const& v)
100             {
101                 return v.which();
102             }
103         };
104     }}
105 }
106 
107 ///////////////////////////////////////////////////////////////////////////////
108 struct binary_op
109 {
binary_opbinary_op110     binary_op() {}
111 
binary_opbinary_op112     binary_op(
113         char op
114       , expression_ast const& left
115       , expression_ast const& right)
116       : op(op), left(left), right(right) {}
117 
118     char op;
119     expression_ast left;
120     expression_ast right;
121 };
122 
123 struct unary_op
124 {
unary_opunary_op125     unary_op(
126         char op
127       , expression_ast const& right)
128     : op(op), right(right) {}
129 
130     char op;
131     expression_ast right;
132 };
133 
operator +=(expression_ast const & rhs)134 inline expression_ast& expression_ast::operator+=(expression_ast const& rhs)
135 {
136     expr = binary_op('+', expr, rhs);
137     return *this;
138 }
139 
operator -=(expression_ast const & rhs)140 inline expression_ast& expression_ast::operator-=(expression_ast const& rhs)
141 {
142     expr = binary_op('-', expr, rhs);
143     return *this;
144 }
145 
operator *=(expression_ast const & rhs)146 inline expression_ast& expression_ast::operator*=(expression_ast const& rhs)
147 {
148     expr = binary_op('*', expr, rhs);
149     return *this;
150 }
151 
operator /=(expression_ast const & rhs)152 inline expression_ast& expression_ast::operator/=(expression_ast const& rhs)
153 {
154     expr = binary_op('/', expr, rhs);
155     return *this;
156 }
157 
158 // We should be using expression_ast::operator-. There's a bug
159 // in phoenix type deduction mechanism that prevents us from
160 // doing so. Phoenix will be switching to BOOST_TYPEOF. In the
161 // meantime, we will use a phoenix::function below:
162 template <char Op>
163 struct unary_expr
164 {
165     template <typename T>
166     struct result { typedef T type; };
167 
operator ()unary_expr168     expression_ast operator()(expression_ast const& expr) const
169     {
170         return unary_op(Op, expr);
171     }
172 };
173 
174 boost::phoenix::function<unary_expr<'+'> > pos;
175 boost::phoenix::function<unary_expr<'-'> > neg;
176 
177 #endif
178