spirit/repository/example/karma/calc2_ast.hpp
Hartmut Kaiser f0ef6642e5 Spirit: fixed Karma examples
[SVN r76383]
2012-01-09 13:52:23 +00:00

180 lines
4.8 KiB
C++

/*=============================================================================
Copyright (c) 2001-2010 Joel de Guzman
Copyright (c) 2001-2012 Hartmut Kaiser
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
///////////////////////////////////////////////////////////////////////////////
//
// A Calculator example demonstrating generation of AST which gets dumped into
// a human readable format afterwards.
//
// [ JDG April 28, 2008 ]
// [ HK April 28, 2008 ]
//
///////////////////////////////////////////////////////////////////////////////
#if !defined(SPIRIT_EXAMPLE_CALC2_AST_APR_30_2008_1011AM)
#define SPIRIT_EXAMPLE_CALC2_AST_APR_30_2008_1011AM
#include <boost/variant.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/home/karma/domain.hpp>
#include <boost/spirit/include/support_attributes_fwd.hpp>
///////////////////////////////////////////////////////////////////////////////
// Our AST
///////////////////////////////////////////////////////////////////////////////
struct binary_op;
struct unary_op;
struct nil {};
struct expression_ast
{
typedef
boost::variant<
nil // can't happen!
, int
, boost::recursive_wrapper<binary_op>
, boost::recursive_wrapper<unary_op>
>
type;
// expose variant types
typedef type::types types;
// expose variant functionality
int which() const { return expr.which(); }
// constructors
expression_ast()
: expr(nil()) {}
expression_ast(unary_op const& expr)
: expr(expr) {}
expression_ast(binary_op const& expr)
: expr(expr) {}
expression_ast(unsigned int expr)
: expr(expr) {}
expression_ast(type const& expr)
: expr(expr) {}
expression_ast& operator+=(expression_ast const& rhs);
expression_ast& operator-=(expression_ast const& rhs);
expression_ast& operator*=(expression_ast const& rhs);
expression_ast& operator/=(expression_ast const& rhs);
type expr;
};
// expose variant functionality
namespace boost
{
// this function has to live in namespace boost for ADL to correctly find it
template <typename T>
inline T get(expression_ast const& expr)
{
return boost::get<T>(expr.expr);
}
// the specialization below tells Spirit to handle expression_ast as if it
// where a 'real' variant
namespace spirit { namespace traits
{
// the specialization below tells Spirit to handle expression_ast as
// if it where a 'real' variant (if used with Spirit.Karma)
template <>
struct not_is_variant<expression_ast, karma::domain>
: mpl::false_ {};
// the specialization of variant_which allows to generically extract
// the current type stored in the given variant like type
template <>
struct variant_which<expression_ast>
{
static int call(expression_ast const& v)
{
return v.which();
}
};
}}
}
///////////////////////////////////////////////////////////////////////////////
struct binary_op
{
binary_op() {}
binary_op(
char op
, expression_ast const& left
, expression_ast const& right)
: op(op), left(left), right(right) {}
char op;
expression_ast left;
expression_ast right;
};
struct unary_op
{
unary_op(
char op
, expression_ast const& right)
: op(op), right(right) {}
char op;
expression_ast right;
};
inline expression_ast& expression_ast::operator+=(expression_ast const& rhs)
{
expr = binary_op('+', expr, rhs);
return *this;
}
inline expression_ast& expression_ast::operator-=(expression_ast const& rhs)
{
expr = binary_op('-', expr, rhs);
return *this;
}
inline expression_ast& expression_ast::operator*=(expression_ast const& rhs)
{
expr = binary_op('*', expr, rhs);
return *this;
}
inline expression_ast& expression_ast::operator/=(expression_ast const& rhs)
{
expr = binary_op('/', expr, rhs);
return *this;
}
// We should be using expression_ast::operator-. There's a bug
// in phoenix type deduction mechanism that prevents us from
// doing so. Phoenix will be switching to BOOST_TYPEOF. In the
// meantime, we will use a phoenix::function below:
template <char Op>
struct unary_expr
{
template <typename T>
struct result { typedef T type; };
expression_ast operator()(expression_ast const& expr) const
{
return unary_op(Op, expr);
}
};
boost::phoenix::function<unary_expr<'+'> > pos;
boost::phoenix::function<unary_expr<'-'> > neg;
#endif