compiler.cpp 16 KB

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