fork download
  1. #include <iostream>
  2. #include <stack>
  3. #include <sstream>
  4.  
  5. namespace Parser {
  6. class Token {
  7. public:
  8. enum Kind {
  9. NUMBER,
  10. PLUS, MINUS, MUL, DIV,
  11. PRINT, EOS, UNKNOWN
  12. };
  13.  
  14. Token() :k{EOS} {}
  15. Token(Kind x) :k{x} {}
  16. Token(double x) :k{NUMBER}, n{x} {}
  17.  
  18. double number() const { return n; }
  19. Kind kind() const { return k; }
  20.  
  21. private:
  22. Kind k;
  23. double n;
  24. };
  25.  
  26. class TokenStream {
  27. public:
  28. TokenStream(std::istream& s) :is{s} {}
  29.  
  30. const Token& get() {
  31. char c;
  32. is >> c;
  33.  
  34. if (is.eof())
  35. return curr_tok = {Token::EOS};
  36.  
  37. if (c >= '0' && c <= '9') {
  38. is.putback(c);
  39. double d;
  40. is >> d;
  41. return curr_tok = {d};
  42. }
  43. switch (c) {
  44. case '+': return curr_tok = {Token::PLUS};
  45. case '-': return curr_tok = {Token::MINUS};
  46. case '*': return curr_tok = {Token::MUL};
  47. case '/': return curr_tok = {Token::DIV};
  48. case ';':
  49. case '\n': return curr_tok = {Token::PRINT};
  50. default: return curr_tok = {Token::UNKNOWN};
  51. }
  52. }
  53.  
  54. const Token& current() const {
  55. return curr_tok;
  56. }
  57.  
  58. private:
  59. std::istream& is;
  60. Token curr_tok;
  61. };
  62. } //namespace
  63.  
  64. struct SyntaxError : public std::runtime_error {
  65. SyntaxError(const char* s) :runtime_error{s} {}
  66. };
  67.  
  68. double builtin_op(double x, double y, Parser::Token t) {
  69. using Parser::Token;
  70. switch (t.kind()) {
  71. case Token::PLUS: return x + y;
  72. case Token::MINUS: return x - y;
  73. case Token::MUL: return x * y;
  74. case Token::DIV: return x / y;
  75. }
  76. }
  77.  
  78. void calculate(std::istream& is) {
  79. using Parser::Token;
  80. Parser::TokenStream ts {is};
  81. std::stack<double> st;
  82.  
  83. while (ts.get().kind() != Token::EOS) {
  84. auto tok = ts.current();
  85. switch (tok.kind()) {
  86. case Token::PRINT:
  87. {
  88. if (st.empty())
  89. throw SyntaxError {"Nothing to print"};
  90. double res = st.top();
  91. st.pop();
  92. if (!st.empty())
  93. throw SyntaxError {"Too many values"};
  94. std::cout << "= " << res << '\n';
  95. break;
  96. }
  97. case Token::NUMBER:
  98. st.push(tok.number());
  99. break;
  100. case Token::PLUS:
  101. case Token::MINUS:
  102. case Token::MUL:
  103. case Token::DIV:
  104. {
  105. if (st.empty())
  106. throw SyntaxError{"Expected a number before the operator"};
  107. double n1 = st.top();
  108. st.pop();
  109. if (st.empty())
  110. throw SyntaxError{"Expected a number before the operator"};
  111. double n2 = st.top();
  112. st.pop();
  113. st.push(builtin_op(n2, n1, tok));
  114. break;
  115. }
  116. default: throw SyntaxError {"Unexpected token"};
  117. }
  118. }
  119. }
  120.  
  121. int main() {
  122. //calculate(std::cin);
  123. std::istringstream is {"5 1 2 + 4 * + 3 -; 2 2 +; 2 2 -;"};
  124. calculate(is);
  125. return EXIT_SUCCESS;
  126. }
Success #stdin #stdout 0s 3472KB
stdin
Standard input is empty
stdout
= 14
= 4
= 0