• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2001-2010 Joel de Guzman
3     Copyright (c) 2001-2012 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/home/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 ///////////////////////////////////////////////////////////////////////////////
110 struct binary_op
111 {
binary_opbinary_op112     binary_op() {}
113 
binary_opbinary_op114     binary_op(
115         char op
116       , expression_ast const& left
117       , expression_ast const& right)
118       : op(op), left(left), right(right) {}
119 
120     char op;
121     expression_ast left;
122     expression_ast right;
123 };
124 
125 struct unary_op
126 {
unary_opunary_op127     unary_op(
128         char op
129       , expression_ast const& right)
130     : op(op), right(right) {}
131 
132     char op;
133     expression_ast right;
134 };
135 
operator +=(expression_ast const & rhs)136 inline expression_ast& expression_ast::operator+=(expression_ast const& rhs)
137 {
138     expr = binary_op('+', expr, rhs);
139     return *this;
140 }
141 
operator -=(expression_ast const & rhs)142 inline expression_ast& expression_ast::operator-=(expression_ast const& rhs)
143 {
144     expr = binary_op('-', expr, rhs);
145     return *this;
146 }
147 
operator *=(expression_ast const & rhs)148 inline expression_ast& expression_ast::operator*=(expression_ast const& rhs)
149 {
150     expr = binary_op('*', expr, rhs);
151     return *this;
152 }
153 
operator /=(expression_ast const & rhs)154 inline expression_ast& expression_ast::operator/=(expression_ast const& rhs)
155 {
156     expr = binary_op('/', expr, rhs);
157     return *this;
158 }
159 
160 // We should be using expression_ast::operator-. There's a bug
161 // in phoenix type deduction mechanism that prevents us from
162 // doing so. Phoenix will be switching to BOOST_TYPEOF. In the
163 // meantime, we will use a phoenix::function below:
164 template <char Op>
165 struct unary_expr
166 {
167     template <typename T>
168     struct result { typedef T type; };
169 
operator ()unary_expr170     expression_ast operator()(expression_ast const& expr) const
171     {
172         return unary_op(Op, expr);
173     }
174 };
175 
176 boost::phoenix::function<unary_expr<'+'> > pos;
177 boost::phoenix::function<unary_expr<'-'> > neg;
178 
179 #endif
180