compiler.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. /*=============================================================================
  2. Copyright (c) 2001-2011 Joel de Guzman
  3. Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. =============================================================================*/
  6. #include "config.hpp"
  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. namespace client { namespace code_gen
  15. {
  16. void function::op(int a)
  17. {
  18. code.push_back(a);
  19. size_ += 1;
  20. }
  21. void function::op(int a, int b)
  22. {
  23. code.push_back(a);
  24. code.push_back(b);
  25. size_ += 2;
  26. }
  27. void function::op(int a, int b, int c)
  28. {
  29. code.push_back(a);
  30. code.push_back(b);
  31. code.push_back(c);
  32. size_ += 3;
  33. }
  34. int const* function::find_var(std::string const& name) const
  35. {
  36. std::map<std::string, int>::const_iterator i = variables.find(name);
  37. if (i == variables.end())
  38. return 0;
  39. return &i->second;
  40. }
  41. void function::add_var(std::string const& name)
  42. {
  43. std::size_t n = variables.size();
  44. variables[name] = n;
  45. }
  46. void function::link_to(std::string const& name, std::size_t address)
  47. {
  48. function_calls[address] = name;
  49. }
  50. void function::print_assembler() const
  51. {
  52. std::vector<int>::const_iterator pc = code.begin() + address;
  53. std::vector<std::string> locals(variables.size());
  54. typedef std::pair<std::string, int> pair;
  55. BOOST_FOREACH(pair const& p, variables)
  56. {
  57. locals[p.second] = p.first;
  58. std::cout << " local "
  59. << p.first << ", @" << p.second << std::endl;
  60. }
  61. std::map<std::size_t, std::string> lines;
  62. std::set<std::size_t> jumps;
  63. while (pc != (code.begin() + address + size_))
  64. {
  65. std::string line;
  66. std::size_t address = pc - code.begin();
  67. switch (*pc++)
  68. {
  69. case op_neg:
  70. line += " op_neg";
  71. break;
  72. case op_not:
  73. line += " op_not";
  74. break;
  75. case op_add:
  76. line += " op_add";
  77. break;
  78. case op_sub:
  79. line += " op_sub";
  80. break;
  81. case op_mul:
  82. line += " op_mul";
  83. break;
  84. case op_div:
  85. line += " op_div";
  86. break;
  87. case op_eq:
  88. line += " op_eq";
  89. break;
  90. case op_neq:
  91. line += " op_neq";
  92. break;
  93. case op_lt:
  94. line += " op_lt";
  95. break;
  96. case op_lte:
  97. line += " op_lte";
  98. break;
  99. case op_gt:
  100. line += " op_gt";
  101. break;
  102. case op_gte:
  103. line += " op_gte";
  104. break;
  105. case op_and:
  106. line += " op_and";
  107. break;
  108. case op_or:
  109. line += " op_or";
  110. break;
  111. case op_load:
  112. line += " op_load ";
  113. line += locals[*pc++];
  114. break;
  115. case op_store:
  116. line += " op_store ";
  117. line += locals[*pc++];
  118. break;
  119. case op_int:
  120. line += " op_int ";
  121. line += boost::lexical_cast<std::string>(*pc++);
  122. break;
  123. case op_true:
  124. line += " op_true";
  125. break;
  126. case op_false:
  127. line += " op_false";
  128. break;
  129. case op_jump:
  130. {
  131. line += " op_jump ";
  132. std::size_t pos = (pc - code.begin()) + *pc++;
  133. if (pos == code.size())
  134. line += "end";
  135. else
  136. line += boost::lexical_cast<std::string>(pos);
  137. jumps.insert(pos);
  138. }
  139. break;
  140. case op_jump_if:
  141. {
  142. line += " op_jump_if ";
  143. std::size_t pos = (pc - code.begin()) + *pc++;
  144. if (pos == code.size())
  145. line += "end";
  146. else
  147. line += boost::lexical_cast<std::string>(pos);
  148. jumps.insert(pos);
  149. }
  150. break;
  151. case op_call:
  152. {
  153. line += " op_call ";
  154. int nargs = *pc++;
  155. std::size_t jump = *pc++;
  156. line += boost::lexical_cast<std::string>(nargs) + ", ";
  157. BOOST_ASSERT(function_calls.find(jump) != function_calls.end());
  158. line += function_calls.find(jump)->second;
  159. }
  160. break;
  161. case op_stk_adj:
  162. line += " op_stk_adj ";
  163. line += boost::lexical_cast<std::string>(*pc++);
  164. break;
  165. case op_return:
  166. line += " op_return";
  167. break;
  168. }
  169. lines[address] = line;
  170. }
  171. std::cout << "start:" << std::endl;
  172. typedef std::pair<std::size_t, std::string> line_info;
  173. BOOST_FOREACH(line_info const& l, lines)
  174. {
  175. std::size_t pos = l.first;
  176. if (jumps.find(pos) != jumps.end())
  177. std::cout << pos << ':' << std::endl;
  178. std::cout << l.second << std::endl;
  179. }
  180. std::cout << "end:" << std::endl << std::endl;
  181. }
  182. bool compiler::operator()(unsigned int x)
  183. {
  184. BOOST_ASSERT(current != 0);
  185. current->op(op_int, x);
  186. return true;
  187. }
  188. bool compiler::operator()(bool x)
  189. {
  190. BOOST_ASSERT(current != 0);
  191. current->op(x ? op_true : op_false);
  192. return true;
  193. }
  194. bool compiler::operator()(ast::identifier const& x)
  195. {
  196. BOOST_ASSERT(current != 0);
  197. int const* p = current->find_var(x.name);
  198. if (p == 0)
  199. {
  200. error_handler(x.id, "Undeclared variable: " + x.name);
  201. return false;
  202. }
  203. current->op(op_load, *p);
  204. return true;
  205. }
  206. bool compiler::operator()(token_ids::type const& x)
  207. {
  208. BOOST_ASSERT(current != 0);
  209. switch (x)
  210. {
  211. case token_ids::plus: current->op(op_add); break;
  212. case token_ids::minus: current->op(op_sub); break;
  213. case token_ids::times: current->op(op_mul); break;
  214. case token_ids::divide: current->op(op_div); break;
  215. case token_ids::equal: current->op(op_eq); break;
  216. case token_ids::not_equal: current->op(op_neq); break;
  217. case token_ids::less: current->op(op_lt); break;
  218. case token_ids::less_equal: current->op(op_lte); break;
  219. case token_ids::greater: current->op(op_gt); break;
  220. case token_ids::greater_equal: current->op(op_gte); break;
  221. case token_ids::logical_or: current->op(op_or); break;
  222. case token_ids::logical_and: current->op(op_and); break;
  223. default: BOOST_ASSERT(0); return false;
  224. }
  225. return true;
  226. }
  227. bool compiler::operator()(ast::unary const& x)
  228. {
  229. BOOST_ASSERT(current != 0);
  230. if (!boost::apply_visitor(*this, x.operand_))
  231. return false;
  232. switch (x.operator_)
  233. {
  234. case token_ids::minus: current->op(op_neg); break;
  235. case token_ids::not_: current->op(op_not); break;
  236. case token_ids::plus: break;
  237. default: BOOST_ASSERT(0); return false;
  238. }
  239. return true;
  240. }
  241. bool compiler::operator()(ast::function_call const& x)
  242. {
  243. BOOST_ASSERT(current != 0);
  244. if (functions.find(x.function_name.name) == functions.end())
  245. {
  246. error_handler(x.function_name.id, "Function not found: " + x.function_name.name);
  247. return false;
  248. }
  249. boost::shared_ptr<code_gen::function> p = functions[x.function_name.name];
  250. if (p->nargs() != x.args.size())
  251. {
  252. error_handler(x.function_name.id, "Wrong number of arguments: " + x.function_name.name);
  253. return false;
  254. }
  255. BOOST_FOREACH(ast::expression const& expr, x.args)
  256. {
  257. if (!(*this)(expr))
  258. return false;
  259. }
  260. current->op(
  261. op_call,
  262. p->nargs(),
  263. p->get_address());
  264. current->link_to(x.function_name.name, p->get_address());
  265. return true;
  266. }
  267. namespace
  268. {
  269. int precedence[] = {
  270. // precedence 1
  271. 1, // op_comma
  272. // precedence 2
  273. 2, // op_assign
  274. 2, // op_plus_assign
  275. 2, // op_minus_assign
  276. 2, // op_times_assign
  277. 2, // op_divide_assign
  278. 2, // op_mod_assign
  279. 2, // op_bit_and_assign
  280. 2, // op_bit_xor_assign
  281. 2, // op_bitor_assign
  282. 2, // op_shift_left_assign
  283. 2, // op_shift_right_assign
  284. // precedence 3
  285. 3, // op_logical_or
  286. // precedence 4
  287. 4, // op_logical_and
  288. // precedence 5
  289. 5, // op_bit_or
  290. // precedence 6
  291. 6, // op_bit_xor
  292. // precedence 7
  293. 7, // op_bit_and
  294. // precedence 8
  295. 8, // op_equal
  296. 8, // op_not_equal
  297. // precedence 9
  298. 9, // op_less
  299. 9, // op_less_equal
  300. 9, // op_greater
  301. 9, // op_greater_equal
  302. // precedence 10
  303. 10, // op_shift_left
  304. 10, // op_shift_right
  305. // precedence 11
  306. 11, // op_plus
  307. 11, // op_minus
  308. // precedence 12
  309. 12, // op_times
  310. 12, // op_divide
  311. 12 // op_mod
  312. };
  313. }
  314. inline int precedence_of(token_ids::type op)
  315. {
  316. return precedence[op & 0xFF];
  317. }
  318. // The Shunting-yard algorithm
  319. bool compiler::compile_expression(
  320. int min_precedence,
  321. std::list<ast::operation>::const_iterator& rbegin,
  322. std::list<ast::operation>::const_iterator rend)
  323. {
  324. while ((rbegin != rend) && (precedence_of(rbegin->operator_) >= min_precedence))
  325. {
  326. token_ids::type op = rbegin->operator_;
  327. if (!boost::apply_visitor(*this, rbegin->operand_))
  328. return false;
  329. ++rbegin;
  330. while ((rbegin != rend) && (precedence_of(rbegin->operator_) > precedence_of(op)))
  331. {
  332. token_ids::type next_op = rbegin->operator_;
  333. compile_expression(precedence_of(next_op), rbegin, rend);
  334. }
  335. (*this)(op);
  336. }
  337. return true;
  338. }
  339. bool compiler::operator()(ast::expression const& x)
  340. {
  341. BOOST_ASSERT(current != 0);
  342. if (!boost::apply_visitor(*this, x.first))
  343. return false;
  344. std::list<ast::operation>::const_iterator rbegin = x.rest.begin();
  345. if (!compile_expression(0, rbegin, x.rest.end()))
  346. return false;
  347. return true;
  348. }
  349. bool compiler::operator()(ast::assignment const& x)
  350. {
  351. BOOST_ASSERT(current != 0);
  352. if (!(*this)(x.rhs))
  353. return false;
  354. int const* p = current->find_var(x.lhs.name);
  355. if (p == 0)
  356. {
  357. error_handler(x.lhs.id, "Undeclared variable: " + x.lhs.name);
  358. return false;
  359. }
  360. current->op(op_store, *p);
  361. return true;
  362. }
  363. bool compiler::operator()(ast::variable_declaration const& x)
  364. {
  365. BOOST_ASSERT(current != 0);
  366. int const* p = current->find_var(x.lhs.name);
  367. if (p != 0)
  368. {
  369. error_handler(x.lhs.id, "Duplicate variable: " + x.lhs.name);
  370. return false;
  371. }
  372. if (x.rhs) // if there's an RHS initializer
  373. {
  374. bool r = (*this)(*x.rhs);
  375. if (r) // don't add the variable if the RHS fails
  376. {
  377. current->add_var(x.lhs.name);
  378. current->op(op_store, *current->find_var(x.lhs.name));
  379. }
  380. return r;
  381. }
  382. else
  383. {
  384. current->add_var(x.lhs.name);
  385. }
  386. return true;
  387. }
  388. bool compiler::operator()(ast::statement const& x)
  389. {
  390. BOOST_ASSERT(current != 0);
  391. return boost::apply_visitor(*this, x);
  392. }
  393. bool compiler::operator()(ast::statement_list const& x)
  394. {
  395. BOOST_ASSERT(current != 0);
  396. BOOST_FOREACH(ast::statement const& s, x)
  397. {
  398. if (!(*this)(s))
  399. return false;
  400. }
  401. return true;
  402. }
  403. bool compiler::operator()(ast::if_statement const& x)
  404. {
  405. BOOST_ASSERT(current != 0);
  406. if (!(*this)(x.condition))
  407. return false;
  408. current->op(op_jump_if, 0); // we shall fill this (0) in later
  409. std::size_t skip = current->size()-1; // mark its position
  410. if (!(*this)(x.then))
  411. return false;
  412. (*current)[skip] = current->size()-skip; // now we know where to jump to (after the if branch)
  413. if (x.else_) // We got an alse
  414. {
  415. (*current)[skip] += 2; // adjust for the "else" jump
  416. current->op(op_jump, 0); // we shall fill this (0) in later
  417. std::size_t exit = current->size()-1; // mark its position
  418. if (!(*this)(*x.else_))
  419. return false;
  420. (*current)[exit] = current->size()-exit;// now we know where to jump to (after the else branch)
  421. }
  422. return true;
  423. }
  424. bool compiler::operator()(ast::while_statement const& x)
  425. {
  426. BOOST_ASSERT(current != 0);
  427. std::size_t loop = current->size(); // mark our position
  428. if (!(*this)(x.condition))
  429. return false;
  430. current->op(op_jump_if, 0); // we shall fill this (0) in later
  431. std::size_t exit = current->size()-1; // mark its position
  432. if (!(*this)(x.body))
  433. return false;
  434. current->op(op_jump,
  435. int(loop-1) - int(current->size())); // loop back
  436. (*current)[exit] = current->size()-exit; // now we know where to jump to (to exit the loop)
  437. return true;
  438. }
  439. bool compiler::operator()(ast::return_statement const& x)
  440. {
  441. if (void_return)
  442. {
  443. if (x.expr)
  444. {
  445. error_handler(x.id, "'void' function returning a value: ");
  446. return false;
  447. }
  448. }
  449. else
  450. {
  451. if (!x.expr)
  452. {
  453. error_handler(x.id, current_function_name + " function must return a value: ");
  454. return false;
  455. }
  456. }
  457. if (x.expr)
  458. {
  459. if (!(*this)(*x.expr))
  460. return false;
  461. }
  462. current->op(op_return);
  463. return true;
  464. }
  465. bool compiler::operator()(ast::function const& x)
  466. {
  467. void_return = x.return_type == "void";
  468. if (functions.find(x.function_name.name) != functions.end())
  469. {
  470. error_handler(x.function_name.id, "Duplicate function: " + x.function_name.name);
  471. return false;
  472. }
  473. boost::shared_ptr<code_gen::function>& p = functions[x.function_name.name];
  474. p.reset(new code_gen::function(code, x.args.size()));
  475. current = p.get();
  476. current_function_name = x.function_name.name;
  477. // op_stk_adj 0 for now. we'll know how many variables
  478. // we'll have later and add them
  479. current->op(op_stk_adj, 0);
  480. BOOST_FOREACH(ast::identifier const& arg, x.args)
  481. {
  482. current->add_var(arg.name);
  483. }
  484. if (!(*this)(x.body))
  485. return false;
  486. (*current)[1] = current->nvars(); // now store the actual number of variables
  487. // this includes the arguments
  488. return true;
  489. }
  490. bool compiler::operator()(ast::function_list const& x)
  491. {
  492. // Jump to the main function
  493. code.push_back(op_jump);
  494. code.push_back(0); // we will fill this in later when we finish compiling
  495. // and we know where the main function is
  496. BOOST_FOREACH(ast::function const& f, x)
  497. {
  498. if (!(*this)(f))
  499. {
  500. code.clear();
  501. return false;
  502. }
  503. }
  504. // find the main function
  505. boost::shared_ptr<code_gen::function> p =
  506. find_function("main");
  507. if (!p) // main function not found
  508. {
  509. std::cerr << "Error: main function not defined" << std::endl;
  510. return false;
  511. }
  512. code[1] = p->get_address()-1; // jump to this (main function) address
  513. return true;
  514. }
  515. void compiler::print_assembler() const
  516. {
  517. typedef std::pair<std::string, boost::shared_ptr<code_gen::function> > pair;
  518. BOOST_FOREACH(pair const& p, functions)
  519. {
  520. std::cout << ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;" << std::endl;
  521. std::cout << p.second->get_address() << ": function " << p.first << std::endl;
  522. p.second->print_assembler();
  523. }
  524. }
  525. boost::shared_ptr<code_gen::function>
  526. compiler::find_function(std::string const& name) const
  527. {
  528. function_table::const_iterator i = functions.find(name);
  529. if (i == functions.end())
  530. return boost::shared_ptr<code_gen::function>();
  531. else
  532. return i->second;
  533. }
  534. }}