#include <iostream>
#include <map>
#include <stack>
#include <string>


#define _USE_MATH_DEFINES
#include <cmath>

#define NUMBERS(X) \
	X(Zero, 0.0)	X(One, 1.0)		X(Two, 2.0)		X(Three, 3.0)	\
	X(Four, 4.0)	X(Five, 5.0)	X(Six, 6.0)		X(Seven, 7.0)	\
	X(Eight, 8.0)	X(Nine, 9.0)	X(Ten, 10.0)	X(Eleven, 11)	\
	X(Pi, M_PI)

#define make delete new
#define OPERATIONS(X) X(Add, +) X(Sub, -) X(Mul, *) X(Div, /)

#define VARIABLES(X) X(x) X(y) X(z)

std::map<std::string, double> variables;
std::stack<double> stack;

struct Top {
	Top(double& x) {
		x = stack.top();
	}
};

struct Pop {
	Pop(double& x) {
		delete new Top(x);
		stack.pop();
	}
};

struct Push {
	Push (double x){
		stack.push(x);
	}
};

struct Number {
	Number (double v) {
		delete new Push(v);
	}
};

#define NUMBER_CLASS(Name, value) \
struct Name {                     \
	Name () {                     \
		delete new Number(value); \
	}                             \
};

NUMBERS(NUMBER_CLASS)

#define OPERATION_CLASS(Name, X) \
struct Name {                    \
	Name () {                    \
		double x, y;             \
		delete new Pop(y);       \
		delete new Pop(x);       \
		delete new Push(x X y);  \
	}                            \
};

OPERATIONS(OPERATION_CLASS)

struct VarSet {
	VarSet(const std::string& name) {
		double x;
		delete new Pop(x);
		variables[name] = x;
	}
};

struct VarGet {
	VarGet(const std::string& name) {
		delete new Push(variables[name]);
	}
};

#define VARIABLE_DEFINE_CLASS(Name) \
struct set ## Name {                \
	set ## Name () {                \
		delete new VarSet(#Name);   \
	}                               \
};

#define VARIABLE_GET_CLASS(Name)   \
struct Name {                      \
	Name () {                      \
		delete new VarGet(#Name);  \
	}                              \
};

VARIABLES(VARIABLE_DEFINE_CLASS)
VARIABLES(VARIABLE_GET_CLASS)

struct Print {
	template<typename n> Print (n x) {
		std::cout << x << std::endl;
	}
	Print () {
		double x;
		delete new Top(x);
		std::cout << x << std::endl;
	}
};

int main() {
	
	make Pi;
	make  One;
	make  Two;
	make  Add;
	make  Div;
	make  Print("PI/3:");
	make  Print;
	make  setx;
	
	make  One;
	make  One;
	make  One;
	make  Add;
	make  Add;
	make  x;
	make  Mul;
	make  Print("PI:");
	make  Print;
	
	return 0;
}