calc2_ast_vm.hpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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. // the specialization below tells Spirit to handle expression_ast as if it
  71. // where a 'real' variant
  72. namespace spirit { namespace traits
  73. {
  74. // the specialization below tells Spirit to handle expression_ast as
  75. // if it where a 'real' variant (if used with Spirit.Karma)
  76. template <>
  77. struct not_is_variant<expression_ast, karma::domain>
  78. : mpl::false_ {};
  79. // the specialization of variant_which allows to generically extract
  80. // the current type stored in the given variant like type
  81. template <>
  82. struct variant_which<expression_ast>
  83. {
  84. static int call(expression_ast const& v)
  85. {
  86. return v.which();
  87. }
  88. };
  89. }}
  90. }
  91. enum byte_code
  92. {
  93. op_neg = 1, // negate the top stack entry
  94. op_pos, // essentially a no-op (unary plus)
  95. op_add, // add top two stack entries
  96. op_sub, // subtract top two stack entries
  97. op_mul, // multiply top two stack entries
  98. op_div, // divide top two stack entries
  99. op_int, // push constant integer into the stack
  100. };
  101. ///////////////////////////////////////////////////////////////////////////////
  102. struct binary_op
  103. {
  104. binary_op() {}
  105. binary_op(
  106. int op
  107. , expression_ast const& left
  108. , expression_ast const& right)
  109. : op(op), left(left), right(right) {}
  110. int op;
  111. expression_ast left;
  112. expression_ast right;
  113. };
  114. struct unary_op
  115. {
  116. unary_op(
  117. int op
  118. , expression_ast const& right)
  119. : op(op), right(right) {}
  120. int op;
  121. expression_ast right;
  122. };
  123. inline expression_ast& expression_ast::operator+=(expression_ast const& rhs)
  124. {
  125. expr = binary_op(op_add, expr, rhs);
  126. return *this;
  127. }
  128. inline expression_ast& expression_ast::operator-=(expression_ast const& rhs)
  129. {
  130. expr = binary_op(op_sub, expr, rhs);
  131. return *this;
  132. }
  133. inline expression_ast& expression_ast::operator*=(expression_ast const& rhs)
  134. {
  135. expr = binary_op(op_mul, expr, rhs);
  136. return *this;
  137. }
  138. inline expression_ast& expression_ast::operator/=(expression_ast const& rhs)
  139. {
  140. expr = binary_op(op_div, expr, rhs);
  141. return *this;
  142. }
  143. // We should be using expression_ast::operator-. There's a bug
  144. // in phoenix type deduction mechanism that prevents us from
  145. // doing so. Phoenix will be switching to BOOST_TYPEOF. In the
  146. // meantime, we will use a phoenix::function below:
  147. template <char Op>
  148. struct unary_expr
  149. {
  150. template <typename T>
  151. struct result { typedef T type; };
  152. expression_ast operator()(expression_ast const& expr) const
  153. {
  154. return unary_op(Op, expr);
  155. }
  156. };
  157. boost::phoenix::function<unary_expr<op_pos> > pos;
  158. boost::phoenix::function<unary_expr<op_neg> > neg;
  159. #endif