-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathExpressionUtils.cpp
More file actions
executable file
·220 lines (200 loc) · 6.81 KB
/
ExpressionUtils.cpp
File metadata and controls
executable file
·220 lines (200 loc) · 6.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
//
// Created by elad on 18/12/18.
//
#include "ExpressionUtils.h"
using namespace std;
/**
* calculate infix string by converting it to prefix using dijkstra’s shunting yard variant,
* then converts that to a complex expression, calculates it, and return the result.
*/
double ExpressionUtils::calculateInfixStr(const string &infix, unordered_map<string, double> assignment) {
queue<string> prefixQueue = infixToPrefixQueue(infix);
Expression *exp = queueToExp(prefixQueue);
return exp->calculate(assignment);
}
/** Find precedence of operators. **/
int ExpressionUtils::precedence(const string &op) {
if (op == "+" || op == "-")
return 1;
if (op == "*" || op == "/")
return 2;
return 0;
}
void ExpressionUtils::treatNegBracesAndSpaces(string &infix){
//delete spaces
std::string::iterator end_pos = std::remove(infix.begin(), infix.end(), ' ');
infix.erase(end_pos, infix.end());
string toSearch="-(";
string replaceStr="-1*(";
// Get the first occurrence
size_t pos = infix.find(toSearch);
// Repeat till end is reached
while( pos != std::string::npos)
{
// Replace this occurrence of Sub String
infix.replace(pos, toSearch.size(), replaceStr);
// Get the next occurrence from the current position
pos =infix.find(toSearch, pos + toSearch.size());
}
}
/**
* converts infix string to prefix using dijkstra’s shunting yard variant.
*/
queue<string> ExpressionUtils::infixToPrefixQueue(const string &infixToChange) {
//string copy
string infix=infixToChange;
// stack to store operators.
stack<string> stackOp;
// queue to store vals and operators.
queue<string> queueValOp;
bool flagOp = true;
bool isNeg = false;
treatNegBracesAndSpaces(infix);
for (unsigned int i = 0; i < infix.length(); i++) {
// whitespace- skip.
if (isspace(infix[i]))
continue;
//opening brace - push to stack
else if (infix[i] == '(') {
//negative braces are taken care of in treatNegBraces method
isNeg=false;
flagOp=true;
stackOp.push(string(1, infix[i]));
}
// number-push to the values queue
else if (isdigit(infix[i])) {
string valStr;
if (isNeg) {
valStr = "-";
isNeg = false;
}
while (isdigit(infix[i]) || infix[i] == '.') {
valStr += infix[i];
i++;
}
i--;
queueValOp.push(valStr);
flagOp = false;
}
//variable- push to queue
else if (((infix[i] >= 'a') && (infix[i] <= 'z')) || ((infix[i] >= 'A') && (infix[i] <= 'Z'))) {
string varStr;
if (isNeg) {
varStr = "-";
isNeg = false;
}
while (infix[i] != '+' && infix[i] != '-' && infix[i] != '*' && infix[i] != '/' && infix[i] != ')' &&
i < infix.length() && !isspace(infix[i])) {
varStr += infix[i];
++i;
}
--i;
queueValOp.push(varStr);
flagOp = false;
}
// Closing braces
else if (infix[i] == ')') {
while (!stackOp.empty() && stackOp.top() != "(") {
//pop operator from stack onto queue
queueValOp.push(stackOp.top());
stackOp.pop();
}
if (stackOp.top() == "(") {
// pop opening brace.
stackOp.pop();
} else {
throw "Opening braces missing";
}
flagOp = false;
}
//operator
else {
if (infix[i] == '-') {
if (flagOp) {
isNeg = true;
continue;
}
}if (infix[i] == '+') { //redundant
if(flagOp){
continue;
}
}
flagOp = true;
//while the top of operators stack has equal or greater precedence than the current token(operator)
while (!stackOp.empty() && precedence(stackOp.top()) >= precedence(string(1, infix[i]))) {
//pop operator from stack onto queue
queueValOp.push(stackOp.top());
stackOp.pop();
}
stackOp.push(string(1, infix[i]));
}
}
//no more tokens to read
while (!stackOp.empty()) {
//pop operator from stack onto queue
queueValOp.push(stackOp.top());
stackOp.pop();
}
return queueValOp;
}
/**
* converts queue of strings(as prefix) to a complex Expression.
*/
Expression *ExpressionUtils::queueToExp(queue<string> &queueValOp) {
//all tokens in queue - convert to Expressions
stack<Expression *> expStack;
while (!queueValOp.empty()) {
Expression *num;
Expression *neg;
Expression *var;
//take number from front
string front = queueValOp.front();
queueValOp.pop();
if (front == "+" || front == "-" || front == "*" || front == "/") {//operator
Expression *secondNum = expStack.top();
expStack.pop();
Expression *firstNum = expStack.top();
expStack.pop();
Expression *exp;
if (front == "+") {
exp = new Plus(firstNum, secondNum);
deathMap.push_back(exp);
} else if (front == "-") {
exp = new Minus(firstNum, secondNum);
deathMap.push_back(exp);
} else if (front == "/") {
exp = new Div(firstNum, secondNum);
deathMap.push_back(exp);
} else if (front == "*") {
exp = new Mult(firstNum, secondNum);
deathMap.push_back(exp);
}
expStack.push(exp);
} else if (front[0] == '-') {//neg num
front.erase(front.find('-'), 1);
if (isdigit(front[0])) {//num
num = new Num(stod(front));
deathMap.push_back(num);
neg = new Neg(num);
deathMap.push_back(neg);
expStack.push(neg);
} else { //var
var = new Var(front);
deathMap.push_back(var);
neg = new Neg(var);
deathMap.push_back(neg);
expStack.push(neg);
}
} else if (isdigit(front[0])) {//num
num = new Num(stod(front));
deathMap.push_back(num);
expStack.push(num);
} else { //var
var = new Var(front);
deathMap.push_back(var);
expStack.push(var);
}
}
//only one (complex) expression left on stack
return expStack.top();
}