calc6.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  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. ///////////////////////////////////////////////////////////////////////////////
  7. //
  8. // Yet another calculator example! This time, we will compile to a simple
  9. // virtual machine. This is actually one of the very first Spirit example
  10. // circa 2000. Now, it's ported to Spirit2.
  11. //
  12. // [ JDG Sometime 2000 ] pre-boost
  13. // [ JDG September 18, 2002 ] spirit1
  14. // [ JDG April 8, 2007 ] spirit2
  15. // [ JDG February 18, 2011 ] Pure attributes. No semantic actions.
  16. //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. ///////////////////////////////////////////////////////////////////////////////
  19. // Spirit v2.5 allows you to suppress automatic generation
  20. // of predefined terminals to speed up complation. With
  21. // BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are
  22. // responsible in creating instances of the terminals that
  23. // you need (e.g. see qi::uint_type uint_ below).
  24. #define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
  25. ///////////////////////////////////////////////////////////////////////////////
  26. ///////////////////////////////////////////////////////////////////////////////
  27. // Define this to enable debugging
  28. //#define BOOST_SPIRIT_QI_DEBUG
  29. ///////////////////////////////////////////////////////////////////////////////
  30. // Uncomment this if you want to enable debugging
  31. //#define BOOST_SPIRIT_QI_DEBUG
  32. ///////////////////////////////////////////////////////////////////////////////
  33. #if defined(_MSC_VER)
  34. # pragma warning(disable: 4345)
  35. #endif
  36. #include <boost/config/warning_disable.hpp>
  37. #include <boost/spirit/include/qi.hpp>
  38. #include <boost/variant/recursive_variant.hpp>
  39. #include <boost/variant/apply_visitor.hpp>
  40. #include <boost/fusion/include/adapt_struct.hpp>
  41. #include <boost/spirit/include/phoenix_function.hpp>
  42. #include <boost/foreach.hpp>
  43. #include <iostream>
  44. #include <string>
  45. namespace client { namespace ast
  46. {
  47. ///////////////////////////////////////////////////////////////////////////
  48. // The AST
  49. ///////////////////////////////////////////////////////////////////////////
  50. struct nil {};
  51. struct signed_;
  52. struct expression;
  53. typedef boost::variant<
  54. nil
  55. , unsigned int
  56. , boost::recursive_wrapper<signed_>
  57. , boost::recursive_wrapper<expression>
  58. >
  59. operand;
  60. struct signed_
  61. {
  62. char sign;
  63. operand operand_;
  64. };
  65. struct operation
  66. {
  67. char operator_;
  68. operand operand_;
  69. };
  70. struct expression
  71. {
  72. operand first;
  73. std::list<operation> rest;
  74. };
  75. // print function for debugging
  76. inline std::ostream& operator<<(std::ostream& out, nil) { out << "nil"; return out; }
  77. }}
  78. BOOST_FUSION_ADAPT_STRUCT(
  79. client::ast::signed_,
  80. (char, sign)
  81. (client::ast::operand, operand_)
  82. )
  83. BOOST_FUSION_ADAPT_STRUCT(
  84. client::ast::operation,
  85. (char, operator_)
  86. (client::ast::operand, operand_)
  87. )
  88. BOOST_FUSION_ADAPT_STRUCT(
  89. client::ast::expression,
  90. (client::ast::operand, first)
  91. (std::list<client::ast::operation>, rest)
  92. )
  93. namespace client
  94. {
  95. ///////////////////////////////////////////////////////////////////////////
  96. // The Virtual Machine
  97. ///////////////////////////////////////////////////////////////////////////
  98. enum byte_code
  99. {
  100. op_neg, // negate the top stack entry
  101. op_add, // add top two stack entries
  102. op_sub, // subtract top two stack entries
  103. op_mul, // multiply top two stack entries
  104. op_div, // divide top two stack entries
  105. op_int, // push constant integer into the stack
  106. };
  107. class vmachine
  108. {
  109. public:
  110. vmachine(unsigned stackSize = 4096)
  111. : stack(stackSize)
  112. , stack_ptr(stack.begin())
  113. {
  114. }
  115. int top() const { return stack_ptr[-1]; };
  116. void execute(std::vector<int> const& code);
  117. private:
  118. std::vector<int> stack;
  119. std::vector<int>::iterator stack_ptr;
  120. };
  121. void vmachine::execute(std::vector<int> const& code)
  122. {
  123. std::vector<int>::const_iterator pc = code.begin();
  124. stack_ptr = stack.begin();
  125. while (pc != code.end())
  126. {
  127. switch (*pc++)
  128. {
  129. case op_neg:
  130. stack_ptr[-1] = -stack_ptr[-1];
  131. break;
  132. case op_add:
  133. --stack_ptr;
  134. stack_ptr[-1] += stack_ptr[0];
  135. break;
  136. case op_sub:
  137. --stack_ptr;
  138. stack_ptr[-1] -= stack_ptr[0];
  139. break;
  140. case op_mul:
  141. --stack_ptr;
  142. stack_ptr[-1] *= stack_ptr[0];
  143. break;
  144. case op_div:
  145. --stack_ptr;
  146. stack_ptr[-1] /= stack_ptr[0];
  147. break;
  148. case op_int:
  149. *stack_ptr++ = *pc++;
  150. break;
  151. }
  152. }
  153. }
  154. ///////////////////////////////////////////////////////////////////////////
  155. // The Compiler
  156. ///////////////////////////////////////////////////////////////////////////
  157. struct compiler
  158. {
  159. typedef void result_type;
  160. std::vector<int>& code;
  161. compiler(std::vector<int>& code)
  162. : code(code) {}
  163. void operator()(ast::nil) const { BOOST_ASSERT(0); }
  164. void operator()(unsigned int n) const
  165. {
  166. code.push_back(op_int);
  167. code.push_back(n);
  168. }
  169. void operator()(ast::operation const& x) const
  170. {
  171. boost::apply_visitor(*this, x.operand_);
  172. switch (x.operator_)
  173. {
  174. case '+': code.push_back(op_add); break;
  175. case '-': code.push_back(op_sub); break;
  176. case '*': code.push_back(op_mul); break;
  177. case '/': code.push_back(op_div); break;
  178. default: BOOST_ASSERT(0); break;
  179. }
  180. }
  181. void operator()(ast::signed_ const& x) const
  182. {
  183. boost::apply_visitor(*this, x.operand_);
  184. switch (x.sign)
  185. {
  186. case '-': code.push_back(op_neg); break;
  187. case '+': break;
  188. default: BOOST_ASSERT(0); break;
  189. }
  190. }
  191. void operator()(ast::expression const& x) const
  192. {
  193. boost::apply_visitor(*this, x.first);
  194. BOOST_FOREACH(ast::operation const& oper, x.rest)
  195. {
  196. (*this)(oper);
  197. }
  198. }
  199. };
  200. namespace qi = boost::spirit::qi;
  201. namespace ascii = boost::spirit::ascii;
  202. using boost::phoenix::function;
  203. ///////////////////////////////////////////////////////////////////////////////
  204. // The error handler
  205. ///////////////////////////////////////////////////////////////////////////////
  206. struct error_handler_
  207. {
  208. template <typename, typename, typename>
  209. struct result { typedef void type; };
  210. template <typename Iterator>
  211. void operator()(
  212. qi::info const& what
  213. , Iterator err_pos, Iterator last) const
  214. {
  215. std::cout
  216. << "Error! Expecting "
  217. << what // what failed?
  218. << " here: \""
  219. << std::string(err_pos, last) // iterators to error-pos, end
  220. << "\""
  221. << std::endl
  222. ;
  223. }
  224. };
  225. function<error_handler_> const error_handler = error_handler_();
  226. ///////////////////////////////////////////////////////////////////////////////
  227. // The calculator grammar
  228. ///////////////////////////////////////////////////////////////////////////////
  229. template <typename Iterator>
  230. struct calculator : qi::grammar<Iterator, ast::expression(), ascii::space_type>
  231. {
  232. calculator() : calculator::base_type(expression)
  233. {
  234. qi::char_type char_;
  235. qi::uint_type uint_;
  236. qi::_2_type _2;
  237. qi::_3_type _3;
  238. qi::_4_type _4;
  239. using qi::on_error;
  240. using qi::fail;
  241. expression =
  242. term
  243. >> *( (char_('+') > term)
  244. | (char_('-') > term)
  245. )
  246. ;
  247. term =
  248. factor
  249. >> *( (char_('*') > factor)
  250. | (char_('/') > factor)
  251. )
  252. ;
  253. factor =
  254. uint_
  255. | '(' > expression > ')'
  256. | (char_('-') > factor)
  257. | (char_('+') > factor)
  258. ;
  259. // Debugging and error handling and reporting support.
  260. BOOST_SPIRIT_DEBUG_NODES(
  261. (expression)(term)(factor));
  262. // Error handling
  263. on_error<fail>(expression, error_handler(_4, _3, _2));
  264. }
  265. qi::rule<Iterator, ast::expression(), ascii::space_type> expression;
  266. qi::rule<Iterator, ast::expression(), ascii::space_type> term;
  267. qi::rule<Iterator, ast::operand(), ascii::space_type> factor;
  268. };
  269. }
  270. ///////////////////////////////////////////////////////////////////////////////
  271. // Main program
  272. ///////////////////////////////////////////////////////////////////////////////
  273. int
  274. main()
  275. {
  276. std::cout << "/////////////////////////////////////////////////////////\n\n";
  277. std::cout << "Expression parser...\n\n";
  278. std::cout << "/////////////////////////////////////////////////////////\n\n";
  279. std::cout << "Type an expression...or [q or Q] to quit\n\n";
  280. typedef std::string::const_iterator iterator_type;
  281. typedef client::calculator<iterator_type> calculator;
  282. typedef client::ast::expression ast_expression;
  283. typedef client::compiler compiler;
  284. std::string str;
  285. while (std::getline(std::cin, str))
  286. {
  287. if (str.empty() || str[0] == 'q' || str[0] == 'Q')
  288. break;
  289. client::vmachine mach; // Our virtual machine
  290. std::vector<int> code; // Our VM code
  291. calculator calc; // Our grammar
  292. ast_expression expression; // Our program (AST)
  293. compiler compile(code); // Compiles the program
  294. std::string::const_iterator iter = str.begin();
  295. std::string::const_iterator end = str.end();
  296. boost::spirit::ascii::space_type space;
  297. bool r = phrase_parse(iter, end, calc, space, expression);
  298. if (r && iter == end)
  299. {
  300. std::cout << "-------------------------\n";
  301. std::cout << "Parsing succeeded\n";
  302. compile(expression);
  303. mach.execute(code);
  304. std::cout << "\nResult: " << mach.top() << std::endl;
  305. std::cout << "-------------------------\n";
  306. }
  307. else
  308. {
  309. std::string rest(iter, end);
  310. std::cout << "-------------------------\n";
  311. std::cout << "Parsing failed\n";
  312. std::cout << "-------------------------\n";
  313. }
  314. }
  315. std::cout << "Bye... :-) \n\n";
  316. return 0;
  317. }