Skip to content

Instantly share code, notes, and snippets.

@howardlau1999
Created December 5, 2018 05:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save howardlau1999/92c31f08f0d1829884e836f81c4ce8e8 to your computer and use it in GitHub Desktop.
Save howardlau1999/92c31f08f0d1829884e836f81c4ce8e8 to your computer and use it in GitHub Desktop.
Simple Calculator
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cctype>
#include <stdexcept>
using namespace std;
struct Node {
string content;
vector<Node*> children;
Node(string content) : content(content) {}
};
struct BinaryNode {
string content;
BinaryNode *left, *right;
BinaryNode(string content, BinaryNode* left = nullptr, BinaryNode *right = nullptr) : content(content), left(left), right(right) {}
};
string to_string(char c) {
string s;
s.push_back(c);
return s;
}
class Calculator {
int cur, preview;
string s;
public:
Node *root;
BinaryNode *exp_root;
int calculate(string s) {
size_t space;
root = new Node("");
exp_root = new BinaryNode("");
while ((space = s.find(" ")) != string::npos) {
s.erase(space, 1);
}
this->s = s;
cur = 0;
int val = expr(root, &exp_root);
if (cur != s.size()) throw runtime_error("expected +, - at " + to_string(cur) + " found " + to_string(s[cur]));
return val;
}
int expr(Node *parent, BinaryNode **exp_parent) {
Node *expression = new Node("E");
parent->children.push_back(expression);
BinaryNode* middle = new BinaryNode("");
int val = factor(expression, &middle);
while (cur < s.size() && (s[cur] == '+' || s[cur] == '-')) {
expression->children.push_back(new Node(to_string(s[cur])));
middle = new BinaryNode(to_string(s[cur]), middle, new BinaryNode(""));
switch (s[cur++]) {
case '+':
val += factor(expression, &middle->right);
break;
case '-':
val -= factor(expression, &middle->right);
break;
}
}
*exp_parent = middle;
return val;
}
int factor(Node *parent, BinaryNode **exp_parent) {
Node *fact = new Node("F");
parent->children.push_back(fact);
BinaryNode* middle = new BinaryNode("");
int val = term(fact, &middle);
while (cur < s.size() && (s[cur] == '*' || s[cur] == '/' || s[cur] == '%')) {
fact->children.push_back(new Node(to_string(s[cur])));
middle = new BinaryNode(to_string(s[cur]), middle, new BinaryNode(""));
switch (s[cur++]) {
case '*':
val *= term(fact, &middle->right);
break;
case '/':
val /= term(fact, &middle->right);
break;
case '%':
val %= term(fact, &middle->right);
break;
}
}
*exp_parent = middle;
return val;
}
int term(Node *parent, BinaryNode **exp_parent) {
bool neg = false;
Node *t = new Node("T");
BinaryNode* middle = new BinaryNode("");
bool unary = false;
parent->children.push_back(t);
if (s[cur] == '+') {
t->children.push_back(new Node(to_string(s[cur])));
middle->content = to_string(s[cur]);
middle->left = new BinaryNode("");
unary = true;
++cur;
} else if (s[cur] == '-') {
t->children.push_back(new Node(to_string(s[cur])));
middle->content = to_string(s[cur]);
middle->left = new BinaryNode("");
unary = true;
neg = true;
++cur;
}
int val = unary ? expo(t, &middle->left) : expo(t, &middle);
*exp_parent = middle;
return neg ? -val : val;
}
int expo(Node* parent, BinaryNode **exp_parent) {
Node* exp = new Node("Ep");
parent->children.push_back(exp);
BinaryNode* middle = new BinaryNode("");
int val = 0;
if (s[cur] == '(') {
exp->children.push_back(new Node(to_string(s[cur])));
++cur;
val = expr(exp, &middle);
if (s[cur] != ')') throw runtime_error("expected ) at " + to_string(cur) + ", found " + to_string(s[cur]));
exp->children.push_back(new Node(to_string(s[cur])));
++cur;
}
else {
if (!isdigit(s[cur])) throw runtime_error("expected number at " + to_string(cur) + ", found " + to_string(s[cur]));
while (std::isdigit(s[cur])) {
val *= 10;
val += (s[cur++] - '0');
}
exp->children.push_back(new Node(to_string(val)));
middle->content = to_string(val);
}
while (cur < s.size() && s[cur] == '^') {
exp->children.push_back(new Node(to_string(s[cur])));
middle = new BinaryNode(to_string(s[cur]), middle, new BinaryNode(""));
switch (s[cur++]) {
case '^':
val = pow(val, expo(exp, &middle->right));
break;
}
}
*exp_parent = middle;
return val;
}
};
int main() {
string expr;
getline(cin, expr);
Calculator cal;
try {
cout << cal.calculate(expr) << endl;
} catch (runtime_error& e) {
cout << e.what() << endl;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment