fork download
  1. #include <iostream>
  2. #include <string>
  3. #include <stdexcept>
  4. #include <cctype>
  5. #include <map>
  6. #include <cstdlib>
  7. #include <cmath>
  8.  
  9. struct parse_error : std::runtime_error
  10. {
  11. parse_error(std::string const& what)
  12. : runtime_error(what)
  13. {}
  14. };
  15.  
  16. typedef double calculation_type;
  17.  
  18. std::map<std::string, calculation_type> constants;
  19. std::map<std::string, calculation_type (*) (calculation_type)> functions;
  20.  
  21. // identifier = {A-Za-z_} {A-Za-z0-9_}*
  22. // function-call = identifier [factor]
  23. // operand = (('+' | '-') operand) | double | function-call | '(' sum ')'
  24. // power = operand ['^' operand]*
  25. // product = power [('*' | '/') power ]*
  26. // sum = product [('+' | '-') product]*
  27.  
  28. calculation_type parse_sum(char const*& input);
  29. calculation_type parse_operand(char const*& input);
  30.  
  31. void skip_spaces(char const*& input)
  32. {
  33. while(std::isspace(*input))
  34. ++input;
  35. }
  36.  
  37. double parse_double(char const*& input)
  38. {
  39. return std::strtod(input, const_cast<char**>(&input));
  40. }
  41.  
  42. std::string parse_identifier(char const*& input)
  43. {
  44. skip_spaces(input);
  45. std::string identifier(1, *input++);
  46.  
  47. while(std::isalnum(*input) || *input == '_')
  48. identifier += *input++;
  49.  
  50. return identifier;
  51. }
  52.  
  53. calculation_type parse_function_call(char const*& input)
  54. {
  55. skip_spaces(input);
  56.  
  57. std::string const name = parse_identifier(input);
  58.  
  59. {
  60. auto const iter = constants.find(name);
  61.  
  62. if(iter != constants.end())
  63. return iter->second;
  64. }
  65.  
  66. {
  67. auto const iter = functions.find(name);
  68.  
  69. if(iter != functions.end())
  70. {
  71. skip_spaces(input);
  72. calculation_type const argument = parse_operand(input);
  73. return iter->second(argument);
  74. }
  75. }
  76.  
  77. throw parse_error("unknown function '" + name + "'");
  78. }
  79.  
  80. calculation_type parse_operand(char const*& input)
  81. {
  82. skip_spaces(input);
  83.  
  84. if(*input == '+')
  85. return parse_operand(++input);
  86.  
  87. if(*input == '-')
  88. return -parse_operand(++input);
  89.  
  90. if(std::isdigit(*input) || *input == '.')
  91. return parse_double(input);
  92.  
  93. if(std::isalpha(*input) || *input == '_')
  94. return parse_function_call(input);
  95.  
  96. if(*input == '(')
  97. {
  98. skip_spaces(input);
  99. calculation_type const value = parse_sum(++input);
  100.  
  101. skip_spaces(input);
  102. if(*input != ')')
  103. throw parse_error("closing brace ')' missing");
  104.  
  105. ++input;
  106. return value;
  107. }
  108.  
  109. throw parse_error("expected value here: " + std::string(input));
  110. }
  111.  
  112. calculation_type parse_power(char const*& input)
  113. {
  114. skip_spaces(input);
  115. calculation_type power = parse_operand(input);
  116.  
  117. skip_spaces(input);
  118. if(*input == '^')
  119. power = std::pow(power, parse_power(++input));
  120.  
  121. return power;
  122. }
  123.  
  124. calculation_type parse_product(char const*& input)
  125. {
  126. skip_spaces(input);
  127. calculation_type product = parse_power(input);
  128.  
  129. skip_spaces(input);
  130. while(*input == '*' || *input == '/')
  131. if(*input == '*')
  132. product *= parse_power(++input);
  133. else if(*input == '/')
  134. product /= parse_power(++input);
  135.  
  136. return product;
  137. }
  138.  
  139. calculation_type parse_sum(char const*& input)
  140. {
  141. skip_spaces(input);
  142. calculation_type sum = parse_product(input);
  143.  
  144. skip_spaces(input);
  145. while(*input == '+' || *input == '-')
  146. if(*input == '+')
  147. sum += parse_product(++input);
  148. else if(*input == '-')
  149. sum -= parse_product(++input);
  150.  
  151. return sum;
  152. }
  153.  
  154. calculation_type eval(char const* input)
  155. {
  156. return parse_sum(input);
  157. }
  158.  
  159. int main()
  160. {
  161. char const* const input = "2^2^2^2";
  162.  
  163. constants["pi"] = 3.14159265;
  164. constants["e"] = 2.71828183;
  165.  
  166. functions["sin"] = std::sin;
  167. functions["cos"] = std::cos;
  168.  
  169. try
  170. {
  171. std::cout << eval(input);
  172. }
  173.  
  174. catch(parse_error const& e)
  175. {
  176. std::cout << "parse error: " << e.what();
  177. }
  178.  
  179. std::cin.get();
  180. }
Success #stdin #stdout 0s 2976KB
stdin
Standard input is empty
stdout
65536