calc2_ast_dump.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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 human readable format 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. (char, op)
  65. (expression_ast, right)
  66. )
  67. BOOST_FUSION_ADAPT_STRUCT(
  68. unary_op,
  69. (char, op)
  70. (expression_ast, right)
  71. )
  72. ///////////////////////////////////////////////////////////////////////////////
  73. // Our AST grammar for the generator, this just dumps the AST as a expression
  74. ///////////////////////////////////////////////////////////////////////////////
  75. template <typename OuputIterator>
  76. struct dump_ast
  77. : karma::grammar<OuputIterator, expression_ast(), space_type>
  78. {
  79. dump_ast() : dump_ast::base_type(ast_node)
  80. {
  81. ast_node %= int_ | binary_node | unary_node;
  82. binary_node %= '(' << ast_node << char_ << ast_node << ')';
  83. unary_node %= '(' << char_ << ast_node << ')';
  84. }
  85. karma::rule<OuputIterator, expression_ast(), space_type> ast_node;
  86. karma::rule<OuputIterator, binary_op(), space_type> binary_node;
  87. karma::rule<OuputIterator, unary_op(), space_type> unary_node;
  88. };
  89. ///////////////////////////////////////////////////////////////////////////////
  90. // Main program
  91. ///////////////////////////////////////////////////////////////////////////////
  92. int
  93. main()
  94. {
  95. std::cout << "/////////////////////////////////////////////////////////\n\n";
  96. std::cout << "Dump AST's for simple expressions...\n\n";
  97. std::cout << "/////////////////////////////////////////////////////////\n\n";
  98. std::cout << "Type an expression...or [q or Q] to quit\n\n";
  99. // Our parser grammar definitions
  100. typedef std::string::const_iterator iterator_type;
  101. typedef calculator<iterator_type> calculator;
  102. calculator calc;
  103. // Our generator grammar definitions
  104. typedef std::back_insert_iterator<std::string> output_iterator_type;
  105. typedef dump_ast<output_iterator_type> dump_ast;
  106. dump_ast ast_grammar;
  107. std::string str;
  108. while (std::getline(std::cin, str))
  109. {
  110. if (str.empty() || str[0] == 'q' || str[0] == 'Q')
  111. break;
  112. expression_ast ast;
  113. std::string::const_iterator iter = str.begin();
  114. std::string::const_iterator end = str.end();
  115. bool r = qi::phrase_parse(iter, end, calc, space, ast);
  116. if (r && iter == end)
  117. {
  118. std::string generated;
  119. output_iterator_type outit(generated);
  120. r = karma::generate_delimited(outit, ast_grammar, space, ast);
  121. if (r)
  122. {
  123. std::cout << "Got AST:" << std::endl << generated
  124. << std::endl;
  125. std::cout << "-------------------------\n";
  126. }
  127. else
  128. {
  129. std::cout << "-------------------------\n";
  130. std::cout << "Generating failed\n";
  131. std::cout << "-------------------------\n";
  132. }
  133. }
  134. else
  135. {
  136. std::string rest(iter, end);
  137. std::cout << "-------------------------\n";
  138. std::cout << "Parsing failed\n";
  139. std::cout << "stopped at: \": " << rest << "\"\n";
  140. std::cout << "-------------------------\n";
  141. }
  142. }
  143. std::cout << "Bye... :-) \n\n";
  144. return 0;
  145. }