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