Last active
August 18, 2020 13:50
-
-
Save maekawatoshiki/6918b83f3b6c5c381b6296237d18d0a5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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