I've been making an interpreter for my own programming language that I've been working on as a hobby. I made an expression evaluator that can evaluate simple mathematical expressions.
It understands, +, -, /, *, brackets and the order of operations. I haven't put a modulus operator in the evaluator because I'm going to make a function for modulus instead.
I works in all of the tests I've tried. But I'd appreciate of anyone knows of any complicated expressions that it fails to evaluate.
It also understands that a positive number of minuses is that same as a plus.
It evaluates expressions like this:
(10 + (20 * - (5 + 9)))
and produce the correct output of, -270.
I'd just like to know whether there are any ways I can improve my expression evaluator and whether there are any complicated expressions that don't evaluate correctly.
Also, is there a better way than using the time command on OSX to find out how fast it evaluates because the time command only does to 3 decimal places so it's not accurate enough.
My expression evaluator evaluates the above expression like this:
(10 + (20 * - (14)))
It first does the deepest brackets.
(10 + (20 * -14))
Then, since there's a minus it multiplies the result of the brackets by -1.
(10 + (-280))
Then it does the multiply in the brackets.
(-270)
Then it does the addition with the 10 and the -280.
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
vector rdo_num_stack;
int opp_count = 0;
bool rdo_ws(char c) {
if (c != ' ')
return 0;
else
return 1;
}
char rdo_expr_item_type(char c) {
switch(c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
c = 'n';
break;
case '+':
case '-':
case '*':
case '/':
c = 'o';
break;
case '(':
case ')':
c = 'b';
break;
}
return c;
}
string rdo_opp_to_string(char opp) {
string o = "";
switch(opp) {
case '+':
o = "+";
break;
case '-':
o = "-";
break;
case '/':
o = "/";
break;
case '*':
o = "*";
break;
case '(':
o = "(";
break;
case ')':
o = ")";
break;
}
return o;
}
bool rdo_is_num(string is_num) {
if (is_num == "+" or
is_num == "-" or
is_num == "/" or
is_num == "*" or
is_num == "(" or
is_num == ")") {
return 0;
}
return 1;
}
void rdo_count_opp(bool to_count_or_not) {
if (to_count_or_not == 1)
opp_count++;
}
string rdo_eval(string expr) {
string result;
string num_holder = "";
string temp_result = "";
string num1 = "";
string num2 = "";
int n2 = 0;
int i;
int iter;
int bcount = 0;
int depth = 0;
int current_depth = 0;
int diff = 0;
int diff2 = 0;
int current_b = 0;
int minus_count = 0;
int minus_start = 0;
int plus_count = 0;
int plus_start = 0;
bool found_end = 0;
bool got_diff = 0;
bool to_inverse = 0;
bool do_calc = 0;
for (i = 0; i < expr.length();i++) {
if (!rdo_ws(expr[i])) {
if (rdo_expr_item_type(expr[i]) == 'n' or rdo_expr_item_type(expr[i]) == 'o' or rdo_expr_item_type(expr[i]) == 'b') {
if (rdo_expr_item_type(expr[i]) == 'n') {
num_holder += expr[i];
} else if (rdo_expr_item_type(expr[i]) == 'o') {
if (num_holder != "") {
rdo_num_stack.push_back(num_holder);
num_holder = "";
}
rdo_num_stack.push_back(rdo_opp_to_string(expr[i]));
} else {
if (num_holder != "") {
rdo_num_stack.push_back(num_holder);
num_holder = "";
}
rdo_num_stack.push_back(rdo_opp_to_string(expr[i]));
bcount++;
}
} else {
cout << "Invalid character in expression" << endl;
exit(0);
}
if (i == expr.length()-1 and num_holder != "") {
rdo_num_stack.push_back(num_holder);
num_holder = "";
}
}
}
if (bcount % 2 != 0) {
cout << "Extra / Missing parens." << endl;
exit(0);
} else {
bcount /= 2;
}
for (i = 0; i < rdo_num_stack.size();i++) {
if (rdo_num_stack[i] == "(") {
current_b++;
}
if (current_b == bcount and !found_end) {
if (i == 1)
depth = 0;
else
depth = i;
found_end = 1;
}
if (rdo_num_stack[i] == ")" and found_end and !got_diff) {
diff = i - depth;
got_diff = 1;
}
}
for (i = depth; i < depth+diff; i++) {
if (rdo_num_stack[i] == "+" or rdo_num_stack[i] == "-" or rdo_num_stack[i] == "*" or rdo_num_stack[i] == "/") {
if (rdo_num_stack[i-1] == "(" and rdo_num_stack[i] == "-") {
rdo_count_opp(0);
} else if (rdo_num_stack[i-1] == "(" and rdo_num_stack[i] == "+") {
rdo_count_opp(0);
} else {
rdo_count_opp(1);
}
}
}
for (i = depth; i <= depth+diff;i++) {
if (rdo_num_stack[i] == "+" and rdo_num_stack[i+1] == "-") {
rdo_num_stack.erase(rdo_num_stack.begin()+i);
diff -= 1;
}
if (rdo_num_stack[i] == "-" and rdo_num_stack[i+1] == "+") {
rdo_num_stack.erase(rdo_num_stack.begin()+i+1);
diff -= 1;
}
}
for (i = depth; i <= depth+diff;i++) {
if (rdo_num_stack[i] == "-") {
minus_count++;
if (minus_start == 0) {
minus_start = i;
}
}
if (rdo_num_stack[i] != "-") {
if (minus_count != 0 and minus_count % 2 == 0) {
for (iter = minus_start;iter < minus_start+minus_count;iter++) {
rdo_num_stack[iter] = "";
}
if (rdo_num_stack[minus_start+minus_count] != "" and rdo_num_stack[minus_start+minus_count][0] != '+') {
rdo_num_stack[minus_start+minus_count] = "+" + rdo_num_stack[minus_start+minus_count];
}
minus_start = 0;
minus_count = 0;
} else if (minus_count != 0 and minus_count % 2 != 0) {
for (iter = minus_start;iter < minus_start+minus_count;iter++) {
rdo_num_stack[iter] = "";
}
rdo_num_stack[minus_start+minus_count] = "-" + rdo_num_stack[minus_start+minus_count];
minus_start = 0;
minus_count = 0;
}
}
}
for (i = depth; i <= depth+diff;i++) {
if (rdo_num_stack[i] == "+") {
plus_count++;
if (plus_start == 0) {
plus_start = i;
}
}
if (rdo_num_stack[i] != "+") {
for (iter = plus_start;iter < plus_start+plus_count;iter++) {
rdo_num_stack[iter] = "";
}
if (rdo_num_stack[plus_start+plus_count] != "" and rdo_num_stack[plus_start+plus_count][0] != '(') {
rdo_num_stack[plus_start+plus_count] = "+" + rdo_num_stack[plus_start+plus_count];
}
plus_start = 0;
plus_count = 0;
}
}
for (i = depth+diff;i >= depth;i--) {
if (i - 1 >= depth) {
if (rdo_num_stack[i-1] == "(" and rdo_num_stack[i] != "(" and rdo_num_stack[i][0] != '+' and rdo_num_stack[i][0] != '-' and rdo_num_stack[i] != "") {
rdo_num_stack[i] = "+" + rdo_num_stack[i];
}
if (rdo_num_stack[i] == "/" and rdo_num_stack[i-1][0] != '+' and rdo_num_stack[i-1][0] != '-') {
rdo_num_stack[i-1] = "+" + rdo_num_stack[i-1];
}
if (rdo_num_stack[i] == "/" and rdo_num_stack[i+1][0] != '+' and rdo_num_stack[i+1][0] != '-') {
rdo_num_stack[i+1] = "+" + rdo_num_stack[i+1];
}
if (rdo_num_stack[i] == "*" and rdo_num_stack[i-1][0] != '+' and rdo_num_stack[i-1][0] != '-') {
rdo_num_stack[i-1] = "+" + rdo_num_stack[i-1];
}
if (rdo_num_stack[i] == "*" and rdo_num_stack[i+1][0] != '+' and rdo_num_stack[i+1][0] != '-') {
rdo_num_stack[i+1] = "+" + rdo_num_stack[i+1];
}
}
if (rdo_num_stack[i] == "") {
rdo_num_stack.erase(rdo_num_stack.begin()+i);
diff-=1;
}
}
div_loop:for (i = depth+diff;i >= depth;i--) {
if (rdo_num_stack[i] == "/") {
result = to_string(stof(rdo_num_stack[i-1]) / stof(rdo_num_stack[i+1]));
if (result[0] != '+' and result[0] != '-') {
result = "+" + result;
}
rdo_num_stack[i-1] = result;
rdo_num_stack.erase(rdo_num_stack.begin()+i);
rdo_num_stack.erase(rdo_num_stack.begin()+i);
diff -= 2;
goto div_loop;
}
}
mul_loop:for (i = depth+diff;i >= depth;i--) {
if (rdo_num_stack[i] == "*") {
result = to_string(stof(rdo_num_stack[i-1]) * stof(rdo_num_stack[i+1]));
if (result[0] != '+' and result[0] != '-') {
result = "+" + result;
}
rdo_num_stack[i-1] = result;
rdo_num_stack.erase(rdo_num_stack.begin()+i);
rdo_num_stack.erase(rdo_num_stack.begin()+i);
diff -= 2;
goto mul_loop;
}
}
minus_loop:for (i = depth; i <= depth+diff;i++) {
if (rdo_num_stack[i][0] == '-' and rdo_num_stack[i-1] != "(") {
result = to_string(stof(rdo_num_stack[i]) + stof(rdo_num_stack[i-1]));
if (result[0] != '+' and result[0] != '-') {
result = "+" + result;
}
rdo_num_stack[i-1] = result;
rdo_num_stack.erase(rdo_num_stack.begin()+i);
diff-=1;
goto minus_loop;
}
}
plus_loop:for (i = depth; i <= depth+diff;i++) {
if (rdo_num_stack[i][0] == '+' and rdo_num_stack[i-1] != "(") {
result = to_string(stof(rdo_num_stack[i]) + stof(rdo_num_stack[i-1]));
if (result[0] != '+' and result[0] != '-') {
result = "+" + result;
}
rdo_num_stack[i-1] = result;
rdo_num_stack.erase(rdo_num_stack.begin()+i);
diff-=2;
goto plus_loop;
}
}
opp_count = 0;
for (i = 0; i < rdo_num_stack.size();i++) {
if (rdo_num_stack[i] == "+" or rdo_num_stack[i] == "-" or rdo_num_stack[i] == "*" or rdo_num_stack[i] == "/") {
opp_count++;
}
}
if (opp_count > 0) {
for (i = depth; i < depth+diff;i++) {
if (rdo_num_stack[i] == "(" and rdo_num_stack[i+2] == ")") {
rdo_num_stack.erase(rdo_num_stack.begin()+i);
rdo_num_stack.erase(rdo_num_stack.begin()+i+1);
}
}
}
expr = "";
for (i = 0; i < rdo_num_stack.size();i++) {
expr += rdo_num_stack[i];
}
expr = "";
bcount = 0;
depth = 0;
for (i = 0; i < rdo_num_stack.size();i++) {
expr += rdo_num_stack[i];
if (rdo_num_stack[i] == "(") {
bcount++;
depth = i;
}
}
result = rdo_num_stack[depth+1];
rdo_num_stack.clear();
if (opp_count > 0)
return rdo_eval(expr);
else
expr = to_string(stoi(result));
return expr;
}
int main() {
int i;
cout << rdo_eval("(10 + (20 * - (5 + 9)))") << endl << endl;
return 0;
}