calc2_ast_rpn.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*=============================================================================
  2. Copyright (c) 2001-2010 Joel de Guzman
  3. Copyright (c) 2001-2010 Hartmut Kaiser
  4. Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. =============================================================================*/
  7. ///////////////////////////////////////////////////////////////////////////////
  8. //
  9. // A Calculator example demonstrating generation of AST which gets dumped into
  10. // a reverse polish notation afterwards.
  11. //
  12. // [ JDG April 28, 2008 ]
  13. // [ HK April 28, 2008 ]
  14. //
  15. ///////////////////////////////////////////////////////////////////////////////
  16. #include <boost/config/warning_disable.hpp>
  17. #include <iostream>
  18. #include <vector>
  19. #include <string>
  20. #include "calc2_ast.hpp"
  21. #include <boost/spirit/include/qi.hpp>
  22. #include <boost/spirit/include/karma.hpp>
  23. #include <boost/fusion/include/adapt_struct.hpp>
  24. using namespace boost::spirit;
  25. using namespace boost::spirit::ascii;
  26. ///////////////////////////////////////////////////////////////////////////////
  27. // Our calculator parser grammar
  28. ///////////////////////////////////////////////////////////////////////////////
  29. template <typename Iterator>
  30. struct calculator
  31. : qi::grammar<Iterator, expression_ast(), space_type>
  32. {
  33. calculator() : calculator::base_type(expression)
  34. {
  35. expression =
  36. term [_val = _1]
  37. >> *( ('+' >> term [_val += _1])
  38. | ('-' >> term [_val -= _1])
  39. )
  40. ;
  41. term =
  42. factor [_val = _1]
  43. >> *( ('*' >> factor [_val *= _1])
  44. | ('/' >> factor [_val /= _1])
  45. )
  46. ;
  47. factor =
  48. uint_ [_val = _1]
  49. | '(' >> expression [_val = _1] >> ')'
  50. | ('-' >> factor [_val = neg(_1)])
  51. | ('+' >> factor [_val = pos(_1)])
  52. ;
  53. }
  54. qi::rule<Iterator, expression_ast(), space_type> expression, term, factor;
  55. };
  56. // We need to tell fusion about our binary_op and unary_op structs
  57. // to make them a first-class fusion citizen
  58. //
  59. // Note: we register the members exactly in the same sequence as we need them
  60. // in the grammar
  61. BOOST_FUSION_ADAPT_STRUCT(
  62. binary_op,
  63. (expression_ast, left)
  64. (expression_ast, right)
  65. (char, op)
  66. )
  67. BOOST_FUSION_ADAPT_STRUCT(
  68. unary_op,
  69. (expression_ast, right)
  70. (char, op)
  71. )
  72. ///////////////////////////////////////////////////////////////////////////////
  73. // Our AST grammar for the generator, this prints the AST in reverse polish
  74. // notation
  75. ///////////////////////////////////////////////////////////////////////////////
  76. template <typename OuputIterator>
  77. struct ast_rpn
  78. : karma::grammar<OuputIterator, expression_ast(), space_type>
  79. {
  80. ast_rpn() : ast_rpn::base_type(ast_node)
  81. {
  82. ast_node %= int_ | binary_node | unary_node;
  83. binary_node %= ast_node << ast_node << char_;
  84. unary_node %= '(' << ast_node << char_ << ')';
  85. }
  86. karma::rule<OuputIterator, expression_ast(), space_type> ast_node;
  87. karma::rule<OuputIterator, binary_op(), space_type> binary_node;
  88. karma::rule<OuputIterator, unary_op(), space_type> unary_node;
  89. };
  90. ///////////////////////////////////////////////////////////////////////////////
  91. // Main program
  92. ///////////////////////////////////////////////////////////////////////////////
  93. int
  94. main()
  95. {
  96. std::cout << "/////////////////////////////////////////////////////////\n\n";
  97. std::cout << "RPN generator for simple expressions...\n\n";
  98. std::cout << "/////////////////////////////////////////////////////////\n\n";
  99. std::cout << "Type an expression...or [q or Q] to quit\n\n";
  100. // Our parser grammar definitions
  101. typedef std::string::const_iterator iterator_type;
  102. typedef calculator<iterator_type> calculator;
  103. calculator calc;
  104. // Our generator grammar definitions
  105. typedef std::back_insert_iterator<std::string> output_iterator_type;
  106. typedef ast_rpn<output_iterator_type> ast_rpn;
  107. ast_rpn ast_grammar;
  108. std::string str;
  109. while (std::getline(std::cin, str))
  110. {
  111. if (str.empty() || str[0] == 'q' || str[0] == 'Q')
  112. break;
  113. expression_ast ast; // this will hold the generated AST
  114. std::string::const_iterator iter = str.begin();
  115. std::string::const_iterator end = str.end();
  116. bool r = qi::phrase_parse(iter, end, calc, space, ast);
  117. if (r && iter == end)
  118. {
  119. std::string generated;
  120. output_iterator_type outit(generated);
  121. r = karma::generate_delimited(outit, ast_grammar, space, ast);
  122. if (r)
  123. {
  124. std::cout << "RPN for '" << str << "': \n" << generated
  125. << std::endl;
  126. std::cout << "-------------------------\n";
  127. }
  128. else
  129. {
  130. std::cout << "-------------------------\n";
  131. std::cout << "Generating failed\n";
  132. std::cout << "-------------------------\n";
  133. }
  134. }
  135. else
  136. {
  137. std::string rest(iter, end);
  138. std::cout << "-------------------------\n";
  139. std::cout << "Parsing failed\n";
  140. std::cout << "stopped at: \": " << rest << "\"\n";
  141. std::cout << "-------------------------\n";
  142. }
  143. }
  144. std::cout << "Bye... :-) \n\n";
  145. return 0;
  146. }