fork download
  1. #include <iostream>
  2. #include <string>
  3. #include <stdexcept>
  4. #include <cctype>
  5. #include <map>
  6. #include <cstdlib>
  7. #include <cmath>
  8. #include <ctime>
  9.  
  10. struct parse_error : std::runtime_error
  11. {
  12. parse_error(std::string const& what)
  13. : runtime_error(what)
  14. {}
  15. };
  16.  
  17. typedef double calculation_type;
  18.  
  19. std::map<std::string, calculation_type> constants;
  20. std::map<std::string, calculation_type (*) ()> nullary_functions;
  21. std::map<std::string, calculation_type (*) (calculation_type)> unary_functions;
  22. std::map<std::string, calculation_type (*) (calculation_type, calculation_type)> binary_functions;
  23.  
  24. // unary-operator = '+' | '-' | '#'
  25. // identifier = {A-Za-z_} {A-Za-z0-9_}*
  26. // function-call = identifier [primary-expression] [primary-expression]
  27. // group = '(' sum ')' | '[' sum ']' | '{' sum '}' | '|' sum '|'
  28. // primary-expression = unary-operator primary-expression | double | function-call | group
  29. // infix-function-call = primary-expression [':' identifier ':' primary-expression]*
  30. // root = infix-function-call ['#' root]
  31. // power = root ['^' power]
  32. // product = power [('*' | '/' | '%') power]*
  33. // sum = product [('+' | '-') product]*
  34.  
  35. calculation_type parse_sum(char const*& input);
  36. calculation_type parse_primary_expression(char const*& input);
  37.  
  38. void skip_spaces(char const*& input)
  39. {
  40. while(std::isspace(*input))
  41. ++input;
  42. }
  43.  
  44. double parse_double(char const*& input)
  45. {
  46. return std::strtod(input, const_cast<char**>(&input));
  47. }
  48.  
  49. std::string parse_identifier(char const*& input)
  50. {
  51. skip_spaces(input);
  52. std::string identifier(1, *input++);
  53.  
  54. while(std::isalnum(*input) || *input == '_')
  55. identifier += *input++;
  56.  
  57. return identifier;
  58. }
  59.  
  60. calculation_type parse_function_call(char const*& input)
  61. {
  62. std::string const name = parse_identifier(input);
  63.  
  64. {
  65. auto const iter = constants.find(name);
  66.  
  67. if(iter != constants.end())
  68. return iter->second;
  69. }
  70.  
  71. {
  72. auto const iter = nullary_functions.find(name);
  73.  
  74. if(iter != nullary_functions.end())
  75. return iter->second();
  76. }
  77.  
  78. {
  79. auto const iter = unary_functions.find(name);
  80.  
  81. if(iter != unary_functions.end())
  82. {
  83. calculation_type const argument = parse_primary_expression(input);
  84. return iter->second(argument);
  85. }
  86. }
  87.  
  88. {
  89. auto iter = binary_functions.find(name);
  90.  
  91. if(iter != binary_functions.end())
  92. {
  93. calculation_type const arg1 = parse_primary_expression(input);
  94. calculation_type const arg2 = parse_primary_expression(input);
  95. return iter->second(arg1, arg2);
  96. }
  97. }
  98.  
  99. throw parse_error("call to unknown function '" + name + "'");
  100. }
  101.  
  102. calculation_type parse_group(char const*& input)
  103. {
  104. char const delim = *input == '(' ? ')' : *input == '[' ? ']' : *input == '{' ? '}' : '|';
  105.  
  106. calculation_type const value = parse_sum(++input);
  107.  
  108. if(*input++ != delim)
  109. throw parse_error("terminating '" + std::string(1, delim) + "' missing");
  110.  
  111. return value;
  112. }
  113.  
  114. calculation_type parse_primary_expression(char const*& input)
  115. {
  116. skip_spaces(input);
  117.  
  118. if(*input == '+')
  119. return parse_primary_expression(++input);
  120.  
  121. if(*input == '-')
  122. return -parse_primary_expression(++input);
  123.  
  124. if(*input == '#')
  125. return std::sqrt(parse_primary_expression(++input));
  126.  
  127. if(std::isdigit(*input) || *input == '.')
  128. return parse_double(input);
  129.  
  130. if(std::isalpha(*input) || *input == '_')
  131. return parse_function_call(input);
  132.  
  133. if(*input == '(' || *input == '[' || *input == '{')
  134. return parse_group(input);
  135.  
  136. if(*input == '|')
  137. {
  138. calculation_type const value = parse_group(input);
  139. return std::abs(value);
  140. }
  141.  
  142. throw parse_error("expected value here: " + std::string(input));
  143. }
  144.  
  145. calculation_type parse_infix_function_call(char const*& input)
  146. {
  147. calculation_type result = parse_primary_expression(input);
  148.  
  149. for(;;)
  150. {
  151. skip_spaces(input);
  152.  
  153. if(*input != ':')
  154. break;
  155.  
  156. std::string const name = parse_identifier(++input);
  157.  
  158. skip_spaces(input);
  159.  
  160. if(*input != ':')
  161. throw parse_error("missing terminating ':' at infix call to function '" + name + "'");
  162.  
  163. auto iter = binary_functions.find(name);
  164.  
  165. if(iter != binary_functions.end())
  166. result = iter->second(result, parse_primary_expression(++input));
  167. else
  168. throw parse_error("infix call to unknown function '" + name + "'");
  169. }
  170.  
  171. return result;
  172. }
  173.  
  174. calculation_type parse_root(char const*& input)
  175. {
  176. calculation_type root = parse_infix_function_call(input);
  177.  
  178. skip_spaces(input);
  179.  
  180. if(*input == '#')
  181. root = std::pow(parse_root(++input), 1 / root);
  182.  
  183. return root;
  184. }
  185.  
  186. calculation_type parse_power(char const*& input)
  187. {
  188. calculation_type power = parse_root(input);
  189.  
  190. skip_spaces(input);
  191.  
  192. if(*input == '^')
  193. power = std::pow(power, parse_power(++input));
  194.  
  195. return power;
  196. }
  197.  
  198. calculation_type parse_product(char const*& input)
  199. {
  200. calculation_type product = parse_power(input);
  201.  
  202. for(;;)
  203. {
  204. skip_spaces(input);
  205.  
  206. if(*input == '*')
  207. product *= parse_power(++input);
  208. else if(*input == '/')
  209. product /= parse_power(++input);
  210. else if(*input == '%')
  211. product = std::fmod(product, parse_power(++input));
  212. else break;
  213. }
  214.  
  215. return product;
  216. }
  217.  
  218. calculation_type parse_sum(char const*& input)
  219. {
  220. calculation_type sum = parse_product(input);
  221.  
  222. for(;;)
  223. {
  224. skip_spaces(input);
  225.  
  226. if(*input == '+')
  227. sum += parse_product(++input);
  228. else if(*input == '-')
  229. sum -= parse_product(++input);
  230. else break;
  231. }
  232.  
  233. return sum;
  234. }
  235.  
  236. calculation_type eval(char const* input)
  237. {
  238. calculation_type result = parse_sum(input);
  239.  
  240. skip_spaces(input);
  241.  
  242. if(!*input)
  243. return result;
  244.  
  245. throw parse_error("unexpected character here: " + std::string(input));
  246. }
  247.  
  248. calculation_type squared(calculation_type v)
  249. {
  250. return v * v;
  251. }
  252.  
  253. calculation_type randint()
  254. {
  255. return std::rand();
  256. }
  257.  
  258. int main()
  259. {
  260. std::srand(static_cast<unsigned>(std::time(0)));
  261.  
  262. constants["pi"] = 3.14159265;
  263. constants["e"] = 2.71828183;
  264.  
  265. nullary_functions["randint"] = randint;
  266.  
  267. unary_functions["sin"] = std::sin;
  268. unary_functions["cos"] = std::cos;
  269. unary_functions["tan"] = std::tan;
  270. unary_functions["squared"] = squared;
  271.  
  272. binary_functions["pow"] = std::pow;
  273.  
  274. for(std::string line; std::getline(std::cin, line) && line != "";)
  275. {
  276. try
  277. {
  278. std::cout << eval(line.c_str()) << '\n';
  279. }
  280.  
  281. catch(parse_error const& e)
  282. {
  283. std::cout << "parse error: " << e.what() << '\n';
  284. }
  285. }
  286. }
Success #stdin #stdout 0s 2988KB
stdin
sin (pi / 2) - cos 0
squared 42 :pow: 2 - randint % 666
stdout
0
3.11103e+06