compiler.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  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 program::op(int a)
  16. {
  17. code.push_back(a);
  18. }
  19. void program::op(int a, int b)
  20. {
  21. code.push_back(a);
  22. code.push_back(b);
  23. }
  24. void program::op(int a, int b, int c)
  25. {
  26. code.push_back(a);
  27. code.push_back(b);
  28. code.push_back(c);
  29. }
  30. int const* program::find_var(std::string const& name) const
  31. {
  32. std::map<std::string, int>::const_iterator i = variables.find(name);
  33. if (i == variables.end())
  34. return 0;
  35. return &i->second;
  36. }
  37. void program::add_var(std::string const& name)
  38. {
  39. std::size_t n = variables.size();
  40. variables[name] = n;
  41. }
  42. void program::print_variables(std::vector<int> const& stack) const
  43. {
  44. typedef std::pair<std::string, int> pair;
  45. BOOST_FOREACH(pair const& p, variables)
  46. {
  47. std::cout << " " << p.first << ": " << stack[p.second] << std::endl;
  48. }
  49. }
  50. void program::print_assembler() const
  51. {
  52. std::vector<int>::const_iterator pc = code.begin();
  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.end())
  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_stk_adj:
  152. line += " op_stk_adj ";
  153. line += boost::lexical_cast<std::string>(*pc++);
  154. break;
  155. }
  156. lines[address] = line;
  157. }
  158. std::cout << "start:" << std::endl;
  159. typedef std::pair<std::size_t, std::string> line_info;
  160. BOOST_FOREACH(line_info const& l, lines)
  161. {
  162. std::size_t pos = l.first;
  163. if (jumps.find(pos) != jumps.end())
  164. std::cout << pos << ':' << std::endl;
  165. std::cout << l.second << std::endl;
  166. }
  167. std::cout << "end:" << std::endl;
  168. }
  169. bool compiler::operator()(unsigned int x) const
  170. {
  171. program.op(op_int, x);
  172. return true;
  173. }
  174. bool compiler::operator()(bool x) const
  175. {
  176. program.op(x ? op_true : op_false);
  177. return true;
  178. }
  179. bool compiler::operator()(ast::variable const& x) const
  180. {
  181. int const* p = program.find_var(x.name);
  182. if (p == 0)
  183. {
  184. std::cout << x.id << std::endl;
  185. error_handler(x.id, "Undeclared variable: " + x.name);
  186. return false;
  187. }
  188. program.op(op_load, *p);
  189. return true;
  190. }
  191. bool compiler::operator()(ast::operation const& x) const
  192. {
  193. if (!boost::apply_visitor(*this, x.operand_))
  194. return false;
  195. switch (x.operator_)
  196. {
  197. case ast::op_plus: program.op(op_add); break;
  198. case ast::op_minus: program.op(op_sub); break;
  199. case ast::op_times: program.op(op_mul); break;
  200. case ast::op_divide: program.op(op_div); break;
  201. case ast::op_equal: program.op(op_eq); break;
  202. case ast::op_not_equal: program.op(op_neq); break;
  203. case ast::op_less: program.op(op_lt); break;
  204. case ast::op_less_equal: program.op(op_lte); break;
  205. case ast::op_greater: program.op(op_gt); break;
  206. case ast::op_greater_equal: program.op(op_gte); break;
  207. case ast::op_and: program.op(op_and); break;
  208. case ast::op_or: program.op(op_or); break;
  209. default: BOOST_ASSERT(0); return false;
  210. }
  211. return true;
  212. }
  213. bool compiler::operator()(ast::unary const& x) const
  214. {
  215. if (!boost::apply_visitor(*this, x.operand_))
  216. return false;
  217. switch (x.operator_)
  218. {
  219. case ast::op_negative: program.op(op_neg); break;
  220. case ast::op_not: program.op(op_not); break;
  221. case ast::op_positive: break;
  222. default: BOOST_ASSERT(0); return false;
  223. }
  224. return true;
  225. }
  226. bool compiler::operator()(ast::expression const& x) const
  227. {
  228. if (!boost::apply_visitor(*this, x.first))
  229. return false;
  230. BOOST_FOREACH(ast::operation const& oper, x.rest)
  231. {
  232. if (!(*this)(oper))
  233. return false;
  234. }
  235. return true;
  236. }
  237. bool compiler::operator()(ast::assignment const& x) const
  238. {
  239. if (!(*this)(x.rhs))
  240. return false;
  241. int const* p = program.find_var(x.lhs.name);
  242. if (p == 0)
  243. {
  244. std::cout << x.lhs.id << std::endl;
  245. error_handler(x.lhs.id, "Undeclared variable: " + x.lhs.name);
  246. return false;
  247. }
  248. program.op(op_store, *p);
  249. return true;
  250. }
  251. bool compiler::operator()(ast::variable_declaration const& x) const
  252. {
  253. int const* p = program.find_var(x.assign.lhs.name);
  254. if (p != 0)
  255. {
  256. std::cout << x.assign.lhs.id << std::endl;
  257. error_handler(x.assign.lhs.id, "Duplicate variable: " + x.assign.lhs.name);
  258. return false;
  259. }
  260. bool r = (*this)(x.assign.rhs);
  261. if (r) // don't add the variable if the RHS fails
  262. {
  263. program.add_var(x.assign.lhs.name);
  264. program.op(op_store, *program.find_var(x.assign.lhs.name));
  265. }
  266. return r;
  267. }
  268. bool compiler::operator()(ast::statement const& x) const
  269. {
  270. return boost::apply_visitor(*this, x);
  271. }
  272. bool compiler::operator()(ast::statement_list const& x) const
  273. {
  274. BOOST_FOREACH(ast::statement const& s, x)
  275. {
  276. if (!(*this)(s))
  277. return false;
  278. }
  279. return true;
  280. }
  281. bool compiler::operator()(ast::if_statement const& x) const
  282. {
  283. if (!(*this)(x.condition))
  284. return false;
  285. program.op(op_jump_if, 0); // we shall fill this (0) in later
  286. std::size_t skip = program.size()-1; // mark its position
  287. if (!(*this)(x.then))
  288. return false;
  289. program[skip] = program.size()-skip; // now we know where to jump to (after the if branch)
  290. if (x.else_) // We got an alse
  291. {
  292. program[skip] += 2; // adjust for the "else" jump
  293. program.op(op_jump, 0); // we shall fill this (0) in later
  294. std::size_t exit = program.size()-1; // mark its position
  295. if (!(*this)(*x.else_))
  296. return false;
  297. program[exit] = program.size()-exit; // now we know where to jump to (after the else branch)
  298. }
  299. return true;
  300. }
  301. bool compiler::operator()(ast::while_statement const& x) const
  302. {
  303. std::size_t loop = program.size(); // mark our position
  304. if (!(*this)(x.condition))
  305. return false;
  306. program.op(op_jump_if, 0); // we shall fill this (0) in later
  307. std::size_t exit = program.size()-1; // mark its position
  308. if (!(*this)(x.body))
  309. return false;
  310. program.op(op_jump,
  311. int(loop-1) - int(program.size())); // loop back
  312. program[exit] = program.size()-exit; // now we know where to jump to (to exit the loop)
  313. return true;
  314. }
  315. bool compiler::start(ast::statement_list const& x) const
  316. {
  317. program.clear();
  318. // op_stk_adj 0 for now. we'll know how many variables we'll have later
  319. program.op(op_stk_adj, 0);
  320. if (!(*this)(x))
  321. {
  322. program.clear();
  323. return false;
  324. }
  325. program[1] = program.nvars(); // now store the actual number of variables
  326. return true;
  327. }
  328. }}