I am currently working at this project called "expression evaluator" and I've got some questions about how to code it.
First of all, what does this "expression evaluator" do? It simply evaluates the expression that you inserted, it must support:
I currently managed to transform the string to postfix notation(Reversed Polish Notation) and to evaluate it, but it currently supports only (+, -, *, /, ^) and only just the real and integer constants.
How could I add support for the rest of the operators/variables/formulas?
I have actually tried to add support for variables/formulas but it works only for basic expressions, like: pow(1, 3) + 2, this outputs 3 (TRUE). If I try more complex expressions it happens something like: pow(pow(2, 3), 2), this outputs 512 which is wrong, it should output 64.
Here's my code so you can test it yourself.
#include <algorithm>
#include <cmath>
#include <fstream>
#include <map>
#include <stack>
#include <string>
#include <vector>
#include <iostream>
// Setari
#define __DEBUG__ // Afiseaza informatii despre procesul de rezolvare.
#define __SUPPORT_DOUBLE__ // Activeaza suportul pentru numere reale.
// Variabile
std::vector<std::string> Infix;
std::stack<std::string> operators;
std::stack<std::string> Rezultat;
// Salvez operatorii si nivelul lor de prioritate intr-un dictioar pentru a face procesul de identificare mai rapid
std::map<std::string, short> Operators = { {"+", 1}, {"-", 1}, {"*", 2}, {"/", 2}, {"^", 3}, {"pow", 3}, {"==", 4}, {"=", 5} };
std::ifstream fin("eval.in");
std::ofstream fout("eval.out");
// Functii
// Caut in dictionarul 'Operators' operatorul si, daca-l gasesc returnez prioritatea acestuia.
int CheckOperator(const std::string& op){
const auto& it = Operators.find(op);
if (it != Operators.end())
return it->second;
return 0;
}
int main(){
std::string expr, token;
while (std::getline(fin, token))
expr.append(token);
fin.close();
// Analizez expresie si sterg caracterele inutile( \ ).
expr.erase(std::remove_if(expr.begin(), expr.end(), [](const char& c){ return c == '\\'; }), expr.end());
// Transform expresia in expresie postfix.
for (size_t i = 0; i < expr.length(); ++i){
char c = expr[i];
token.clear();
int prioritate = 0;
token += c;
if (isdigit(c))
{
for (++i; i < expr.length(); ++i){
c = expr[i];
#if defined(__SUPPORT_DOUBLE__)
if (!isdigit(c) && c != '.')
break;
#else
if (!isdigit(c))
break;
#endif
token += c;
}
--i;
Infix.push_back(token);
}
else if(isalpha(c))
{
for (++i; i < expr.length(); ++i){
c = expr[i];
if (!isalnum(c))
break;
token += c;
}
std::cout << "Verificare: " << token << '\n';
--i;
if (CheckOperator(token))
operators.push(token);
else
Infix.push_back(token);
}
else if((prioritate = CheckOperator(token))){
bool numar = false;
for (++i; i < expr.length(); ++i){
c = expr[i];
token += c;
#if defined(__SUPPORT_DOUBLE__)
if (!CheckOperator(token) && !isdigit(c) && c != '.'){
token.erase(token.length() - 1, token.length());
break;
}
#else
if (!CheckOperator(token) && !isdigit(c)){
token.erase(token.length() - 1, token.length());
break;
}
#endif
if (isdigit(c))
numar = true;
}
--i;
if (!numar){
while(!operators.empty() && CheckOperator(operators.top()) >= prioritate)
{
Infix.push_back(operators.top());
operators.pop();
}
operators.push(token);
}
else
{
Infix.push_back(token);
}
}
else if (c == '(')
{
operators.push("(");
}
else if (c == ')')
{
while (!operators.empty())
{
if (operators.top() == "("){
operators.pop();
break;
}
Infix.push_back(operators.top());
operators.pop();
}
}
}
while (!operators.empty())
{
Infix.push_back(operators.top());
operators.pop();
}
#if defined(__DEBUG__)
for (const auto& ex : Infix)
fout << ex << ' ';
fout << '\n';
#endif
auto& it = Infix.begin();
for(; it != Infix.end(); ++it)
{
if (CheckOperator(*it))
{
if (*it == "+")
{
long double b = std::stold(Rezultat.top());
Rezultat.pop();
long double a = std::stold(Rezultat.top());
Rezultat.pop();
Rezultat.push(std::to_string(a + b));
}
else if(*it == "-")
{
long double b = std::stold(Rezultat.top());
Rezultat.pop();
long double a = std::stold(Rezultat.top());
Rezultat.pop();
Rezultat.push(std::to_string(a - b));
}
else if(*it == "*")
{
long double b = std::stold(Rezultat.top());
Rezultat.pop();
long double a = std::stold(Rezultat.top());
Rezultat.pop();
Rezultat.push(std::to_string(a * b));
}
else if(*it == "/")
{
long double b = std::stold(Rezultat.top());
Rezultat.pop();
long double a = std::stold(Rezultat.top());
Rezultat.pop();
Rezultat.push(std::to_string(a / b));
}
else if(*it == "^")
{
long double b = std::stold(Rezultat.top());
Rezultat.pop();
long double a = std::stold(Rezultat.top());
Rezultat.pop();
Rezultat.push(std::to_string(std::powl(a, b)));
}
else if(*it == "==")
{
long double b = std::stold(Rezultat.top());
Rezultat.pop();
long double a = std::stold(Rezultat.top());
Rezultat.pop();
Rezultat.push(std::to_string(a == b));
}
else if(*it == "pow")
{
long double b = std::stold(Rezultat.top());
Rezultat.pop();
long double a = std::stold(Rezultat.top());
Rezultat.pop();
Rezultat.push(std::to_string(std::powl(a, b)));
}
}
else
{
Rezultat.push(*it);
}
}
#if defined(__SUPPORT_DOUBLE__)
fout << Rezultat.top() << '\n';
#else
fout << std::stol(Rezultat.top()) << '\n';
#endif
return 0;
}
Thank you!
Edit: I have posted a solution on Github if you need it.
It isn't quite clear what you mean by "formulas".
Variables in the shunting yard algorithm behave in exactly the same way as numbers, no difference whatsoever.
An assignment x = y
can be treated as just another kind of expression. You want to add the =
operator to your list of supported operators. Just choose its precedence.
Obviously the evaluator needs to distinguish variables from constants and expressions, so that it can signal an error in each of these cases:
x + 2 (undefined x)
2 = 5 (assignment to non-variable)
(1+2) = 3 (same)
Note that you want to be able to evaluate several expressions now, so that you may evaluate var = 50
and then 1 + var
as two separate expressions. Devise a way to separate them. The ;
character will work just fine for this purpose.
Also note that having =
to serve for both comparison and assignment is really really not advised. You want to either change the comparison to ==
as most programming languages do these days, or change the assignment to use some other symbol, say :=
or <-
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.