calc6.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /*=============================================================================
  2. Copyright (c) 2001-2014 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 (and X3).
  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. // [ JDG April 9, 2014 ] Spirit X3 (from qi calc6)
  17. //
  18. ///////////////////////////////////////////////////////////////////////////////
  19. ///////////////////////////////////////////////////////////////////////////////
  20. // Uncomment this if you want to enable debugging
  21. //#define BOOST_SPIRIT_X3_DEBUG
  22. #if defined(_MSC_VER)
  23. # pragma warning(disable: 4345)
  24. #endif
  25. #include <boost/config/warning_disable.hpp>
  26. #include <boost/spirit/home/x3.hpp>
  27. #include <boost/spirit/home/x3/support/ast/variant.hpp>
  28. #include <boost/fusion/include/adapt_struct.hpp>
  29. #include <iostream>
  30. #include <string>
  31. #include <list>
  32. #include <numeric>
  33. namespace x3 = boost::spirit::x3;
  34. namespace client { namespace ast
  35. {
  36. ///////////////////////////////////////////////////////////////////////////
  37. // The AST
  38. ///////////////////////////////////////////////////////////////////////////
  39. struct nil {};
  40. struct signed_;
  41. struct expression;
  42. struct operand : x3::variant<
  43. nil
  44. , unsigned int
  45. , x3::forward_ast<signed_>
  46. , x3::forward_ast<expression>
  47. >
  48. {
  49. using base_type::base_type;
  50. using base_type::operator=;
  51. };
  52. struct signed_
  53. {
  54. char sign;
  55. operand operand_;
  56. };
  57. struct operation
  58. {
  59. char operator_;
  60. operand operand_;
  61. };
  62. struct expression
  63. {
  64. operand first;
  65. std::list<operation> rest;
  66. };
  67. // print function for debugging
  68. inline std::ostream& operator<<(std::ostream& out, nil) { out << "nil"; return out; }
  69. }}
  70. BOOST_FUSION_ADAPT_STRUCT(client::ast::signed_,
  71. sign, operand_
  72. )
  73. BOOST_FUSION_ADAPT_STRUCT(client::ast::operation,
  74. operator_, operand_
  75. )
  76. BOOST_FUSION_ADAPT_STRUCT(client::ast::expression,
  77. first, rest
  78. )
  79. namespace client
  80. {
  81. ///////////////////////////////////////////////////////////////////////////
  82. // The Virtual Machine
  83. ///////////////////////////////////////////////////////////////////////////
  84. enum byte_code
  85. {
  86. op_neg, // negate the top stack entry
  87. op_add, // add top two stack entries
  88. op_sub, // subtract top two stack entries
  89. op_mul, // multiply top two stack entries
  90. op_div, // divide top two stack entries
  91. op_int, // push constant integer into the stack
  92. };
  93. class vmachine
  94. {
  95. public:
  96. vmachine(unsigned stackSize = 4096)
  97. : stack(stackSize)
  98. , stack_ptr(stack.begin())
  99. {
  100. }
  101. int top() const { return stack_ptr[-1]; };
  102. void execute(std::vector<int> const& code);
  103. private:
  104. std::vector<int> stack;
  105. std::vector<int>::iterator stack_ptr;
  106. };
  107. void vmachine::execute(std::vector<int> const& code)
  108. {
  109. std::vector<int>::const_iterator pc = code.begin();
  110. stack_ptr = stack.begin();
  111. while (pc != code.end())
  112. {
  113. switch (*pc++)
  114. {
  115. case op_neg:
  116. stack_ptr[-1] = -stack_ptr[-1];
  117. break;
  118. case op_add:
  119. --stack_ptr;
  120. stack_ptr[-1] += stack_ptr[0];
  121. break;
  122. case op_sub:
  123. --stack_ptr;
  124. stack_ptr[-1] -= stack_ptr[0];
  125. break;
  126. case op_mul:
  127. --stack_ptr;
  128. stack_ptr[-1] *= stack_ptr[0];
  129. break;
  130. case op_div:
  131. --stack_ptr;
  132. stack_ptr[-1] /= stack_ptr[0];
  133. break;
  134. case op_int:
  135. *stack_ptr++ = *pc++;
  136. break;
  137. }
  138. }
  139. }
  140. ///////////////////////////////////////////////////////////////////////////
  141. // The Compiler
  142. ///////////////////////////////////////////////////////////////////////////
  143. struct compiler
  144. {
  145. typedef void result_type;
  146. std::vector<int>& code;
  147. compiler(std::vector<int>& code)
  148. : code(code) {}
  149. void operator()(ast::nil) const { BOOST_ASSERT(0); }
  150. void operator()(unsigned int n) const
  151. {
  152. code.push_back(op_int);
  153. code.push_back(n);
  154. }
  155. void operator()(ast::operation const& x) const
  156. {
  157. boost::apply_visitor(*this, x.operand_);
  158. switch (x.operator_)
  159. {
  160. case '+': code.push_back(op_add); break;
  161. case '-': code.push_back(op_sub); break;
  162. case '*': code.push_back(op_mul); break;
  163. case '/': code.push_back(op_div); break;
  164. default: BOOST_ASSERT(0); break;
  165. }
  166. }
  167. void operator()(ast::signed_ const& x) const
  168. {
  169. boost::apply_visitor(*this, x.operand_);
  170. switch (x.sign)
  171. {
  172. case '-': code.push_back(op_neg); break;
  173. case '+': break;
  174. default: BOOST_ASSERT(0); break;
  175. }
  176. }
  177. void operator()(ast::expression const& x) const
  178. {
  179. boost::apply_visitor(*this, x.first);
  180. for (ast::operation const& oper : x.rest)
  181. {
  182. (*this)(oper);
  183. }
  184. }
  185. };
  186. ///////////////////////////////////////////////////////////////////////////////
  187. // The calculator grammar
  188. ///////////////////////////////////////////////////////////////////////////////
  189. namespace calculator_grammar
  190. {
  191. using x3::uint_;
  192. using x3::char_;
  193. struct expression_class;
  194. struct term_class;
  195. struct factor_class;
  196. x3::rule<expression_class, ast::expression> const expression("expression");
  197. x3::rule<term_class, ast::expression> const term("term");
  198. x3::rule<factor_class, ast::operand> const factor("factor");
  199. auto const expression_def =
  200. term
  201. >> *( (char_('+') > term)
  202. | (char_('-') > term)
  203. )
  204. ;
  205. auto const term_def =
  206. factor
  207. >> *( (char_('*') > factor)
  208. | (char_('/') > factor)
  209. )
  210. ;
  211. auto const factor_def =
  212. uint_
  213. | '(' > expression > ')'
  214. | (char_('-') > factor)
  215. | (char_('+') > factor)
  216. ;
  217. BOOST_SPIRIT_DEFINE(
  218. expression
  219. , term
  220. , factor
  221. );
  222. struct expression_class
  223. {
  224. // Our error handler
  225. template <typename Iterator, typename Exception, typename Context>
  226. x3::error_handler_result
  227. on_error(Iterator&, Iterator const& last, Exception const& x, Context const& context)
  228. {
  229. std::cout
  230. << "Error! Expecting: "
  231. << x.which()
  232. << " here: \""
  233. << std::string(x.where(), last)
  234. << "\""
  235. << std::endl
  236. ;
  237. return x3::error_handler_result::fail;
  238. }
  239. };
  240. auto calculator = expression;
  241. }
  242. using calculator_grammar::calculator;
  243. }
  244. ///////////////////////////////////////////////////////////////////////////////
  245. // Main program
  246. ///////////////////////////////////////////////////////////////////////////////
  247. int
  248. main()
  249. {
  250. std::cout << "/////////////////////////////////////////////////////////\n\n";
  251. std::cout << "Expression parser...\n\n";
  252. std::cout << "/////////////////////////////////////////////////////////\n\n";
  253. std::cout << "Type an expression...or [q or Q] to quit\n\n";
  254. typedef std::string::const_iterator iterator_type;
  255. typedef client::ast::expression ast_expression;
  256. typedef client::compiler compiler;
  257. std::string str;
  258. while (std::getline(std::cin, str))
  259. {
  260. if (str.empty() || str[0] == 'q' || str[0] == 'Q')
  261. break;
  262. client::vmachine mach; // Our virtual machine
  263. std::vector<int> code; // Our VM code
  264. auto& calc = client::calculator; // Our grammar
  265. ast_expression expression; // Our program (AST)
  266. compiler compile(code); // Compiles the program
  267. iterator_type iter = str.begin();
  268. iterator_type const end = str.end();
  269. boost::spirit::x3::ascii::space_type space;
  270. bool r = phrase_parse(iter, end, calc, space, expression);
  271. if (r && iter == end)
  272. {
  273. std::cout << "-------------------------\n";
  274. std::cout << "Parsing succeeded\n";
  275. compile(expression);
  276. mach.execute(code);
  277. std::cout << "\nResult: " << mach.top() << std::endl;
  278. std::cout << "-------------------------\n";
  279. }
  280. else
  281. {
  282. std::string rest(iter, end);
  283. std::cout << "-------------------------\n";
  284. std::cout << "Parsing failed\n";
  285. std::cout << "-------------------------\n";
  286. }
  287. }
  288. std::cout << "Bye... :-) \n\n";
  289. return 0;
  290. }