-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmath_expr_parser_postfix.c
More file actions
397 lines (359 loc) · 10.5 KB
/
math_expr_parser_postfix.c
File metadata and controls
397 lines (359 loc) · 10.5 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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
#include "math_expr_parser_postfix.h"
// Function to calculate the result of
// the correct expression
double calc(char *str)
{
int len = strlen(str);
int is_number = 0;
int num_count = 0;
int ops_count = 0;
int ops_len = 0;
int vals_len = 0;
//Get numbers' and operatots' count
for (int i = 0; i < len; i++)
{
if (is_digit(str[i]))
{
if(is_number == 0)
{
num_count++;
is_number = 1;
}
}
else
{
is_number = 0;
if (str[i] != ' ')
{
ops_count++;
}
}
}
// Arrays to store values and operators
double values[num_count];
char ops[ops_count];
for(int i = 0; i < len; i++)
{
// Current symbol is an opening
// brace, add it to 'ops'
if(str[i] == '(')
{
ops[ops_len++] = str[i];
}
// Get number and add it to values' array
else if(is_digit(str[i]))
{
int val = 0;
while(i < len && is_digit(str[i]))
{
val = (val*10) + (str[i]-'0');
i++;
}
values[vals_len++] = val;
// decrease the value of i because it already
// points to the character next to the digit,
// and the for loop will increase the i
i--;
}
// Closing brace encountered, solve
// entire brace.
else if(str[i] == ')')
{
while(ops_len > 0 && ops[ops_len - 1] != '(')
{
char op = ops[--ops_len];
ops[ops_len] = 0;
double val2 = values[--vals_len];
values[vals_len] = 0;
double val1 = values[vals_len - 1];
values[vals_len - 1] = apply_op(val1, val2, op);
}
// Remove opening brace
if(ops_len > 0)
{
ops[--ops_len] = 0;
}
}
else
{
// While the last operator in 'ops' has same or greater
// precedence to the current character, which
// is an operator. Apply the last operator
// of 'ops' to the last two values
while(ops_len > 0 && precedence(ops[ops_len - 1]) >= precedence(str[i]))
{
char op = ops[--ops_len];
ops[ops_len] = 0;
double val2 = values[--vals_len];
values[vals_len] = 0;
double val1 = values[vals_len - 1];
values[vals_len - 1] = apply_op(val1, val2, op);
}
// Add current character to 'ops'
ops[ops_len++] = str[i];
}
}
// Entire expression has been parsed at this
// point, apply remaining ops to remaining
// values.
while(ops_len > 0)
{
char op = ops[--ops_len];
ops[ops_len] = 0;
double val2 = values[--vals_len];
values[vals_len] = 0;
double val1 = values[vals_len - 1];
values[vals_len - 1] = apply_op(val1, val2, op);
}
// The last value is the result
return values[vals_len - 1];
}
// Function to check whether string is correct math expression,
// remove spaces and return constructed string if str is
// correct or 0 if str is incorrect math expression
char *get_str_wo_spaces(char *str)
{
char *str_wo_spaces = 0;
int len = 0;
int i = 0;
int is_bracket = 0;
int brackets_count = 0;
int st_ind = -1;
if (str == 0 || *str == '\n')
{
printf("Error: empty string or there is no string\n");
return str_wo_spaces;
}
// str contains \n, because getline is used for getting string
// get string length without spaces to allocate memory
while (str[i] != '\n')
{
if (str[i] == ' ')
{
i++;
continue;
}
if (st_ind == -1)
{
st_ind = i;
if (str[i] != '(' && str[i] != '-' && !is_digit(str[i]))
{
printf("Error: math expression starts from something which differs from (, - or digit\n");
return str_wo_spaces;
}
}
// increase number of brackets to check whether every ( has the matching )
if (str[i] == '(')
{
is_bracket = 1;
brackets_count++;
}
// increase len to store '0' character before unary - sign
// (1st number after ( is negative)
else if (str[i] == '-' && is_bracket)
{
len++;
}
// decrease number of brackets to check whether every ( has the matching )
else if (str[i] == ')')
{
is_bracket = 0;
brackets_count--;
}
else if (is_bracket)
{
is_bracket = 0;
}
len++;
i++;
}
// ( and ) mismatch
if (brackets_count != 0)
{
printf("Error: different number of ( and )\n");
return str_wo_spaces;
}
// add 2 chars for 0+ at the beginning of every exppression and 1 char for \0
if (!(str_wo_spaces = (char *) malloc(sizeof(char)*(len + 3))))
{
printf("Memory allocation error\n");
return str_wo_spaces;
}
// initialize memory with 0s
memset(str_wo_spaces, 0, len + 3);
str_wo_spaces[0] = '0';
str_wo_spaces[1] = '+';
int j = 1;
is_bracket = 0;
i = 0;
if (str[0] == ' ' || str[0] == '-')
{
// skip spaces
while (i <= len && str[i] == ' ')
{
i++;
}
if (i <= len && str[i] == '-')
{
i++;
if(i <= len && !is_digit(str[i]))
{
while (i <= len && str[i] == ' ')
{
i++;
}
if (i <= len && str[i] != '(')
{
free(str_wo_spaces);
str_wo_spaces = 0;
printf("Error: there is no digit or ( after unary - sign\n");
return str_wo_spaces;
}
else if (str[i] == '(')
{
is_bracket = 1;
}
}
// expr starts from - and there is a digit or ( after -
str_wo_spaces[j] = '-';
}
}
// str contains \n, because getline is used for getting string
while (str[i] != '\n')
{
int is_curr_digit = (str[i] >= '0' && str[i] <= '9');
int is_curr_op = is_operator(str[i]);
if (str[i] != ' ' && !is_curr_digit && !is_curr_op && str[i] != '(' && str[i] != ')')
{
free(str_wo_spaces);
str_wo_spaces = 0;
printf("Error: usage of incorrect symbol. It is allowed only digits, spaces, () and -, +, *, / signs\n");
return str_wo_spaces;
}
// skip spaces
while (str[i] == ' ')
{
i++;
is_curr_digit = (str[i] >= '0' && str[i] <= '9');
is_curr_op = is_operator(str[i]);
}
// current character is operator
if (is_curr_op)
{
if (!is_digit(str_wo_spaces[j]) && str_wo_spaces[j] != ')' && ((str[i] == '-' && str_wo_spaces[j] != '(')) || is_operator(str_wo_spaces[j]))
{
free(str_wo_spaces);
str_wo_spaces = 0;
printf("Error: there is no number before operator or ( before unary -\n");
return str_wo_spaces;
}
// add 0 before unary -
if (str[i] == '-' && str_wo_spaces[j] == '(')
{
str_wo_spaces[++j] = '0';
}
}
// current character is digit
if (is_curr_digit)
{
if ((str_wo_spaces[j] != '(' && !is_digit(str_wo_spaces[j]) && !is_operator(str_wo_spaces[j]))
|| (is_digit(str_wo_spaces[j]) && i > 0 && str[i - 1] == ' ')) // space between digits
{
free(str_wo_spaces);
str_wo_spaces = 0;
printf("Error: something which is differ from digit, ( or +, -, *, / signs before digit\n");
return str_wo_spaces;
}
}
// current character is (
if (str[i] == '(')
{
if (!is_operator(str_wo_spaces[j]) && str_wo_spaces[j] != '(')
{
free(str_wo_spaces);
str_wo_spaces = 0;
printf("Error: there is no operator or ( before (\n");
return str_wo_spaces;
}
}
// current character is )
if (str[i] == ')')
{
if (!is_digit(str_wo_spaces[j]) && str_wo_spaces[j] != ')')
{
free(str_wo_spaces);
str_wo_spaces = 0;
printf("Error: there is no number before )\n");
return str_wo_spaces;
}
}
// add character to output string
str_wo_spaces[++j] = str[i];
i++;
}
if (!is_digit(str_wo_spaces[j]) && str_wo_spaces[j] != ')') // last part is not a number
{
free(str_wo_spaces);
str_wo_spaces = 0;
printf("Error: there is no number or ) at the end of expression\n");
return str_wo_spaces;
}
// return constructed string
return str_wo_spaces;
}
// Function to find operator's precedence
int precedence(char op)
{
if(op == '+' || op == '-')
{
return 1;
}
if(op == '*' || op == '/')
{
return 2;
}
return 0;
}
// Function to perform arithmetic operations
double apply_op(double a, double b, char op)
{
switch(op)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
if (b != 0)
{
return a / b;
}
else
{
printf("Error: division by 0. Result is incorrect\n");
return 0;
}
}
}
// Function to check whether a character is operator or not
int is_operator (const char c)
{
char op[] = {'+', '-', '*', '/'};
for (long unsigned int i = 0; i < sizeof(op); i++)
{
if (c == op[i])
{
return 1;
}
}
return 0;
}
// Function to check whether a character is numeric or not
int is_digit (const char c)
{
return (c >= '0' && c <= '9');
}
// For expression calculation algorithm from
// https://www.geeksforgeeks.org/expression-evaluation/ page is used