]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/compiler.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / spirit / example / qi / compiler_tutorial / calc8 / compiler.cpp
1 /*=============================================================================
2 Copyright (c) 2001-2011 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 #include "compiler.hpp"
8 #include "vm.hpp"
9 #include <boost/foreach.hpp>
10 #include <boost/variant/apply_visitor.hpp>
11 #include <boost/assert.hpp>
12 #include <boost/lexical_cast.hpp>
13 #include <set>
14
15 namespace client { namespace code_gen
16 {
17 void program::op(int a)
18 {
19 code.push_back(a);
20 }
21
22 void program::op(int a, int b)
23 {
24 code.push_back(a);
25 code.push_back(b);
26 }
27
28 void program::op(int a, int b, int c)
29 {
30 code.push_back(a);
31 code.push_back(b);
32 code.push_back(c);
33 }
34
35 int const* program::find_var(std::string const& name) const
36 {
37 std::map<std::string, int>::const_iterator i = variables.find(name);
38 if (i == variables.end())
39 return 0;
40 return &i->second;
41 }
42
43 void program::add_var(std::string const& name)
44 {
45 std::size_t n = variables.size();
46 variables[name] = n;
47 }
48
49 void program::print_variables(std::vector<int> const& stack) const
50 {
51 typedef std::pair<std::string, int> pair;
52 BOOST_FOREACH(pair const& p, variables)
53 {
54 std::cout << " " << p.first << ": " << stack[p.second] << std::endl;
55 }
56 }
57
58 void program::print_assembler() const
59 {
60 std::vector<int>::const_iterator pc = code.begin();
61
62 std::vector<std::string> locals(variables.size());
63 typedef std::pair<std::string, int> pair;
64 BOOST_FOREACH(pair const& p, variables)
65 {
66 locals[p.second] = p.first;
67 std::cout << " local "
68 << p.first << ", @" << p.second << std::endl;
69 }
70
71 std::map<std::size_t, std::string> lines;
72 std::set<std::size_t> jumps;
73
74 while (pc != code.end())
75 {
76 std::string line;
77 std::size_t address = pc - code.begin();
78
79 switch (*pc++)
80 {
81 case op_neg:
82 line += " op_neg";
83 break;
84
85 case op_not:
86 line += " op_not";
87 break;
88
89 case op_add:
90 line += " op_add";
91 break;
92
93 case op_sub:
94 line += " op_sub";
95 break;
96
97 case op_mul:
98 line += " op_mul";
99 break;
100
101 case op_div:
102 line += " op_div";
103 break;
104
105 case op_eq:
106 line += " op_eq";
107 break;
108
109 case op_neq:
110 line += " op_neq";
111 break;
112
113 case op_lt:
114 line += " op_lt";
115 break;
116
117 case op_lte:
118 line += " op_lte";
119 break;
120
121 case op_gt:
122 line += " op_gt";
123 break;
124
125 case op_gte:
126 line += " op_gte";
127 break;
128
129 case op_and:
130 line += " op_and";
131 break;
132
133 case op_or:
134 line += " op_or";
135 break;
136
137 case op_load:
138 line += " op_load ";
139 line += locals[*pc++];
140 break;
141
142 case op_store:
143 line += " op_store ";
144 line += locals[*pc++];
145 break;
146
147 case op_int:
148 line += " op_int ";
149 line += boost::lexical_cast<std::string>(*pc++);
150 break;
151
152 case op_true:
153 line += " op_true";
154 break;
155
156 case op_false:
157 line += " op_false";
158 break;
159
160 case op_jump:
161 {
162 line += " op_jump ";
163 std::size_t pos = (pc - code.begin()) + *pc++;
164 if (pos == code.size())
165 line += "end";
166 else
167 line += boost::lexical_cast<std::string>(pos);
168 jumps.insert(pos);
169 }
170 break;
171
172 case op_jump_if:
173 {
174 line += " op_jump_if ";
175 std::size_t pos = (pc - code.begin()) + *pc++;
176 if (pos == code.size())
177 line += "end";
178 else
179 line += boost::lexical_cast<std::string>(pos);
180 jumps.insert(pos);
181 }
182 break;
183
184 case op_stk_adj:
185 line += " op_stk_adj ";
186 line += boost::lexical_cast<std::string>(*pc++);
187 break;
188 }
189 lines[address] = line;
190 }
191
192 std::cout << "start:" << std::endl;
193 typedef std::pair<std::size_t, std::string> line_info;
194 BOOST_FOREACH(line_info const& l, lines)
195 {
196 std::size_t pos = l.first;
197 if (jumps.find(pos) != jumps.end())
198 std::cout << pos << ':' << std::endl;
199 std::cout << l.second << std::endl;
200 }
201
202 std::cout << "end:" << std::endl;
203 }
204
205 bool compiler::operator()(unsigned int x) const
206 {
207 program.op(op_int, x);
208 return true;
209 }
210
211 bool compiler::operator()(bool x) const
212 {
213 program.op(x ? op_true : op_false);
214 return true;
215 }
216
217 bool compiler::operator()(ast::variable const& x) const
218 {
219 int const* p = program.find_var(x.name);
220 if (p == 0)
221 {
222 std::cout << x.id << std::endl;
223 error_handler(x.id, "Undeclared variable: " + x.name);
224 return false;
225 }
226 program.op(op_load, *p);
227 return true;
228 }
229
230 bool compiler::operator()(ast::operation const& x) const
231 {
232 if (!boost::apply_visitor(*this, x.operand_))
233 return false;
234 switch (x.operator_)
235 {
236 case ast::op_plus: program.op(op_add); break;
237 case ast::op_minus: program.op(op_sub); break;
238 case ast::op_times: program.op(op_mul); break;
239 case ast::op_divide: program.op(op_div); break;
240
241 case ast::op_equal: program.op(op_eq); break;
242 case ast::op_not_equal: program.op(op_neq); break;
243 case ast::op_less: program.op(op_lt); break;
244 case ast::op_less_equal: program.op(op_lte); break;
245 case ast::op_greater: program.op(op_gt); break;
246 case ast::op_greater_equal: program.op(op_gte); break;
247
248 case ast::op_and: program.op(op_and); break;
249 case ast::op_or: program.op(op_or); break;
250 default: BOOST_ASSERT(0); return false;
251 }
252 return true;
253 }
254
255 bool compiler::operator()(ast::unary const& x) const
256 {
257 if (!boost::apply_visitor(*this, x.operand_))
258 return false;
259 switch (x.operator_)
260 {
261 case ast::op_negative: program.op(op_neg); break;
262 case ast::op_not: program.op(op_not); break;
263 case ast::op_positive: break;
264 default: BOOST_ASSERT(0); return false;
265 }
266 return true;
267 }
268
269 bool compiler::operator()(ast::expression const& x) const
270 {
271 if (!boost::apply_visitor(*this, x.first))
272 return false;
273 BOOST_FOREACH(ast::operation const& oper, x.rest)
274 {
275 if (!(*this)(oper))
276 return false;
277 }
278 return true;
279 }
280
281 bool compiler::operator()(ast::assignment const& x) const
282 {
283 if (!(*this)(x.rhs))
284 return false;
285 int const* p = program.find_var(x.lhs.name);
286 if (p == 0)
287 {
288 std::cout << x.lhs.id << std::endl;
289 error_handler(x.lhs.id, "Undeclared variable: " + x.lhs.name);
290 return false;
291 }
292 program.op(op_store, *p);
293 return true;
294 }
295
296 bool compiler::operator()(ast::variable_declaration const& x) const
297 {
298 int const* p = program.find_var(x.assign.lhs.name);
299 if (p != 0)
300 {
301 std::cout << x.assign.lhs.id << std::endl;
302 error_handler(x.assign.lhs.id, "Duplicate variable: " + x.assign.lhs.name);
303 return false;
304 }
305 bool r = (*this)(x.assign.rhs);
306 if (r) // don't add the variable if the RHS fails
307 {
308 program.add_var(x.assign.lhs.name);
309 program.op(op_store, *program.find_var(x.assign.lhs.name));
310 }
311 return r;
312 }
313
314 bool compiler::operator()(ast::statement const& x) const
315 {
316 return boost::apply_visitor(*this, x);
317 }
318
319 bool compiler::operator()(ast::statement_list const& x) const
320 {
321 BOOST_FOREACH(ast::statement const& s, x)
322 {
323 if (!(*this)(s))
324 return false;
325 }
326 return true;
327 }
328
329 bool compiler::operator()(ast::if_statement const& x) const
330 {
331 if (!(*this)(x.condition))
332 return false;
333 program.op(op_jump_if, 0); // we shall fill this (0) in later
334 std::size_t skip = program.size()-1; // mark its position
335 if (!(*this)(x.then))
336 return false;
337 program[skip] = program.size()-skip; // now we know where to jump to (after the if branch)
338
339 if (x.else_) // We got an alse
340 {
341 program[skip] += 2; // adjust for the "else" jump
342 program.op(op_jump, 0); // we shall fill this (0) in later
343 std::size_t exit = program.size()-1; // mark its position
344 if (!(*this)(*x.else_))
345 return false;
346 program[exit] = program.size()-exit; // now we know where to jump to (after the else branch)
347 }
348
349 return true;
350 }
351
352 bool compiler::operator()(ast::while_statement const& x) const
353 {
354 std::size_t loop = program.size(); // mark our position
355 if (!(*this)(x.condition))
356 return false;
357 program.op(op_jump_if, 0); // we shall fill this (0) in later
358 std::size_t exit = program.size()-1; // mark its position
359 if (!(*this)(x.body))
360 return false;
361 program.op(op_jump,
362 int(loop-1) - int(program.size())); // loop back
363 program[exit] = program.size()-exit; // now we know where to jump to (to exit the loop)
364 return true;
365 }
366
367 bool compiler::start(ast::statement_list const& x) const
368 {
369 program.clear();
370 // op_stk_adj 0 for now. we'll know how many variables we'll have later
371 program.op(op_stk_adj, 0);
372
373 if (!(*this)(x))
374 {
375 program.clear();
376 return false;
377 }
378 program[1] = program.nvars(); // now store the actual number of variables
379 return true;
380 }
381 }}
382