Skip to main content
Code Review

Return to Revisions

3 of 3
Commonmark migration

Four-function expression evaluator

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)))
  1. It first does the deepest brackets.

    (10 + (20 * -14))
    
  2. Then, since there's a minus it multiplies the result of the brackets by -1.

    (10 + (-280))
    
  3. Then it does the multiply in the brackets.

    (-270)
    
  4. Then it does the addition with the 10 and the -280.

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <functional>
using namespace std;
vector<string> 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;
}
Francis
  • 557
  • 6
  • 10
lang-cpp

AltStyle によって変換されたページ (->オリジナル) /