1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
| #include <iostream>
#include <string>
#include <list>
#include <cmath>
#include <boost/variant.hpp>
using boost::variant;
using boost::recursive_wrapper;
using boost::apply_visitor;
template <typename T> struct IfThenElse;
template <typename T> struct Call;
template <typename T>
struct AST
{
typedef variant
<
T,
recursive_wrapper< IfThenElse<T> >,
recursive_wrapper< Call<T> >
> type;
type contents;
AST() { }
AST(typename AST<T>::type const& rhs) : contents(rhs) { }
};
template <typename T>
struct IfThenElse
{
AST<T> condition_expr;
AST<T> then_expr;
AST<T> else_expr;
IfThenElse(typename AST<T>::type const& c,
typename AST<T>::type const& t,
typename AST<T>::type const& e) :
condition_expr(c),
then_expr(t),
else_expr(e)
{ }
};
template <typename T>
struct Call
{
std::string function_name;
std::list< AST<T> > parameters;
Call(std::string const& f, std::list< AST<T> > const& p) :
function_name(f), parameters(p)
{ }
};
class eval_IntAST : public boost::static_visitor<int>
{
public:
int operator()(int x) const
{
return x;
}
int operator()(IfThenElse<int> const& expr) const
{
if ( apply_visitor(*this, expr.condition_expr.contents) != 0 )
return apply_visitor(*this, expr.then_expr.contents);
else
return apply_visitor(*this, expr.else_expr.contents);
}
int operator()(Call<int> const& expr) const
{
if (expr.function_name == "square")
{
int res = apply_visitor(*this, expr.parameters.front().contents);
return res * res;
}
else
throw std::runtime_error("Unknown function");
}
};
int main()
{
// AST d'entiers
typedef AST<int> IntAST;
std::list<IntAST> paramètres;
paramètres.push_back( IntAST(30) );
IntAST test( IfThenElse<int>(1,
Call<int>("square", paramètres),
0) );
std::cout << apply_visitor(eval_IntAST(), test.contents) << std::endl;
return 0;
} |
Partager