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