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/phoenix/operator.hpp>
23#include <boost/phoenix/function.hpp>
24#include <boost/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///////////////////////////////////////////////////////////////////////////////
31struct binary_op;
32struct unary_op;
33struct nil {};
34
35struct 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
50 int which() const { return expr.which(); }
51
52 // constructors
53 expression_ast()
54 : expr(nil()) {}
55
56 expression_ast(unary_op const& expr)
57 : expr(expr) {}
58
59 expression_ast(binary_op const& expr)
60 : expr(expr) {}
61
62 expression_ast(unsigned int expr)
63 : expr(expr) {}
64
65 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
77namespace boost
78{
79 // this function has to live in namespace boost for ADL to correctly find it
80 template <typename T>
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 {
99 static int call(expression_ast const& v)
100 {
101 return v.which();
102 }
103 };
104 }}
105}
106
107///////////////////////////////////////////////////////////////////////////////
108struct binary_op
109{
110 binary_op() {}
111
112 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
123struct unary_op
124{
125 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
134inline expression_ast& expression_ast::operator+=(expression_ast const& rhs)
135{
136 expr = binary_op('+', expr, rhs);
137 return *this;
138}
139
140inline expression_ast& expression_ast::operator-=(expression_ast const& rhs)
141{
142 expr = binary_op('-', expr, rhs);
143 return *this;
144}
145
146inline expression_ast& expression_ast::operator*=(expression_ast const& rhs)
147{
148 expr = binary_op('*', expr, rhs);
149 return *this;
150}
151
152inline 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:
162template <char Op>
163struct unary_expr
164{
165 template <typename T>
166 struct result { typedef T type; };
167
168 expression_ast operator()(expression_ast const& expr) const
169 {
170 return unary_op(Op, expr);
171 }
172};
173
174boost::phoenix::function<unary_expr<'+'> > pos;
175boost::phoenix::function<unary_expr<'-'> > neg;
176
177#endif
178

source code of boost/libs/spirit/example/karma/calc2_ast.hpp