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 { op(int a)17 void function::op(int a) 18 { 19 code.push_back(a); 20 size_ += 1; 21 } 22 op(int a,int b)23 void function::op(int a, int b) 24 { 25 code.push_back(a); 26 code.push_back(b); 27 size_ += 2; 28 } 29 op(int a,int b,int c)30 void function::op(int a, int b, int c) 31 { 32 code.push_back(a); 33 code.push_back(b); 34 code.push_back(c); 35 size_ += 3; 36 } 37 find_var(std::string const & name) const38 int const* function::find_var(std::string const& name) const 39 { 40 std::map<std::string, int>::const_iterator i = variables.find(name); 41 if (i == variables.end()) 42 return 0; 43 return &i->second; 44 } 45 add_var(std::string const & name)46 void function::add_var(std::string const& name) 47 { 48 std::size_t n = variables.size(); 49 variables[name] = n; 50 } 51 link_to(std::string const & name,std::size_t address)52 void function::link_to(std::string const& name, std::size_t address) 53 { 54 function_calls[address] = name; 55 } 56 print_assembler() const57 void function::print_assembler() const 58 { 59 std::vector<int>::const_iterator pc = code.begin() + address; 60 61 std::vector<std::string> locals(variables.size()); 62 typedef std::pair<std::string, int> pair; 63 BOOST_FOREACH(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.begin() + address + size_)) 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 += boost::lexical_cast<std::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 += boost::lexical_cast<std::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 += boost::lexical_cast<std::string>(pos); 179 jumps.insert(pos); 180 } 181 break; 182 183 case op_call: 184 { 185 line += " op_call "; 186 int nargs = *pc++; 187 std::size_t jump = *pc++; 188 line += boost::lexical_cast<std::string>(nargs) + ", "; 189 BOOST_ASSERT(function_calls.find(jump) != function_calls.end()); 190 line += function_calls.find(jump)->second; 191 } 192 break; 193 194 case op_stk_adj: 195 line += " op_stk_adj "; 196 line += boost::lexical_cast<std::string>(*pc++); 197 break; 198 199 200 case op_return: 201 line += " op_return"; 202 break; 203 } 204 lines[address] = line; 205 } 206 207 std::cout << "start:" << std::endl; 208 typedef std::pair<std::size_t, std::string> line_info; 209 BOOST_FOREACH(line_info const& l, lines) 210 { 211 std::size_t pos = l.first; 212 if (jumps.find(pos) != jumps.end()) 213 std::cout << pos << ':' << std::endl; 214 std::cout << l.second << std::endl; 215 } 216 217 std::cout << "end:" << std::endl << std::endl; 218 } 219 operator ()(unsigned int x)220 bool compiler::operator()(unsigned int x) 221 { 222 BOOST_ASSERT(current != 0); 223 current->op(op_int, x); 224 return true; 225 } 226 operator ()(bool x)227 bool compiler::operator()(bool x) 228 { 229 BOOST_ASSERT(current != 0); 230 current->op(x ? op_true : op_false); 231 return true; 232 } 233 operator ()(ast::identifier const & x)234 bool compiler::operator()(ast::identifier const& x) 235 { 236 BOOST_ASSERT(current != 0); 237 int const* p = current->find_var(x.name); 238 if (p == 0) 239 { 240 error_handler(x.id, "Undeclared variable: " + x.name); 241 return false; 242 } 243 current->op(op_load, *p); 244 return true; 245 } 246 operator ()(ast::optoken const & x)247 bool compiler::operator()(ast::optoken const& x) 248 { 249 BOOST_ASSERT(current != 0); 250 switch (x) 251 { 252 case ast::op_plus: current->op(op_add); break; 253 case ast::op_minus: current->op(op_sub); break; 254 case ast::op_times: current->op(op_mul); break; 255 case ast::op_divide: current->op(op_div); break; 256 257 case ast::op_equal: current->op(op_eq); break; 258 case ast::op_not_equal: current->op(op_neq); break; 259 case ast::op_less: current->op(op_lt); break; 260 case ast::op_less_equal: current->op(op_lte); break; 261 case ast::op_greater: current->op(op_gt); break; 262 case ast::op_greater_equal: current->op(op_gte); break; 263 264 case ast::op_logical_or: current->op(op_or); break; 265 case ast::op_logical_and: current->op(op_and); break; 266 default: BOOST_ASSERT(0); return false; 267 } 268 return true; 269 } 270 operator ()(ast::unary const & x)271 bool compiler::operator()(ast::unary const& x) 272 { 273 BOOST_ASSERT(current != 0); 274 if (!boost::apply_visitor(*this, x.operand_)) 275 return false; 276 switch (x.operator_) 277 { 278 case ast::op_negative: current->op(op_neg); break; 279 case ast::op_not: current->op(op_not); break; 280 case ast::op_positive: break; 281 default: BOOST_ASSERT(0); return false; 282 } 283 return true; 284 } 285 operator ()(ast::function_call const & x)286 bool compiler::operator()(ast::function_call const& x) 287 { 288 BOOST_ASSERT(current != 0); 289 290 if (functions.find(x.function_name.name) == functions.end()) 291 { 292 error_handler(x.function_name.id, "Function not found: " + x.function_name.name); 293 return false; 294 } 295 296 boost::shared_ptr<code_gen::function> p = functions[x.function_name.name]; 297 298 if (p->nargs() != x.args.size()) 299 { 300 error_handler(x.function_name.id, "Wrong number of arguments: " + x.function_name.name); 301 return false; 302 } 303 304 BOOST_FOREACH(ast::expression const& expr, x.args) 305 { 306 if (!(*this)(expr)) 307 return false; 308 } 309 310 current->op( 311 op_call, 312 p->nargs(), 313 p->get_address()); 314 current->link_to(x.function_name.name, p->get_address()); 315 316 return true; 317 } 318 319 namespace 320 { 321 int precedence[] = { 322 // precedence 1 323 1, // op_comma 324 325 // precedence 2 326 2, // op_assign 327 2, // op_plus_assign 328 2, // op_minus_assign 329 2, // op_times_assign 330 2, // op_divide_assign 331 2, // op_mod_assign 332 2, // op_bit_and_assign 333 2, // op_bit_xor_assign 334 2, // op_bitor_assign 335 2, // op_shift_left_assign 336 2, // op_shift_right_assign 337 338 // precedence 3 339 3, // op_logical_or 340 341 // precedence 4 342 4, // op_logical_and 343 344 // precedence 5 345 5, // op_bit_or 346 347 // precedence 6 348 6, // op_bit_xor 349 350 // precedence 7 351 7, // op_bit_and 352 353 // precedence 8 354 8, // op_equal 355 8, // op_not_equal 356 357 // precedence 9 358 9, // op_less 359 9, // op_less_equal 360 9, // op_greater 361 9, // op_greater_equal 362 363 // precedence 10 364 10, // op_shift_left 365 10, // op_shift_right 366 367 // precedence 11 368 11, // op_plus 369 11, // op_minus 370 371 // precedence 12 372 12, // op_times 373 12, // op_divide 374 12, // op_mod 375 376 // precedence 13 377 13, // op_positive 378 13, // op_negative 379 13, // op_pre_incr 380 13, // op_pre_decr 381 13, // op_compl 382 13, // op_not 383 384 // precedence 14 385 14, // op_post_incr 386 14 // op_post_decr 387 }; 388 } 389 390 // The Shunting-yard algorithm compile_expression(int min_precedence,std::list<ast::operation>::const_iterator & rbegin,std::list<ast::operation>::const_iterator rend)391 bool compiler::compile_expression( 392 int min_precedence, 393 std::list<ast::operation>::const_iterator& rbegin, 394 std::list<ast::operation>::const_iterator rend) 395 { 396 while ((rbegin != rend) && (precedence[rbegin->operator_] >= min_precedence)) 397 { 398 ast::optoken op = rbegin->operator_; 399 if (!boost::apply_visitor(*this, rbegin->operand_)) 400 return false; 401 ++rbegin; 402 403 while ((rbegin != rend) && (precedence[rbegin->operator_] > precedence[op])) 404 { 405 ast::optoken next_op = rbegin->operator_; 406 compile_expression(precedence[next_op], rbegin, rend); 407 } 408 (*this)(op); 409 } 410 return true; 411 } 412 operator ()(ast::expression const & x)413 bool compiler::operator()(ast::expression const& x) 414 { 415 BOOST_ASSERT(current != 0); 416 if (!boost::apply_visitor(*this, x.first)) 417 return false; 418 std::list<ast::operation>::const_iterator rbegin = x.rest.begin(); 419 if (!compile_expression(0, rbegin, x.rest.end())) 420 return false; 421 return true; 422 } 423 operator ()(ast::assignment const & x)424 bool compiler::operator()(ast::assignment const& x) 425 { 426 BOOST_ASSERT(current != 0); 427 if (!(*this)(x.rhs)) 428 return false; 429 int const* p = current->find_var(x.lhs.name); 430 if (p == 0) 431 { 432 error_handler(x.lhs.id, "Undeclared variable: " + x.lhs.name); 433 return false; 434 } 435 current->op(op_store, *p); 436 return true; 437 } 438 operator ()(ast::variable_declaration const & x)439 bool compiler::operator()(ast::variable_declaration const& x) 440 { 441 BOOST_ASSERT(current != 0); 442 int const* p = current->find_var(x.lhs.name); 443 if (p != 0) 444 { 445 error_handler(x.lhs.id, "Duplicate variable: " + x.lhs.name); 446 return false; 447 } 448 if (x.rhs) // if there's an RHS initializer 449 { 450 bool r = (*this)(*x.rhs); 451 if (r) // don't add the variable if the RHS fails 452 { 453 current->add_var(x.lhs.name); 454 current->op(op_store, *current->find_var(x.lhs.name)); 455 } 456 return r; 457 } 458 else 459 { 460 current->add_var(x.lhs.name); 461 } 462 return true; 463 } 464 operator ()(ast::statement const & x)465 bool compiler::operator()(ast::statement const& x) 466 { 467 BOOST_ASSERT(current != 0); 468 return boost::apply_visitor(*this, x); 469 } 470 operator ()(ast::statement_list const & x)471 bool compiler::operator()(ast::statement_list const& x) 472 { 473 BOOST_ASSERT(current != 0); 474 BOOST_FOREACH(ast::statement const& s, x) 475 { 476 if (!(*this)(s)) 477 return false; 478 } 479 return true; 480 } 481 operator ()(ast::if_statement const & x)482 bool compiler::operator()(ast::if_statement const& x) 483 { 484 BOOST_ASSERT(current != 0); 485 if (!(*this)(x.condition)) 486 return false; 487 current->op(op_jump_if, 0); // we shall fill this (0) in later 488 std::size_t skip = current->size()-1; // mark its position 489 if (!(*this)(x.then)) 490 return false; 491 (*current)[skip] = current->size()-skip; // now we know where to jump to (after the if branch) 492 493 if (x.else_) // We got an alse 494 { 495 (*current)[skip] += 2; // adjust for the "else" jump 496 current->op(op_jump, 0); // we shall fill this (0) in later 497 std::size_t exit = current->size()-1; // mark its position 498 if (!(*this)(*x.else_)) 499 return false; 500 (*current)[exit] = current->size()-exit;// now we know where to jump to (after the else branch) 501 } 502 503 return true; 504 } 505 operator ()(ast::while_statement const & x)506 bool compiler::operator()(ast::while_statement const& x) 507 { 508 BOOST_ASSERT(current != 0); 509 std::size_t loop = current->size(); // mark our position 510 if (!(*this)(x.condition)) 511 return false; 512 current->op(op_jump_if, 0); // we shall fill this (0) in later 513 std::size_t exit = current->size()-1; // mark its position 514 if (!(*this)(x.body)) 515 return false; 516 current->op(op_jump, 517 int(loop-1) - int(current->size())); // loop back 518 (*current)[exit] = current->size()-exit; // now we know where to jump to (to exit the loop) 519 return true; 520 } 521 operator ()(ast::return_statement const & x)522 bool compiler::operator()(ast::return_statement const& x) 523 { 524 if (void_return) 525 { 526 if (x.expr) 527 { 528 error_handler(x.id, "'void' function returning a value: "); 529 return false; 530 } 531 } 532 else 533 { 534 if (!x.expr) 535 { 536 error_handler(x.id, current_function_name + " function must return a value: "); 537 return false; 538 } 539 } 540 541 if (x.expr) 542 { 543 if (!(*this)(*x.expr)) 544 return false; 545 } 546 current->op(op_return); 547 return true; 548 } 549 operator ()(ast::function const & x)550 bool compiler::operator()(ast::function const& x) 551 { 552 void_return = x.return_type == "void"; 553 if (functions.find(x.function_name.name) != functions.end()) 554 { 555 error_handler(x.function_name.id, "Duplicate function: " + x.function_name.name); 556 return false; 557 } 558 boost::shared_ptr<code_gen::function>& p = functions[x.function_name.name]; 559 p.reset(new code_gen::function(code, x.args.size())); 560 current = p.get(); 561 current_function_name = x.function_name.name; 562 563 // op_stk_adj 0 for now. we'll know how many variables 564 // we'll have later and add them 565 current->op(op_stk_adj, 0); 566 BOOST_FOREACH(ast::identifier const& arg, x.args) 567 { 568 current->add_var(arg.name); 569 } 570 571 if (!(*this)(x.body)) 572 return false; 573 (*current)[1] = current->nvars(); // now store the actual number of variables 574 // this includes the arguments 575 return true; 576 } 577 operator ()(ast::function_list const & x)578 bool compiler::operator()(ast::function_list const& x) 579 { 580 // Jump to the main function 581 code.push_back(op_jump); 582 code.push_back(0); // we will fill this in later when we finish compiling 583 // and we know where the main function is 584 585 BOOST_FOREACH(ast::function const& f, x) 586 { 587 if (!(*this)(f)) 588 { 589 code.clear(); 590 return false; 591 } 592 } 593 // find the main function 594 boost::shared_ptr<code_gen::function> p = 595 find_function("main"); 596 597 if (!p) // main function not found 598 { 599 std::cerr << "Error: main function not defined" << std::endl; 600 return false; 601 } 602 code[1] = p->get_address()-1; // jump to this (main function) address 603 604 return true; 605 } 606 print_assembler() const607 void compiler::print_assembler() const 608 { 609 typedef std::pair<std::string, boost::shared_ptr<code_gen::function> > pair; 610 BOOST_FOREACH(pair const& p, functions) 611 { 612 std::cout << ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;" << std::endl; 613 std::cout << p.second->get_address() << ": function " << p.first << std::endl; 614 p.second->print_assembler(); 615 } 616 } 617 618 boost::shared_ptr<code_gen::function> find_function(std::string const & name) const619 compiler::find_function(std::string const& name) const 620 { 621 function_table::const_iterator i = functions.find(name); 622 if (i == functions.end()) 623 return boost::shared_ptr<code_gen::function>(); 624 else 625 return i->second; 626 } 627 }} 628 629