#include <iostream>
#include <string>
#include <stdexcept>
#include <cctype>
#include <map>
#include <cstdlib>
#include <cmath>

struct parse_error : std::runtime_error
{
	parse_error(std::string const& what)
		: runtime_error(what)
	{}
};

typedef double calculation_type;

std::map<std::string, calculation_type> constants;
std::map<std::string, calculation_type (*) (calculation_type)> functions;

// identifier    = {A-Za-z_} {A-Za-z0-9_}*
// function-call = identifier [factor]
// operand       = (('+' | '-') operand) | double | function-call | '(' sum ')'
// power         = operand ['^' operand]*
// product       = power   [('*' | '/') power  ]*
// sum           = product [('+' | '-') product]*

calculation_type parse_sum(char const*& input);
calculation_type parse_operand(char const*& input);

void skip_spaces(char const*& input)
{
	while(std::isspace(*input))
		++input;
}

double parse_double(char const*& input)
{
	return std::strtod(input, const_cast<char**>(&input));
}

std::string parse_identifier(char const*& input)
{
	skip_spaces(input);
	std::string identifier(1, *input++);

	while(std::isalnum(*input) || *input == '_')
		identifier += *input++;

	return identifier;
}

calculation_type parse_function_call(char const*& input)
{
	skip_spaces(input);

	std::string const name = parse_identifier(input);

	{
		auto const iter = constants.find(name);

		if(iter != constants.end())
			return iter->second;
	}

	{
		auto const iter = functions.find(name);

		if(iter != functions.end())
		{
			skip_spaces(input);
			calculation_type const argument = parse_operand(input);
			return iter->second(argument);
		}
	}

	throw parse_error("unknown function '" + name + "'");
}

calculation_type parse_operand(char const*& input)
{
	skip_spaces(input);

	if(*input == '+')
		return parse_operand(++input);

	if(*input == '-')
		return -parse_operand(++input);

	if(std::isdigit(*input) || *input == '.')
		return parse_double(input);

	if(std::isalpha(*input) || *input == '_')
		return parse_function_call(input);

	if(*input == '(')
	{
		skip_spaces(input);
		calculation_type const value = parse_sum(++input);

		skip_spaces(input);
		if(*input != ')')
			throw parse_error("closing brace ')' missing");

		++input;
		return value;
	}

	throw parse_error("expected value here: " + std::string(input));
}

calculation_type parse_power(char const*& input)
{
	skip_spaces(input);
	calculation_type power = parse_operand(input);

	skip_spaces(input);
	if(*input == '^')
		power = std::pow(power, parse_power(++input));

	return power;
}

calculation_type parse_product(char const*& input)
{
	skip_spaces(input);
	calculation_type product = parse_power(input);

	skip_spaces(input);
	while(*input == '*' || *input == '/')
		if(*input == '*')
			product *= parse_power(++input);
		else if(*input == '/')
			product /= parse_power(++input);

	return product;
}

calculation_type parse_sum(char const*& input)
{
	skip_spaces(input);
	calculation_type sum = parse_product(input);

	skip_spaces(input);
	while(*input == '+' || *input == '-')
		if(*input == '+')
			sum += parse_product(++input);
		else if(*input == '-')
			sum -= parse_product(++input);

	return sum;
}

calculation_type eval(char const* input)
{
	return parse_sum(input);
}

int main()
{
	char const* const input = "2^2^2^2";

	constants["pi"] = 3.14159265;
	constants["e"]  = 2.71828183;

	functions["sin"] = std::sin;
	functions["cos"] = std::cos;

	try
	{
		std::cout << eval(input);
	}

	catch(parse_error const& e)
	{
		std::cout << "parse error: " << e.what();
	}

	std::cin.get();
}