calc4.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  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. // A Calculator example demonstrating generation of AST. The AST,
  9. // once created, is traversed, 1) To print its contents and
  10. // 2) To evaluate the result.
  11. //
  12. // [ JDG April 28, 2008 ] For BoostCon 2008
  13. // [ JDG February 18, 2011 ] Pure attributes. No semantic actions.
  14. //
  15. ///////////////////////////////////////////////////////////////////////////////
  16. // Spirit v2.5 allows you to suppress automatic generation
  17. // of predefined terminals to speed up complation. With
  18. // BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are
  19. // responsible in creating instances of the terminals that
  20. // you need (e.g. see qi::uint_type uint_ below).
  21. #define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
  22. #if defined(_MSC_VER)
  23. # pragma warning(disable: 4345)
  24. #endif
  25. #include <boost/config/warning_disable.hpp>
  26. #include <boost/spirit/include/qi.hpp>
  27. #include <boost/variant/recursive_variant.hpp>
  28. #include <boost/variant/apply_visitor.hpp>
  29. #include <boost/fusion/include/adapt_struct.hpp>
  30. #include <boost/foreach.hpp>
  31. #include <iostream>
  32. #include <string>
  33. namespace client { namespace ast
  34. {
  35. ///////////////////////////////////////////////////////////////////////////
  36. // The AST
  37. ///////////////////////////////////////////////////////////////////////////
  38. struct nil {};
  39. struct signed_;
  40. struct program;
  41. typedef boost::variant<
  42. nil
  43. , unsigned int
  44. , boost::recursive_wrapper<signed_>
  45. , boost::recursive_wrapper<program>
  46. >
  47. operand;
  48. struct signed_
  49. {
  50. char sign;
  51. operand operand_;
  52. };
  53. struct operation
  54. {
  55. char operator_;
  56. operand operand_;
  57. };
  58. struct program
  59. {
  60. operand first;
  61. std::list<operation> rest;
  62. };
  63. }}
  64. BOOST_FUSION_ADAPT_STRUCT(
  65. client::ast::signed_,
  66. (char, sign)
  67. (client::ast::operand, operand_)
  68. )
  69. BOOST_FUSION_ADAPT_STRUCT(
  70. client::ast::operation,
  71. (char, operator_)
  72. (client::ast::operand, operand_)
  73. )
  74. BOOST_FUSION_ADAPT_STRUCT(
  75. client::ast::program,
  76. (client::ast::operand, first)
  77. (std::list<client::ast::operation>, rest)
  78. )
  79. namespace client { namespace ast
  80. {
  81. ///////////////////////////////////////////////////////////////////////////
  82. // The AST Printer
  83. ///////////////////////////////////////////////////////////////////////////
  84. struct printer
  85. {
  86. typedef void result_type;
  87. void operator()(nil) const {}
  88. void operator()(unsigned int n) const { std::cout << n; }
  89. void operator()(operation const& x) const
  90. {
  91. boost::apply_visitor(*this, x.operand_);
  92. switch (x.operator_)
  93. {
  94. case '+': std::cout << " add"; break;
  95. case '-': std::cout << " subt"; break;
  96. case '*': std::cout << " mult"; break;
  97. case '/': std::cout << " div"; break;
  98. }
  99. }
  100. void operator()(signed_ const& x) const
  101. {
  102. boost::apply_visitor(*this, x.operand_);
  103. switch (x.sign)
  104. {
  105. case '-': std::cout << " neg"; break;
  106. case '+': std::cout << " pos"; break;
  107. }
  108. }
  109. void operator()(program const& x) const
  110. {
  111. boost::apply_visitor(*this, x.first);
  112. BOOST_FOREACH(operation const& oper, x.rest)
  113. {
  114. std::cout << ' ';
  115. (*this)(oper);
  116. }
  117. }
  118. };
  119. ///////////////////////////////////////////////////////////////////////////
  120. // The AST evaluator
  121. ///////////////////////////////////////////////////////////////////////////
  122. struct eval
  123. {
  124. typedef int result_type;
  125. int operator()(nil) const { BOOST_ASSERT(0); return 0; }
  126. int operator()(unsigned int n) const { return n; }
  127. int operator()(operation const& x, int lhs) const
  128. {
  129. int rhs = boost::apply_visitor(*this, x.operand_);
  130. switch (x.operator_)
  131. {
  132. case '+': return lhs + rhs;
  133. case '-': return lhs - rhs;
  134. case '*': return lhs * rhs;
  135. case '/': return lhs / rhs;
  136. }
  137. BOOST_ASSERT(0);
  138. return 0;
  139. }
  140. int operator()(signed_ const& x) const
  141. {
  142. int rhs = boost::apply_visitor(*this, x.operand_);
  143. switch (x.sign)
  144. {
  145. case '-': return -rhs;
  146. case '+': return +rhs;
  147. }
  148. BOOST_ASSERT(0);
  149. return 0;
  150. }
  151. int operator()(program const& x) const
  152. {
  153. int state = boost::apply_visitor(*this, x.first);
  154. BOOST_FOREACH(operation const& oper, x.rest)
  155. {
  156. state = (*this)(oper, state);
  157. }
  158. return state;
  159. }
  160. };
  161. }}
  162. namespace client
  163. {
  164. namespace qi = boost::spirit::qi;
  165. namespace ascii = boost::spirit::ascii;
  166. ///////////////////////////////////////////////////////////////////////////////
  167. // The calculator grammar
  168. ///////////////////////////////////////////////////////////////////////////////
  169. template <typename Iterator>
  170. struct calculator : qi::grammar<Iterator, ast::program(), ascii::space_type>
  171. {
  172. calculator() : calculator::base_type(expression)
  173. {
  174. qi::uint_type uint_;
  175. qi::char_type char_;
  176. expression =
  177. term
  178. >> *( (char_('+') >> term)
  179. | (char_('-') >> term)
  180. )
  181. ;
  182. term =
  183. factor
  184. >> *( (char_('*') >> factor)
  185. | (char_('/') >> factor)
  186. )
  187. ;
  188. factor =
  189. uint_
  190. | '(' >> expression >> ')'
  191. | (char_('-') >> factor)
  192. | (char_('+') >> factor)
  193. ;
  194. }
  195. qi::rule<Iterator, ast::program(), ascii::space_type> expression;
  196. qi::rule<Iterator, ast::program(), ascii::space_type> term;
  197. qi::rule<Iterator, ast::operand(), ascii::space_type> factor;
  198. };
  199. }
  200. ///////////////////////////////////////////////////////////////////////////////
  201. // Main program
  202. ///////////////////////////////////////////////////////////////////////////////
  203. int
  204. main()
  205. {
  206. std::cout << "/////////////////////////////////////////////////////////\n\n";
  207. std::cout << "Expression parser...\n\n";
  208. std::cout << "/////////////////////////////////////////////////////////\n\n";
  209. std::cout << "Type an expression...or [q or Q] to quit\n\n";
  210. typedef std::string::const_iterator iterator_type;
  211. typedef client::calculator<iterator_type> calculator;
  212. typedef client::ast::program ast_program;
  213. typedef client::ast::printer ast_print;
  214. typedef client::ast::eval ast_eval;
  215. std::string str;
  216. while (std::getline(std::cin, str))
  217. {
  218. if (str.empty() || str[0] == 'q' || str[0] == 'Q')
  219. break;
  220. calculator calc; // Our grammar
  221. ast_program program; // Our program (AST)
  222. ast_print print; // Prints the program
  223. ast_eval eval; // Evaluates the program
  224. std::string::const_iterator iter = str.begin();
  225. std::string::const_iterator end = str.end();
  226. boost::spirit::ascii::space_type space;
  227. bool r = phrase_parse(iter, end, calc, space, program);
  228. if (r && iter == end)
  229. {
  230. std::cout << "-------------------------\n";
  231. std::cout << "Parsing succeeded\n";
  232. print(program);
  233. std::cout << "\nResult: " << eval(program) << std::endl;
  234. std::cout << "-------------------------\n";
  235. }
  236. else
  237. {
  238. std::string rest(iter, end);
  239. std::cout << "-------------------------\n";
  240. std::cout << "Parsing failed\n";
  241. std::cout << "stopped at: \" " << rest << "\"\n";
  242. std::cout << "-------------------------\n";
  243. }
  244. }
  245. std::cout << "Bye... :-) \n\n";
  246. return 0;
  247. }