vmachine_calc.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*=============================================================================
  2. Copyright (c) 1998-2003 Joel de Guzman
  3. http://spirit.sourceforge.net/
  4. Use, modification and distribution is subject to the Boost Software
  5. License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. http://www.boost.org/LICENSE_1_0.txt)
  7. =============================================================================*/
  8. ////////////////////////////////////////////////////////////////////////////
  9. //
  10. // The calculator using a simple virtual machine and compiler.
  11. //
  12. // Ported to v1.5 from the original v1.0 code by JDG
  13. // [ JDG 9/18/2002 ]
  14. //
  15. ////////////////////////////////////////////////////////////////////////////
  16. #include <boost/spirit/include/classic_core.hpp>
  17. #include <iostream>
  18. #include <vector>
  19. #include <string>
  20. ////////////////////////////////////////////////////////////////////////////
  21. using namespace std;
  22. using namespace BOOST_SPIRIT_CLASSIC_NS;
  23. ///////////////////////////////////////////////////////////////////////////////
  24. //
  25. // The VMachine
  26. //
  27. ///////////////////////////////////////////////////////////////////////////////
  28. enum ByteCodes
  29. {
  30. OP_NEG, // negate the top stack entry
  31. OP_ADD, // add top two stack entries
  32. OP_SUB, // subtract top two stack entries
  33. OP_MUL, // multiply top two stack entries
  34. OP_DIV, // divide top two stack entries
  35. OP_INT, // push constant integer into the stack
  36. OP_RET // return from the interpreter
  37. };
  38. class vmachine
  39. {
  40. public:
  41. vmachine(unsigned stackSize = 1024)
  42. : stack(new int[stackSize]),
  43. stackPtr(stack) {}
  44. ~vmachine() { delete [] stack; }
  45. int top() const { return stackPtr[-1]; };
  46. void execute(int code[]);
  47. private:
  48. int* stack;
  49. int* stackPtr;
  50. };
  51. void
  52. vmachine::execute(int code[])
  53. {
  54. int const* pc = code;
  55. bool running = true;
  56. stackPtr = stack;
  57. while (running)
  58. {
  59. switch (*pc++)
  60. {
  61. case OP_NEG:
  62. stackPtr[-1] = -stackPtr[-1];
  63. break;
  64. case OP_ADD:
  65. stackPtr--;
  66. stackPtr[-1] += stackPtr[0];
  67. break;
  68. case OP_SUB:
  69. stackPtr--;
  70. stackPtr[-1] -= stackPtr[0];
  71. break;
  72. case OP_MUL:
  73. stackPtr--;
  74. stackPtr[-1] *= stackPtr[0];
  75. break;
  76. case OP_DIV:
  77. stackPtr--;
  78. stackPtr[-1] /= stackPtr[0];
  79. break;
  80. case OP_INT:
  81. // Check stack overflow here!
  82. *stackPtr++ = *pc++;
  83. break;
  84. case OP_RET:
  85. running = false;
  86. break;
  87. }
  88. }
  89. }
  90. ///////////////////////////////////////////////////////////////////////////////
  91. //
  92. // The Compiler
  93. //
  94. ///////////////////////////////////////////////////////////////////////////////
  95. struct push_int
  96. {
  97. push_int(vector<int>& code_)
  98. : code(code_) {}
  99. void operator()(char const* str, char const* /*end*/) const
  100. {
  101. using namespace std;
  102. int n = strtol(str, 0, 10);
  103. code.push_back(OP_INT);
  104. code.push_back(n);
  105. cout << "push\t" << int(n) << endl;
  106. }
  107. vector<int>& code;
  108. };
  109. struct push_op
  110. {
  111. push_op(int op_, vector<int>& code_)
  112. : op(op_), code(code_) {}
  113. void operator()(char const*, char const*) const
  114. {
  115. code.push_back(op);
  116. switch (op) {
  117. case OP_NEG:
  118. cout << "neg\n";
  119. break;
  120. case OP_ADD:
  121. cout << "add\n";
  122. break;
  123. case OP_SUB:
  124. cout << "sub\n";
  125. break;
  126. case OP_MUL:
  127. cout << "mul\n";
  128. break;
  129. case OP_DIV:
  130. cout << "div\n";
  131. break;
  132. }
  133. }
  134. int op;
  135. vector<int>& code;
  136. };
  137. template <typename GrammarT>
  138. static bool
  139. compile(GrammarT const& calc, char const* expr)
  140. {
  141. cout << "\n/////////////////////////////////////////////////////////\n\n";
  142. parse_info<char const*>
  143. result = parse(expr, calc, space_p);
  144. if (result.full)
  145. {
  146. cout << "\t\t" << expr << " Parses OK\n\n\n";
  147. calc.code.push_back(OP_RET);
  148. return true;
  149. }
  150. else
  151. {
  152. cout << "\t\t" << expr << " Fails parsing\n";
  153. cout << "\t\t";
  154. for (int i = 0; i < (result.stop - expr); i++)
  155. cout << " ";
  156. cout << "^--Here\n\n\n";
  157. return false;
  158. }
  159. }
  160. ////////////////////////////////////////////////////////////////////////////
  161. //
  162. // Our calculator grammar
  163. //
  164. ////////////////////////////////////////////////////////////////////////////
  165. struct calculator : public grammar<calculator>
  166. {
  167. calculator(vector<int>& code_)
  168. : code(code_) {}
  169. template <typename ScannerT>
  170. struct definition
  171. {
  172. definition(calculator const& self)
  173. {
  174. integer =
  175. lexeme_d[ (+digit_p)[push_int(self.code)] ]
  176. ;
  177. factor =
  178. integer
  179. | '(' >> expression >> ')'
  180. | ('-' >> factor)[push_op(OP_NEG, self.code)]
  181. | ('+' >> factor)
  182. ;
  183. term =
  184. factor
  185. >> *( ('*' >> factor)[push_op(OP_MUL, self.code)]
  186. | ('/' >> factor)[push_op(OP_DIV, self.code)]
  187. )
  188. ;
  189. expression =
  190. term
  191. >> *( ('+' >> term)[push_op(OP_ADD, self.code)]
  192. | ('-' >> term)[push_op(OP_SUB, self.code)]
  193. )
  194. ;
  195. }
  196. rule<ScannerT> expression, term, factor, integer;
  197. rule<ScannerT> const&
  198. start() const { return expression; }
  199. };
  200. vector<int>& code;
  201. };
  202. ////////////////////////////////////////////////////////////////////////////
  203. //
  204. // Main program
  205. //
  206. ////////////////////////////////////////////////////////////////////////////
  207. int
  208. main()
  209. {
  210. cout << "/////////////////////////////////////////////////////////\n\n";
  211. cout << "\t\tA simple virtual machine...\n\n";
  212. cout << "/////////////////////////////////////////////////////////\n\n";
  213. cout << "Type an expression...or [q or Q] to quit\n\n";
  214. vmachine mach; // Our virtual machine
  215. vector<int> code; // Our VM code
  216. calculator calc(code); // Our parser
  217. string str;
  218. while (getline(cin, str))
  219. {
  220. if (str.empty() || str[0] == 'q' || str[0] == 'Q')
  221. break;
  222. code.clear();
  223. if (compile(calc, str.c_str()))
  224. {
  225. mach.execute(&*code.begin());
  226. cout << "\n\nresult = " << mach.top() << "\n\n";
  227. }
  228. }
  229. cout << "Bye... :-) \n\n";
  230. return 0;
  231. }