#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]
// factor = ['+' | '-'] (double | function-call | '(' sum ')')
// product = factor [('*' | '/') factor ]*
// sum = product [('+' | '-') product]*
calculation_type parse_sum(char const*& input);
calculation_type parse_factor(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_factor(input);
return iter->second(argument);
}
}
throw parse_error("unknown function '" + name + "'");
}
calculation_type parse_factor(char const*& input)
{
skip_spaces(input);
if(*input == '+')
return parse_factor(++input);
if(*input == '-')
return -parse_factor(++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_product(char const*& input)
{
skip_spaces(input);
calculation_type product = parse_factor(input);
skip_spaces(input);
while(*input == '*' || *input == '/')
if(*input == '*')
product *= parse_factor(++input);
else if(*input == '/')
product /= parse_factor(++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 = "sin (pi / 2) - cos 0";
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();
}