• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
15 namespace client { namespace code_gen
16 {
op(int a)17     void program::op(int a)
18     {
19         code.push_back(a);
20     }
21 
op(int a,int b)22     void program::op(int a, int b)
23     {
24         code.push_back(a);
25         code.push_back(b);
26     }
27 
op(int a,int b,int c)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 
find_var(std::string const & name) const35     int const* program::find_var(std::string const& name) const
36     {
37         auto i = variables.find(name);
38         if (i == variables.end())
39             return 0;
40         return &i->second;
41     }
42 
add_var(std::string const & name)43     void program::add_var(std::string const& name)
44     {
45         std::size_t n = variables.size();
46         variables[name] = int(n);
47     }
48 
print_variables(std::vector<int> const & stack) const49     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 
print_assembler() const57     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(*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(pos);
167                         jumps.insert(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(pos);
179                         jumps.insert(pos);
180                     }
181                     break;
182 
183                 case op_stk_adj:
184                     line += "      op_stk_adj  ";
185                     line += std::to_string(*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(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 
operator ()(unsigned int x) const203     bool compiler::operator()(unsigned int x) const
204     {
205         program.op(op_int, x);
206         return true;
207     }
208 
operator ()(bool x) const209     bool compiler::operator()(bool x) const
210     {
211         program.op(x ? op_true : op_false);
212         return true;
213     }
214 
operator ()(ast::variable const & x) const215     bool compiler::operator()(ast::variable const& x) const
216     {
217         int const* p = program.find_var(x.name);
218         if (p == 0)
219         {
220             error_handler(x, "Undeclared variable: " + x.name);
221             return false;
222         }
223         program.op(op_load, *p);
224         return true;
225     }
226 
operator ()(ast::operation const & x) const227     bool compiler::operator()(ast::operation const& x) const
228     {
229         if (!boost::apply_visitor(*this, x.operand_))
230             return false;
231         switch (x.operator_)
232         {
233             case ast::op_plus: program.op(op_add); break;
234             case ast::op_minus: program.op(op_sub); break;
235             case ast::op_times: program.op(op_mul); break;
236             case ast::op_divide: program.op(op_div); break;
237 
238             case ast::op_equal: program.op(op_eq); break;
239             case ast::op_not_equal: program.op(op_neq); break;
240             case ast::op_less: program.op(op_lt); break;
241             case ast::op_less_equal: program.op(op_lte); break;
242             case ast::op_greater: program.op(op_gt); break;
243             case ast::op_greater_equal: program.op(op_gte); break;
244 
245             case ast::op_and: program.op(op_and); break;
246             case ast::op_or: program.op(op_or); break;
247             default: BOOST_ASSERT(0); return false;
248         }
249         return true;
250     }
251 
operator ()(ast::unary const & x) const252     bool compiler::operator()(ast::unary const& x) const
253     {
254         if (!boost::apply_visitor(*this, x.operand_))
255             return false;
256         switch (x.operator_)
257         {
258             case ast::op_negative: program.op(op_neg); break;
259             case ast::op_not: program.op(op_not); break;
260             case ast::op_positive: break;
261             default: BOOST_ASSERT(0); return false;
262         }
263         return true;
264     }
265 
operator ()(ast::expression const & x) const266     bool compiler::operator()(ast::expression const& x) const
267     {
268         if (!boost::apply_visitor(*this, 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 
operator ()(ast::assignment const & x) const278     bool compiler::operator()(ast::assignment const& x) const
279     {
280         if (!(*this)(x.rhs))
281             return false;
282         int const* p = program.find_var(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(op_store, *p);
289         return true;
290     }
291 
operator ()(ast::variable_declaration const & x) const292     bool compiler::operator()(ast::variable_declaration const& x) const
293     {
294         int const* p = program.find_var(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(x.assign.lhs.name);
304             program.op(op_store, *program.find_var(x.assign.lhs.name));
305         }
306         return r;
307     }
308 
operator ()(ast::statement const & x) const309     bool compiler::operator()(ast::statement const& x) const
310     {
311         return boost::apply_visitor(*this, x);
312     }
313 
operator ()(ast::statement_list const & x) const314     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 
operator ()(ast::if_statement const & x) const324     bool compiler::operator()(ast::if_statement const& x) const
325     {
326         if (!(*this)(x.condition))
327             return false;
328         program.op(op_jump_if, 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(op_jump, 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 
operator ()(ast::while_statement const & x) const347     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(op_jump_if, 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(op_jump,
357             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 
start(ast::statement_list const & x) const362     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(op_stk_adj, 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