Skip to content

Instantly share code, notes, and snippets.

@maekawatoshiki
Last active August 18, 2020 13:50
Show Gist options
  • Save maekawatoshiki/6918b83f3b6c5c381b6296237d18d0a5 to your computer and use it in GitHub Desktop.
Save maekawatoshiki/6918b83f3b6c5c381b6296237d18d0a5 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <string>
#include <stack>
#include <memory>
#include <sstream>
class Node {
public:
virtual std::string to_string() = 0;
virtual double eval() = 0;
virtual ~Node() {}
};
class OpNode : public Node {
private:
char op;
std::unique_ptr<Node> lhs, rhs;
public:
OpNode(char op_, std::unique_ptr<Node> lhs_, std::unique_ptr<Node> rhs_):
op(op_), lhs(std::move(lhs_)), rhs(std::move(rhs_)) { }
std::string to_string() {
std::stringstream ss("");
ss << "(" << op << " " << lhs->to_string() << " " << rhs->to_string() << ")";
return ss.str();
}
double eval() {
double lhs_ = lhs->eval(), rhs_ = rhs->eval();
switch (op) {
case '+': return lhs_ + rhs_;
case '-': return lhs_ - rhs_;
case '*': return lhs_ * rhs_;
case '/': return lhs_ / rhs_;
default: return 0.0;
}
}
};
class NumNode : public Node {
private:
int value;
public:
NumNode(int value_): value(value_) {}
std::string to_string() { return std::to_string(value); }
double eval() { return (double) value; }
};
class Parser {
private:
std::string::iterator it;
std::string input;
public:
Parser(std::string input_) : input(input_) { it = input.begin(); }
std::unique_ptr<Node> run();
std::unique_ptr<Node> parse_num();
std::unique_ptr<Node> parse_add_sub();
std::unique_ptr<Node> parse_mul_div();
char next() { if (isspace(*it)) { it++; return next(); } return *(it++); }
char cur() { if (isspace(*it)) { it++; return cur(); } return *it; }
bool eof() { return it == input.end(); }
};
std::unique_ptr<Node> Parser::parse_num() {
int num = 0;
while (!eof() && isdigit(cur()))
num = (next() - '0') + num * 10;
return std::unique_ptr<NumNode>(new NumNode(num));
}
std::unique_ptr<Node> Parser::run() {
return parse_add_sub();
}
std::unique_ptr<Node> Parser::parse_mul_div() {
auto lhs = parse_num();
while (cur() == '*' || cur() == '/') {
char op = next();
auto rhs = parse_num();
lhs = std::unique_ptr<OpNode>(new OpNode(op, std::move(lhs), std::move(rhs)));
}
return lhs;
}
std::unique_ptr<Node> Parser::parse_add_sub() {
auto lhs = parse_mul_div();
while (cur() == '+' || cur() == '-') {
char op = next();
auto rhs = parse_mul_div();
lhs = std::unique_ptr<OpNode>(new OpNode(op, std::move(lhs), std::move(rhs)));
}
return lhs;
}
int main() {
std::string s;
std::getline(std::cin, s);
Parser parser(s);
auto node = parser.run();
std::cout << "expr: " << node->to_string() << std::endl;
std::cout << "eval: " << node->eval() << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment