]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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" | |
7c673cae FG |
9 | #include <boost/variant/apply_visitor.hpp> |
10 | #include <boost/assert.hpp> | |
11 | #include <boost/lexical_cast.hpp> | |
12 | #include <iostream> | |
13 | #include <set> | |
14 | #include <iostream> | |
15 | ||
16 | namespace client { namespace code_gen | |
17 | { | |
18 | void program::op(int a) | |
19 | { | |
20 | code.push_back(a); | |
21 | } | |
22 | ||
23 | void program::op(int a, int b) | |
24 | { | |
25 | code.push_back(a); | |
26 | code.push_back(b); | |
27 | } | |
28 | ||
29 | void program::op(int a, int b, int c) | |
30 | { | |
31 | code.push_back(a); | |
32 | code.push_back(b); | |
33 | code.push_back(c); | |
34 | } | |
35 | ||
36 | int const* program::find_var(std::string const& name) const | |
37 | { | |
38 | auto i = variables.find(name); | |
39 | if (i == variables.end()) | |
40 | return 0; | |
41 | return &i->second; | |
42 | } | |
43 | ||
44 | void program::add_var(std::string const& name) | |
45 | { | |
46 | std::size_t n = variables.size(); | |
47 | variables[name] = int(n); | |
48 | } | |
49 | ||
50 | void program::print_variables(std::vector<int> const& stack) const | |
51 | { | |
52 | for (auto 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 | auto pc = code.begin(); | |
61 | ||
62 | std::vector<std::string> locals(variables.size()); | |
63 | typedef std::pair<std::string, int> pair; | |
64 | for (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 += boost::lexical_cast<std::string>(locals[*pc++]); | |
140 | break; | |
141 | ||
142 | case op_store: | |
143 | line += " op_store "; | |
144 | line += boost::lexical_cast<std::string>(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 | for (auto const& l : lines) | |
194 | { | |
195 | std::size_t pos = l.first; | |
196 | if (jumps.find(pos) != jumps.end()) | |
197 | std::cout << pos << ':' << std::endl; | |
198 | std::cout << l.second << std::endl; | |
199 | } | |
200 | ||
201 | std::cout << "end:" << std::endl; | |
202 | } | |
203 | ||
204 | bool compiler::operator()(unsigned int x) const | |
205 | { | |
206 | program.op(op_int, x); | |
207 | return true; | |
208 | } | |
209 | ||
210 | bool compiler::operator()(bool x) const | |
211 | { | |
212 | program.op(x ? op_true : op_false); | |
213 | return true; | |
214 | } | |
215 | ||
216 | bool compiler::operator()(ast::variable const& x) const | |
217 | { | |
218 | int const* p = program.find_var(x.name); | |
219 | if (p == 0) | |
220 | { | |
221 | error_handler(x, "Undeclared variable: " + x.name); | |
222 | return false; | |
223 | } | |
224 | program.op(op_load, *p); | |
225 | return true; | |
226 | } | |
227 | ||
228 | bool compiler::operator()(ast::operation const& x) const | |
229 | { | |
230 | if (!boost::apply_visitor(*this, x.operand_)) | |
231 | return false; | |
232 | switch (x.operator_) | |
233 | { | |
234 | case ast::op_plus: program.op(op_add); break; | |
235 | case ast::op_minus: program.op(op_sub); break; | |
236 | case ast::op_times: program.op(op_mul); break; | |
237 | case ast::op_divide: program.op(op_div); break; | |
238 | ||
239 | case ast::op_equal: program.op(op_eq); break; | |
240 | case ast::op_not_equal: program.op(op_neq); break; | |
241 | case ast::op_less: program.op(op_lt); break; | |
242 | case ast::op_less_equal: program.op(op_lte); break; | |
243 | case ast::op_greater: program.op(op_gt); break; | |
244 | case ast::op_greater_equal: program.op(op_gte); break; | |
245 | ||
246 | case ast::op_and: program.op(op_and); break; | |
247 | case ast::op_or: program.op(op_or); break; | |
248 | default: BOOST_ASSERT(0); return false; | |
249 | } | |
250 | return true; | |
251 | } | |
252 | ||
253 | bool compiler::operator()(ast::unary const& x) const | |
254 | { | |
255 | if (!boost::apply_visitor(*this, x.operand_)) | |
256 | return false; | |
257 | switch (x.operator_) | |
258 | { | |
259 | case ast::op_negative: program.op(op_neg); break; | |
260 | case ast::op_not: program.op(op_not); break; | |
261 | case ast::op_positive: break; | |
262 | default: BOOST_ASSERT(0); return false; | |
263 | } | |
264 | return true; | |
265 | } | |
266 | ||
267 | bool compiler::operator()(ast::expression const& x) const | |
268 | { | |
269 | if (!boost::apply_visitor(*this, x.first)) | |
270 | return false; | |
271 | for (ast::operation const& oper : x.rest) | |
272 | { | |
273 | if (!(*this)(oper)) | |
274 | return false; | |
275 | } | |
276 | return true; | |
277 | } | |
278 | ||
279 | bool compiler::operator()(ast::assignment const& x) const | |
280 | { | |
281 | if (!(*this)(x.rhs)) | |
282 | return false; | |
283 | int const* p = program.find_var(x.lhs.name); | |
284 | if (p == 0) | |
285 | { | |
286 | error_handler(x.lhs, "Undeclared variable: " + x.lhs.name); | |
287 | return false; | |
288 | } | |
289 | program.op(op_store, *p); | |
290 | return true; | |
291 | } | |
292 | ||
293 | bool compiler::operator()(ast::variable_declaration const& x) const | |
294 | { | |
295 | int const* p = program.find_var(x.assign.lhs.name); | |
296 | if (p != 0) | |
297 | { | |
298 | error_handler(x.assign.lhs, "Duplicate variable: " + x.assign.lhs.name); | |
299 | return false; | |
300 | } | |
301 | bool r = (*this)(x.assign.rhs); | |
302 | if (r) // don't add the variable if the RHS fails | |
303 | { | |
304 | program.add_var(x.assign.lhs.name); | |
305 | program.op(op_store, *program.find_var(x.assign.lhs.name)); | |
306 | } | |
307 | return r; | |
308 | } | |
309 | ||
310 | bool compiler::operator()(ast::statement const& x) const | |
311 | { | |
312 | return boost::apply_visitor(*this, x); | |
313 | } | |
314 | ||
315 | bool compiler::operator()(ast::statement_list const& x) const | |
316 | { | |
317 | for (auto const& s : x) | |
318 | { | |
319 | if (!(*this)(s)) | |
320 | return false; | |
321 | } | |
322 | return true; | |
323 | } | |
324 | ||
325 | bool compiler::operator()(ast::if_statement const& x) const | |
326 | { | |
327 | if (!(*this)(x.condition)) | |
328 | return false; | |
329 | program.op(op_jump_if, 0); // we shall fill this (0) in later | |
330 | std::size_t skip = program.size()-1; // mark its position | |
331 | if (!(*this)(x.then)) | |
332 | return false; | |
333 | program[skip] = int(program.size()-skip); // now we know where to jump to (after the if branch) | |
334 | ||
335 | if (x.else_) // We got an alse | |
336 | { | |
337 | program[skip] += 2; // adjust for the "else" jump | |
338 | program.op(op_jump, 0); // we shall fill this (0) in later | |
339 | std::size_t exit = program.size()-1; // mark its position | |
340 | if (!(*this)(*x.else_)) | |
341 | return false; | |
342 | program[exit] = int(program.size()-exit); // now we know where to jump to (after the else branch) | |
343 | } | |
344 | ||
345 | return true; | |
346 | } | |
347 | ||
348 | bool compiler::operator()(ast::while_statement const& x) const | |
349 | { | |
350 | std::size_t loop = program.size(); // mark our position | |
351 | if (!(*this)(x.condition)) | |
352 | return false; | |
353 | program.op(op_jump_if, 0); // we shall fill this (0) in later | |
354 | std::size_t exit = program.size()-1; // mark its position | |
355 | if (!(*this)(x.body)) | |
356 | return false; | |
357 | program.op(op_jump, | |
358 | int(loop-1) - int(program.size())); // loop back | |
359 | program[exit] = int(program.size()-exit); // now we know where to jump to (to exit the loop) | |
360 | return true; | |
361 | } | |
362 | ||
363 | bool compiler::start(ast::statement_list const& x) const | |
364 | { | |
365 | program.clear(); | |
366 | // op_stk_adj 0 for now. we'll know how many variables we'll have later | |
367 | program.op(op_stk_adj, 0); | |
368 | ||
369 | if (!(*this)(x)) | |
370 | { | |
371 | program.clear(); | |
372 | return false; | |
373 | } | |
374 | program[1] = int(program.nvars()); // now store the actual number of variables | |
375 | return true; | |
376 | } | |
377 | }} |