fork download
  1. /*=============================================================================
  2.   Copyright (c) 2001-2013 Joel de Guzman
  3.  
  4.   Distributed under the Boost Software License, Version 1.0. (See accompanying
  5.   file LICENSE_1_0.txt or copy at http://w...content-available-to-author-only...t.org/LICENSE_1_0.txt)
  6. =============================================================================*/
  7. ///////////////////////////////////////////////////////////////////////////////
  8. //
  9. // A Calculator example demonstrating generation of AST. The AST,
  10. // once created, is traversed, 1) To print its contents and
  11. // 2) To evaluate the result.
  12. //
  13. // [ JDG April 28, 2008 ] For BoostCon 2008
  14. // [ JDG February 18, 2011 ] Pure attributes. No semantic actions.
  15. // [ JDG January 9, 2013 ] Spirit X3
  16. //
  17. ///////////////////////////////////////////////////////////////////////////////
  18.  
  19. #if defined(_MSC_VER)
  20. # pragma warning(disable: 4345)
  21. #endif
  22.  
  23. #include <boost/config/warning_disable.hpp>
  24. #include <boost/range/numeric.hpp>
  25. #include <boost/spirit/home/x3.hpp>
  26. #include <boost/variant/recursive_variant.hpp>
  27. #include <boost/variant/apply_visitor.hpp>
  28. #include <boost/fusion/include/adapt_struct.hpp>
  29. #include <boost/foreach.hpp>
  30.  
  31. #include <iostream>
  32. #include <string>
  33. #include <list>
  34.  
  35. namespace client { namespace ast
  36. {
  37. ///////////////////////////////////////////////////////////////////////////
  38. // The AST
  39. ///////////////////////////////////////////////////////////////////////////
  40. struct nil {};
  41. struct signed_;
  42. struct program;
  43.  
  44. typedef boost::variant<
  45. nil
  46. , unsigned int
  47. , boost::recursive_wrapper<signed_>
  48. , boost::recursive_wrapper<program>
  49. >
  50. operand;
  51.  
  52. struct signed_
  53. {
  54. char sign;
  55. operand operand_;
  56. };
  57.  
  58. struct operation
  59. {
  60. char operator_;
  61. operand operand_;
  62. };
  63.  
  64. struct program
  65. {
  66. operand first;
  67. std::list<operation> rest;
  68. };
  69. }}
  70.  
  71. namespace client{ namespace ast{
  72. struct ts{
  73. //ts(){}
  74. //ts(unsigned int) {}
  75. unsigned int id;
  76. };
  77. struct fnc;
  78. typedef boost::variant<ts, boost::recursive_wrapper<fnc> > node;
  79. struct fnc{
  80. std::vector<char> id;
  81. std::vector<node> args;
  82. };
  83. }}
  84. BOOST_FUSION_ADAPT_STRUCT(
  85. client::ast::ts,
  86. (unsigned int, id)
  87. )
  88. BOOST_FUSION_ADAPT_STRUCT(
  89. client::ast::fnc,
  90. (std::vector<char>, id)
  91. (std::vector<client::ast::node>, args)
  92. )
  93.  
  94. BOOST_FUSION_ADAPT_STRUCT(
  95. client::ast::signed_,
  96. (char, sign)
  97. (client::ast::operand, operand_)
  98. )
  99.  
  100. BOOST_FUSION_ADAPT_STRUCT(
  101. client::ast::operation,
  102. (char, operator_)
  103. (client::ast::operand, operand_)
  104. )
  105.  
  106. BOOST_FUSION_ADAPT_STRUCT(
  107. client::ast::program,
  108. (client::ast::operand, first)
  109. (std::list<client::ast::operation>, rest)
  110. )
  111.  
  112. namespace client { namespace ast
  113. {
  114. ///////////////////////////////////////////////////////////////////////////
  115. // The AST Printer
  116. ///////////////////////////////////////////////////////////////////////////
  117. struct printer
  118. {
  119. typedef void result_type;
  120.  
  121. void operator()(nil) const {}
  122. void operator()(unsigned int n) const { std::cout << n; }
  123.  
  124. void operator()(operation const& x) const
  125. {
  126. boost::apply_visitor(*this, x.operand_);
  127. switch (x.operator_)
  128. {
  129. case '+': std::cout << " add"; break;
  130. case '-': std::cout << " subt"; break;
  131. case '*': std::cout << " mult"; break;
  132. case '/': std::cout << " div"; break;
  133. }
  134. }
  135.  
  136. void operator()(signed_ const& x) const
  137. {
  138. boost::apply_visitor(*this, x.operand_);
  139. switch (x.sign)
  140. {
  141. case '-': std::cout << " neg"; break;
  142. case '+': std::cout << " pos"; break;
  143. }
  144. }
  145.  
  146. void operator()(program const& x) const
  147. {
  148. boost::apply_visitor(*this, x.first);
  149. BOOST_FOREACH(operation const& oper, x.rest)
  150. {
  151. std::cout << ' ';
  152. (*this)(oper);
  153. }
  154. }
  155. };
  156.  
  157. ///////////////////////////////////////////////////////////////////////////
  158. // The AST evaluator
  159. ///////////////////////////////////////////////////////////////////////////
  160. struct eval
  161. {
  162. typedef int result_type;
  163.  
  164. int operator()(nil) const { BOOST_ASSERT(0); return 0; }
  165. int operator()(unsigned int n) const { return n; }
  166.  
  167. int operator()(int lhs, operation const& x) const
  168. {
  169. int rhs = boost::apply_visitor(*this, x.operand_);
  170. switch (x.operator_)
  171. {
  172. case '+': return lhs + rhs;
  173. case '-': return lhs - rhs;
  174. case '*': return lhs * rhs;
  175. case '/': return lhs / rhs;
  176. }
  177. BOOST_ASSERT(0);
  178. return 0;
  179. }
  180.  
  181. int operator()(signed_ const& x) const
  182. {
  183. int rhs = boost::apply_visitor(*this, x.operand_);
  184. switch (x.sign)
  185. {
  186. case '-': return -rhs;
  187. case '+': return +rhs;
  188. }
  189. BOOST_ASSERT(0);
  190. return 0;
  191. }
  192.  
  193. int operator()(program const& x) const
  194. {
  195. return boost::accumulate( x.rest
  196. , boost::apply_visitor(*this, x.first)
  197. , *this);
  198. }
  199. };
  200. }}
  201.  
  202. namespace client
  203. {
  204. namespace x3 = boost::spirit::x3;
  205. namespace calc_grammar{
  206. using x3::uint_;
  207. using x3::alpha;
  208. using x3::alnum;
  209. using x3::lit;
  210. using x3::char_;
  211. x3::rule<class funct, ast::fnc> const funct("function");
  212. x3::rule<class ts, ast::ts> const ts("timeseries");
  213. x3::rule<class funct_name, std::vector<char>> const funct_name("function_name");
  214.  
  215. auto const funct_def = funct_name >> lit('(') >> -((ts|funct) % lit(',')) >> lit(')');
  216. auto const ts_def = lit('#') >> uint_ >> lit('#');
  217. auto const funct_name_def = lit('@') >> alpha >> *(alnum|char_('_'));
  218. auto const calc = x3::grammar(
  219. "calc",
  220. funct = funct_def,
  221. ts = ts_def,
  222. funct_name = funct_name_def
  223. );
  224. }
  225.  
  226. ///////////////////////////////////////////////////////////////////////////////
  227. // The calculator grammar
  228. ///////////////////////////////////////////////////////////////////////////////
  229. namespace calculator_grammar
  230. {
  231. using x3::uint_;
  232. using x3::char_;
  233.  
  234. x3::rule<class expression, ast::program> const expression("expression");
  235. x3::rule<class term, ast::program> const term("term");
  236. x3::rule<class factor, ast::operand> const factor("factor");
  237.  
  238. auto const expression_def =
  239. term
  240. >> *( (char_('+') >> term)
  241. | (char_('-') >> term)
  242. )
  243. ;
  244.  
  245. auto const term_def =
  246. factor
  247. >> *( (char_('*') >> factor)
  248. | (char_('/') >> factor)
  249. )
  250. ;
  251.  
  252. auto const factor_def =
  253. uint_
  254. | '(' >> expression >> ')'
  255. | (char_('-') >> factor)
  256. | (char_('+') >> factor)
  257. ;
  258.  
  259. auto const calculator = x3::grammar(
  260. "calculator"
  261. , expression = expression_def
  262. , term = term_def
  263. , factor = factor_def
  264. );
  265. }
  266.  
  267. using calculator_grammar::calculator;
  268. using calc_grammar::calc;
  269.  
  270. }
  271.  
  272. ///////////////////////////////////////////////////////////////////////////////
  273. // Main program
  274. ///////////////////////////////////////////////////////////////////////////////
  275. int
  276. main()
  277. {
  278. std::cout << "/////////////////////////////////////////////////////////\n\n";
  279. std::cout << "Expression parser...\n\n";
  280. std::cout << "/////////////////////////////////////////////////////////\n\n";
  281. std::cout << "Type an expression...or [q or Q] to quit\n\n";
  282.  
  283. typedef std::string::const_iterator iterator_type;
  284. typedef client::ast::program ast_program;
  285. typedef client::ast::printer ast_print;
  286. typedef client::ast::eval ast_eval;
  287.  
  288. std::string str;
  289. while (std::getline(std::cin, str))
  290. {
  291. if (str.empty() || str[0] == 'q' || str[0] == 'Q')
  292. break;
  293.  
  294. auto& calc = client::calc; // Our grammar
  295. client::ast::fnc fnc; // fnx
  296. ast_program program; // Our program (AST)
  297. ast_print print; // Prints the program
  298. ast_eval eval; // Evaluates the program
  299.  
  300. std::string::const_iterator iter = str.begin();
  301. std::string::const_iterator end = str.end();
  302. boost::spirit::x3::ascii::space_type space;
  303. bool r = phrase_parse(iter, end, calc, space, fnc);
  304.  
  305. if (r && iter == end)
  306. {
  307. std::cout << "-------------------------\n";
  308. std::cout << "Parsing succeeded\n";
  309. print(program);
  310. std::cout << "\nResult: " << eval(program) << std::endl;
  311. std::cout << "-------------------------\n";
  312. }
  313. else
  314. {
  315. std::string rest(iter, end);
  316. std::cout << "-------------------------\n";
  317. std::cout << "Parsing failed\n";
  318. std::cout << "stopped at: \"" << rest << "\"\n";
  319. std::cout << "-------------------------\n";
  320. }
  321. }
  322.  
  323. std::cout << "Bye... :-) \n\n";
  324. return 0;
  325. }
Compilation error #stdin compilation error #stdout 0s 0KB
stdin
Standard input is empty
compilation info
prog.cpp:23:44: fatal error: boost/config/warning_disable.hpp: No such file or directory
compilation terminated.
stdout
Standard output is empty