calc2_ast.hpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. #if !defined(SPIRIT_EXAMPLE_CALC2_AST_APR_30_2008_1011AM)
  17. #define SPIRIT_EXAMPLE_CALC2_AST_APR_30_2008_1011AM
  18. #include <boost/variant.hpp>
  19. #include <boost/spirit/include/phoenix_operator.hpp>
  20. #include <boost/spirit/include/phoenix_function.hpp>
  21. #include <boost/spirit/include/phoenix_statement.hpp>
  22. #include <boost/spirit/include/karma_domain.hpp>
  23. #include <boost/spirit/include/support_attributes_fwd.hpp>
  24. ///////////////////////////////////////////////////////////////////////////////
  25. // Our AST
  26. ///////////////////////////////////////////////////////////////////////////////
  27. struct binary_op;
  28. struct unary_op;
  29. struct nil {};
  30. struct expression_ast
  31. {
  32. typedef
  33. boost::variant<
  34. nil // can't happen!
  35. , int
  36. , boost::recursive_wrapper<binary_op>
  37. , boost::recursive_wrapper<unary_op>
  38. >
  39. type;
  40. // expose variant types
  41. typedef type::types types;
  42. // expose variant functionality
  43. int which() const { return expr.which(); }
  44. // constructors
  45. expression_ast()
  46. : expr(nil()) {}
  47. expression_ast(unary_op const& expr)
  48. : expr(expr) {}
  49. expression_ast(binary_op const& expr)
  50. : expr(expr) {}
  51. expression_ast(unsigned int expr)
  52. : expr(expr) {}
  53. expression_ast(type const& expr)
  54. : expr(expr) {}
  55. expression_ast& operator+=(expression_ast const& rhs);
  56. expression_ast& operator-=(expression_ast const& rhs);
  57. expression_ast& operator*=(expression_ast const& rhs);
  58. expression_ast& operator/=(expression_ast const& rhs);
  59. type expr;
  60. };
  61. // expose variant functionality
  62. namespace boost
  63. {
  64. // this function has to live in namespace boost for ADL to correctly find it
  65. template <typename T>
  66. inline T get(expression_ast const& expr)
  67. {
  68. return boost::get<T>(expr.expr);
  69. }
  70. namespace spirit { namespace traits
  71. {
  72. // the specialization below tells Spirit to handle expression_ast as
  73. // if it where a 'real' variant (if used with Spirit.Karma)
  74. template <>
  75. struct not_is_variant<expression_ast, karma::domain>
  76. : mpl::false_ {};
  77. // the specialization of variant_which allows to generically extract
  78. // the current type stored in the given variant like type
  79. template <>
  80. struct variant_which<expression_ast>
  81. {
  82. static int call(expression_ast const& v)
  83. {
  84. return v.which();
  85. }
  86. };
  87. }}
  88. }
  89. ///////////////////////////////////////////////////////////////////////////////
  90. struct binary_op
  91. {
  92. binary_op() {}
  93. binary_op(
  94. char op
  95. , expression_ast const& left
  96. , expression_ast const& right)
  97. : op(op), left(left), right(right) {}
  98. char op;
  99. expression_ast left;
  100. expression_ast right;
  101. };
  102. struct unary_op
  103. {
  104. unary_op(
  105. char op
  106. , expression_ast const& right)
  107. : op(op), right(right) {}
  108. char op;
  109. expression_ast right;
  110. };
  111. inline expression_ast& expression_ast::operator+=(expression_ast const& rhs)
  112. {
  113. expr = binary_op('+', expr, rhs);
  114. return *this;
  115. }
  116. inline expression_ast& expression_ast::operator-=(expression_ast const& rhs)
  117. {
  118. expr = binary_op('-', expr, rhs);
  119. return *this;
  120. }
  121. inline expression_ast& expression_ast::operator*=(expression_ast const& rhs)
  122. {
  123. expr = binary_op('*', expr, rhs);
  124. return *this;
  125. }
  126. inline expression_ast& expression_ast::operator/=(expression_ast const& rhs)
  127. {
  128. expr = binary_op('/', expr, rhs);
  129. return *this;
  130. }
  131. // We should be using expression_ast::operator-. There's a bug
  132. // in phoenix type deduction mechanism that prevents us from
  133. // doing so. Phoenix will be switching to BOOST_TYPEOF. In the
  134. // meantime, we will use a phoenix::function below:
  135. template <char Op>
  136. struct unary_expr
  137. {
  138. template <typename T>
  139. struct result { typedef T type; };
  140. expression_ast operator()(expression_ast const& expr) const
  141. {
  142. return unary_op(Op, expr);
  143. }
  144. };
  145. boost::phoenix::function<unary_expr<'+'> > pos;
  146. boost::phoenix::function<unary_expr<'-'> > neg;
  147. #endif