#include <iostream>
#include <stack>
#include <sstream>
namespace Parser {
class Token {
public:
enum Kind {
NUMBER,
PLUS, MINUS, MUL, DIV,
PRINT, EOS, UNKNOWN
};
Token() :k{EOS} {}
Token(Kind x) :k{x} {}
Token(double x) :k{NUMBER}, n{x} {}
double number() const { return n; }
Kind kind() const { return k; }
private:
Kind k;
double n;
};
class TokenStream {
public:
TokenStream(std::istream& s) :is{s} {}
const Token& get() {
char c;
is >> c;
if (is.eof())
return curr_tok = {Token::EOS};
if (c >= '0' && c <= '9') {
is.putback(c);
double d;
is >> d;
return curr_tok = {d};
}
switch (c) {
case '+': return curr_tok = {Token::PLUS};
case '-': return curr_tok = {Token::MINUS};
case '*': return curr_tok = {Token::MUL};
case '/': return curr_tok = {Token::DIV};
case ';':
case '\n': return curr_tok = {Token::PRINT};
default: return curr_tok = {Token::UNKNOWN};
}
}
const Token& current() const {
return curr_tok;
}
private:
std::istream& is;
Token curr_tok;
};
} //namespace
struct SyntaxError : public std::runtime_error {
SyntaxError(const char* s) :runtime_error{s} {}
};
double builtin_op(double x, double y, Parser::Token t) {
using Parser::Token;
switch (t.kind()) {
case Token::PLUS: return x + y;
case Token::MINUS: return x - y;
case Token::MUL: return x * y;
case Token::DIV: return x / y;
}
}
void calculate(std::istream& is) {
using Parser::Token;
Parser::TokenStream ts {is};
std::stack<double> st;
while (ts.get().kind() != Token::EOS) {
auto tok = ts.current();
switch (tok.kind()) {
case Token::PRINT:
{
if (st.empty())
throw SyntaxError {"Nothing to print"};
double res = st.top();
st.pop();
if (!st.empty())
throw SyntaxError {"Too many values"};
std::cout << "= " << res << '\n';
break;
}
case Token::NUMBER:
st.push(tok.number());
break;
case Token::PLUS:
case Token::MINUS:
case Token::MUL:
case Token::DIV:
{
if (st.empty())
throw SyntaxError{"Expected a number before the operator"};
double n1 = st.top();
st.pop();
if (st.empty())
throw SyntaxError{"Expected a number before the operator"};
double n2 = st.top();
st.pop();
st.push(builtin_op(n2, n1, tok));
break;
}
default: throw SyntaxError {"Unexpected token"};
}
}
}
int main() {
//calculate(std::cin);
std::istringstream is {"5 1 2 + 4 * + 3 -; 2 2 +; 2 2 -;"};
calculate(is);
return EXIT_SUCCESS;
}