]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/example/x3/calc/calc4b.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / spirit / example / x3 / calc / calc4b.cpp
1 /*=============================================================================
2 Copyright (c) 2001-2014 Joel de Guzman
3
4 Distributed under the Boost Software License, Version 1.0. (See accompanying
5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 =============================================================================*/
7 ///////////////////////////////////////////////////////////////////////////////
8 //
9 // A Calculator example demonstrating generation of AST. The AST,
10 // once created, is traversed, 1) To print its contents and
11 // 2) To evaluate the result.
12 //
13 // [ JDG April 28, 2008 ] For BoostCon 2008
14 // [ JDG February 18, 2011 ] Pure attributes. No semantic actions.
15 // [ JDG January 9, 2013 ] Spirit X3
16 //
17 ///////////////////////////////////////////////////////////////////////////////
18
19 #if defined(_MSC_VER)
20 # pragma warning(disable: 4345)
21 #endif
22
23 #include <boost/config/warning_disable.hpp>
24 #include <boost/spirit/home/x3.hpp>
25 #include <boost/spirit/home/x3/support/ast/variant.hpp>
26 #include <boost/fusion/include/adapt_struct.hpp>
27
28 #include <iostream>
29 #include <string>
30 #include <list>
31 #include <numeric>
32
33 namespace x3 = boost::spirit::x3;
34
35 namespace client { namespace ast
36 {
37 ///////////////////////////////////////////////////////////////////////////
38 // The AST
39 ///////////////////////////////////////////////////////////////////////////
40 struct nil {};
41 struct signed_;
42 struct program;
43
44 struct operand : x3::variant<
45 nil
46 , unsigned int
47 , x3::forward_ast<signed_>
48 , x3::forward_ast<program>
49 >
50 {
51 using base_type::base_type;
52 using base_type::operator=;
53 };
54
55 struct signed_
56 {
57 char sign;
58 operand operand_;
59 };
60
61 struct operation
62 {
63 char operator_;
64 operand operand_;
65 };
66
67 struct program
68 {
69 operand first;
70 std::list<operation> rest;
71 };
72 }}
73
74 BOOST_FUSION_ADAPT_STRUCT(client::ast::signed_,
75 sign, operand_
76 )
77
78 BOOST_FUSION_ADAPT_STRUCT(client::ast::operation,
79 operator_, operand_
80 )
81
82 BOOST_FUSION_ADAPT_STRUCT(client::ast::program,
83 first, rest
84 )
85
86 namespace client { namespace ast
87 {
88 ///////////////////////////////////////////////////////////////////////////
89 // The AST Printer
90 ///////////////////////////////////////////////////////////////////////////
91 struct printer
92 {
93 typedef void result_type;
94
95 void operator()(nil) const {}
96 void operator()(unsigned int n) const { std::cout << n; }
97
98 void operator()(operation const& x) const
99 {
100 boost::apply_visitor(*this, x.operand_);
101 switch (x.operator_)
102 {
103 case '+': std::cout << " add"; break;
104 case '-': std::cout << " subt"; break;
105 case '*': std::cout << " mult"; break;
106 case '/': std::cout << " div"; break;
107 }
108 }
109
110 void operator()(signed_ const& x) const
111 {
112 boost::apply_visitor(*this, x.operand_);
113 switch (x.sign)
114 {
115 case '-': std::cout << " neg"; break;
116 case '+': std::cout << " pos"; break;
117 }
118 }
119
120 void operator()(program const& x) const
121 {
122 boost::apply_visitor(*this, x.first);
123 for (operation const& oper: x.rest)
124 {
125 std::cout << ' ';
126 (*this)(oper);
127 }
128 }
129 };
130
131 ///////////////////////////////////////////////////////////////////////////
132 // The AST evaluator
133 ///////////////////////////////////////////////////////////////////////////
134 struct eval
135 {
136 typedef int result_type;
137
138 int operator()(nil) const { BOOST_ASSERT(0); return 0; }
139 int operator()(unsigned int n) const { return n; }
140
141 int operator()(int lhs, operation const& x) const
142 {
143 int rhs = boost::apply_visitor(*this, x.operand_);
144 switch (x.operator_)
145 {
146 case '+': return lhs + rhs;
147 case '-': return lhs - rhs;
148 case '*': return lhs * rhs;
149 case '/': return lhs / rhs;
150 }
151 BOOST_ASSERT(0);
152 return 0;
153 }
154
155 int operator()(signed_ const& x) const
156 {
157 int rhs = boost::apply_visitor(*this, x.operand_);
158 switch (x.sign)
159 {
160 case '-': return -rhs;
161 case '+': return +rhs;
162 }
163 BOOST_ASSERT(0);
164 return 0;
165 }
166
167 int operator()(program const& x) const
168 {
169 return std::accumulate(
170 x.rest.begin(), x.rest.end()
171 , boost::apply_visitor(*this, x.first)
172 , *this);
173 }
174 };
175 }}
176
177 namespace client
178 {
179 ///////////////////////////////////////////////////////////////////////////////
180 // The calculator grammar
181 ///////////////////////////////////////////////////////////////////////////////
182 namespace calculator_grammar
183 {
184 using x3::uint_;
185 using x3::char_;
186
187 x3::rule<class expression, ast::program> const expression("expression");
188 x3::rule<class term, ast::program> const term("term");
189 x3::rule<class factor, ast::operand> const factor("factor");
190
191 auto const expression_def =
192 term
193 >> *( (char_('+') >> term)
194 | (char_('-') >> term)
195 )
196 ;
197
198 auto const term_def =
199 factor
200 >> *( (char_('*') >> factor)
201 | (char_('/') >> factor)
202 )
203 ;
204
205 auto const factor_def =
206 uint_
207 | '(' >> expression >> ')'
208 | (char_('-') >> factor)
209 | (char_('+') >> factor)
210 ;
211
212 BOOST_SPIRIT_DEFINE(expression, term, factor);
213
214 auto calculator = expression;
215 }
216
217 using calculator_grammar::calculator;
218
219 }
220
221 ///////////////////////////////////////////////////////////////////////////////
222 // Main program
223 ///////////////////////////////////////////////////////////////////////////////
224 int
225 main()
226 {
227 std::cout << "/////////////////////////////////////////////////////////\n\n";
228 std::cout << "Expression parser...\n\n";
229 std::cout << "/////////////////////////////////////////////////////////\n\n";
230 std::cout << "Type an expression...or [q or Q] to quit\n\n";
231
232 typedef std::string::const_iterator iterator_type;
233 typedef client::ast::program ast_program;
234 typedef client::ast::printer ast_print;
235 typedef client::ast::eval ast_eval;
236
237 std::string str;
238 while (std::getline(std::cin, str))
239 {
240 if (str.empty() || str[0] == 'q' || str[0] == 'Q')
241 break;
242
243 auto& calc = client::calculator; // Our grammar
244 ast_program program; // Our program (AST)
245 ast_print print; // Prints the program
246 ast_eval eval; // Evaluates the program
247
248 iterator_type iter = str.begin();
249 iterator_type end = str.end();
250 boost::spirit::x3::ascii::space_type space;
251 bool r = phrase_parse(iter, end, calc, space, program);
252
253 if (r && iter == end)
254 {
255 std::cout << "-------------------------\n";
256 std::cout << "Parsing succeeded\n";
257 print(program);
258 std::cout << "\nResult: " << eval(program) << std::endl;
259 std::cout << "-------------------------\n";
260 }
261 else
262 {
263 std::string rest(iter, end);
264 std::cout << "-------------------------\n";
265 std::cout << "Parsing failed\n";
266 std::cout << "stopped at: \"" << rest << "\"\n";
267 std::cout << "-------------------------\n";
268 }
269 }
270
271 std::cout << "Bye... :-) \n\n";
272 return 0;
273 }