Take the result of an expression in c++

Asked

Viewed 178 times

1

I’m almost done with my expression interpreter. But I have no idea how to do the most important part : The result

I’d learn a lot from any idea.

main.cpp

#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <cmath>
#include <algorithm>

//defines
#define space ' '

//disables any deprecation warning
#pragma warning(disable : 4996)

//usings
using std::vector;
using std::string;
using std::cout;
using std::endl;

long double nabs(long double dub) {
    return -abs(dub);
}

string remove_char(string str, char c = space) {
    str.erase(std::remove(str.begin(), str.end(), c), str.end());
    return str;
}

long double parse(string str) {
    return std::stold(str);
}

bool try_parse(string str)
{
    char* end = 0;
    double val = strtod(str.c_str(), &end);
    return end != str.c_str() && val != HUGE_VAL;
}

char first_char(string str) {
    return *str.c_str();
}

bool is_opr(string str) {
    return first_char(str) == '&';
}

string &first_item(vector<string> vec) {
    return vec[0];
}

vector<string> get_types(vector<string> vec) {
    for (int i = 0; i < vec.size(); i++) {
        string &s = vec[i];
        bool doubly = try_parse(s);
        bool amp = is_opr(s);

        //if unknown
        if (!doubly && !amp) {
            s = "<unk> " + s;
            continue;
        }
        //if operator
        else if (!doubly && amp) {
            s = "<opr> " + s;
            continue;
        }
        //if number
        else if (doubly && !amp) {
            s = "<dub> " + s;
            continue;
        }

    }
    return vec;
}

/*
  |
  |
  |
  V
*/
long double get_result(vector<string> vec) {
    long double val;
    for (int i = 0; i < vec.size(); i++) {
        //código...
    }
    return val;
}

vector<string> split(string s, const char c = space)
{
    string buff{ "" };
    vector<string> v;

    for (auto n : s)
    {
        if (n != c) buff += n; else
            if (n == c && buff != "") { v.push_back(buff); buff = ""; }
    }
    if (buff != "") v.push_back(buff);

    return v;
}

string simplify(string expr) {
    string iexpr = expr;
    for (int i = 0; i < iexpr.length(); i++) {

        char& c = iexpr[i];

        if (c == '+')
            iexpr.replace(i, 1, " &ad ");
        else if (c == '-')
            iexpr.replace(i, 1, " &sb ");
        else if (c == '*')
            iexpr.replace(i, 1, " &mp ");
        else if (c == '/')
            iexpr.replace(i, 1, " &dv ");

    }
    return iexpr;
}


int main() {

    vector<string> sep_rep = get_types(split(simplify("-21 + 32 - 3 * 2")));
    for (auto str : sep_rep) {
        cout << str << endl;
    }

    std::cin.get();
    return 0;
}
  • It depends. To get the result, you will have to do the syntactic analysis of this vector<string> and then interpret the result. If you just need something silly that doesn’t have parentheses or operator precedence, it’s not very difficult, but it won’t be very functional either. If you need something that you have or will have after parentheses and precedence, then it is a very laborious thing and the result will be a code significantly larger than what you did for the lexical analysis.

  • What you’re trying to do is syntactic analysis. If you’re not just looking for something simple and silly, I recommend reading this to get started: https://answall.com/q/181635/132 and then read this too: https://answall.com/q/180927/132. It’s worth seeing this one too: https://answall.com/q/2044/132

  • Related question (not duplicate): https://answall.com/q/308306/132

  • I’ll start with the silly one then think about seeing something bigger.

  • Vitor Stafusa, This related question is mine

  • 1

    I know. I usually put this kind of comment on serial questions so that other users who bump into your question don’t think it’s duplicate of the other. Or else those who don’t understand something, who see your other question to understand.

Show 1 more comment

1 answer

0

It took a lot of work to do that.

#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <cmath>
#include <algorithm>

//defines
#define space ' '

//disables any deprecation warning
#pragma warning(disable : 4996)

//usings
using std::vector;
using std::string;
using std::cout;
using std::endl;

long double nabs(long double dub) {
    return -abs(dub);
}

string remove_char(string str, char c = space) {
    str.erase(std::remove(str.begin(), str.end(), c), str.end());
    return str;
}

long double parse(string str) {
    return std::stold(str);
}

bool try_parse(string str) {
    char* end = 0;
    long double val = strtold(str.c_str(), &end);
    return end != str.c_str() && val != HUGE_VALL && val != -HUGE_VALL;
}

char first_char(string str) {
    return *str.c_str();
}

bool is_opr(string str) {
    return first_char(str) == '&';
}

string &first_item(vector<string> vec) {
    return vec[0];
}

vector<string> get_types(vector<string> vec) {
    for (int i = 0; i < vec.size(); i++) {
        string &s = vec[i];
        bool doubly = try_parse(s);
        bool amp = is_opr(s);

        //if unknown
        if (!doubly && !amp) {
            s = "<unk> " + s;
            continue;
        }
        //if operator
        else if (!doubly && amp) {
            s = "<opr> " + s;
            continue;
        }
        //if number
        else if (doubly && !amp) {
            s = "<dub> " + s;
            continue;
        }

    }
    return vec;
}

long double interpretar_numero(string dub) {
    if (dub.substr(0, 6).compare("<dub> ") != 0) {
        throw "Não deu para interpretar como número " + dub;
    }
    return parse(dub.substr(6));
}

long double get_result(vector<string> vec) {
    if (vec.at(0).compare("<opr> &sb") == 0 || vec.at(0).compare("<opr> &ad") == 0) {
        vec.insert(vec.begin(), "<dub> 0");
    }
    long double val = interpretar_numero(vec.at(0));
    for (int i = 1; i < vec.size(); i += 2) {
        std::string op = vec.at(i);
        if (vec.size() == i + 1) throw "Esperava um número antes do fim";
        long double ot = interpretar_numero(vec.at(i + 1));

        if (op.compare("<opr> &ad") == 0) {
            val += ot;
        } else if (op.compare("<opr> &sb") == 0) {
            val -= ot;
        } else if (op.compare("<opr> &mp") == 0) {
            val *= ot;
        } else if (op.compare("<opr> &dv") == 0) {
            val /= ot;
        } else {
            throw "Esperava um operador";
        }
    }
    return val;
}

vector<string> split(string s, const char c = space) {
    string buff{ "" };
    vector<string> v;

    for (auto n : s) {
        if (n != c) {
            buff += n;
        } else if (n == c && buff != "") {
            v.push_back(buff);
            buff = "";
        }
    }
    if (buff != "") v.push_back(buff);

    return v;
}

string simplify(string expr) {
    string iexpr = expr;
    for (int i = 0; i < iexpr.length(); i++) {

        char& c = iexpr[i];

        if (c == '+') {
            iexpr.replace(i, 1, " &ad ");
        } else if (c == '-') {
            iexpr.replace(i, 1, " &sb ");
        } else if (c == '*') {
            iexpr.replace(i, 1, " &mp ");
        } else if (c == '/') {
            iexpr.replace(i, 1, " &dv ");
        }
    }
    return iexpr;
}

int main() {

    vector<string> sep_rep = get_types(split(simplify("-21 + 32 - 3 * 2")));
    for (auto str : sep_rep) {
        cout << str << endl;
    }
    try {
        cout << "R: " << get_result(sep_rep) << endl;
    } catch (const char *e) {
        cout << "Erro: " << e;
    } catch (string e) {
        cout << "Erro: " << e;
    }

    std::cin.get();
    return 0;
}

The function get_result(vector<string>) it got pretty complicated, but what she does is this:

  1. If there’s a plus or minus sign at the beginning, put a zero before.
  2. Interprets the first element of the vector as a number and puts the corresponding value in val.
  3. Interprets the following elements of the vector as pairs in format [op, ot], where ot are the numbers are in odd positions and op are the operators in the even positions.
  4. For each pair [op, ot], uses the operator op with the values val and ot and keeps the result in val.
  5. If the vector does not have an odd amount of strings, or if the val or the ot cannot be interpreted as numbers or if the op cannot be interpreted as an operator, throws a string as an exception.

The generated output is as follows:

<opr> &sb
<dub> 21
<opr> &ad
<dub> 32
<opr> &sb
<dub> 3
<opr> &mp
<dub> 2
R: 16

The reason he’s 16 is that he turns "- 21 + 32 - 3 * 2" in "0 - 21 + 32 - 3 * 2". So he plays the "0" as val. Makes "0 - 21" and comes to -21 as an answer. It does "-21 + 32" and arrives in 11. Makes "11 - 3" and arrives in 8. And finally, it does "8 * 2" and arrives in 16.

See here working on ideone.

  • It was useful... But I need to know what the "compare()" function is for

  • @MariaCristina http://www.cplusplus.com/reference/string/string/compare/

  • Call me Gabriel, it’s my name,"

Browser other questions tagged

You are not signed in. Login or sign up in order to post.