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

source code of boost/libs/spirit/example/x3/calc/calc9/compiler.cpp