e2c4673f4106d4c80074cc30b22e5f471cec3f45
[calc.git] / parser.c
1 #include <malloc.h>
2 #include <math.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5
6 #include "debug.h"
7
8 #include "parser.h"
9
10 /* global variables */
11
12 double answer = 0;
13
14 #define STORAGE_SIZE 10
15 double storage[STORAGE_SIZE] = {0};
16
17 /* compare codes */
18
19 int codecmp (char *ref, char *str)
20 {
21 int sig;
22
23 while (*ref != '\0') {
24 if (*ref == '\t') {
25 sig = (*str == '.') ? -1 : ((*str >= '0') && (*str <= '9'));
26 } else {
27 sig = *str - *ref;
28 }
29 if (sig != 0) {
30 return (sig > 0) ? 1 : -1;
31 }
32 str++;
33 ref++;
34 }
35
36 return 0;
37 }
38
39 /* allocate new element */
40
41 element_t *newelement (func_t function, int nbops, int prio)
42 {
43 element_t *new = (element_t *) calloc (1, sizeof (element_t));
44 if (new == NULL) {
45 VERBOSE (ERROR, fprintf (stderr, "can't allocate memory\n"));
46 return NULL;
47 }
48 new->func = function;
49 new->nbops = nbops;
50 new->prio = prio;
51
52 return new;
53 }
54
55 /* desallocate element */
56
57 void delelement (element_t *root)
58 {
59 int i;
60 if ((root != NULL) && (root != ERROR_OP)) {
61 for (i = 0; i < root->nbops; i++) {
62 if ((root->ops[i] != NULL) && (root->ops[i] != ERROR_OP)) {
63 delelement (root->ops[i]);
64 }
65 }
66 free (root);
67 }
68 }
69
70 /* functions */
71
72 #define NB_OPERATORS 6
73
74 keyword_t operators[NB_OPERATORS] = {
75 { "+\t", Add, 2, 1, 1},
76 { "-\t", Sub, 2, 1, 1},
77 { "*", Mul, 2, 1, 2},
78 { "/", Div, 2, 1, 2},
79 { "%", Mod, 2, 1, 3},
80 { "^", Pow, 2, 1, 4}
81 };
82
83 #define NB_FUNCTIONS 12
84 keyword_t functions[NB_FUNCTIONS] = {
85 { "sqrt", Sqr, 1, 4, 5},
86 { "pow", Pow, 2, 3, 5},
87 { "cos", Cos, 1, 3, 5},
88 { "sin", Sin, 1, 3, 5},
89 { "atan", Atan, 1, 4, 5},
90 { "exp", Exp, 1, 3, 5},
91 { "log", Log, 1, 3, 5},
92 { "sto", Store, 1, 3, 5},
93 { "rcl", Recall, 1, 3, 5},
94 { "disp", Disp, 0, 4, 5},
95 { "quit", Quit, 0, 4, 5},
96 { "help", Help, 0, 4, 5}
97 };
98
99 #define NB_CONSTANTS 3
100 keyword_t constants[NB_CONSTANTS] = {
101 { "ans", Ans, 0, 3, 5},
102 { "e", E, 0, 1, 5},
103 { "pi", Pi, 0, 2, 5}
104 };
105
106 /* subparser function */
107
108 element_t *subparser (element_t **proot, char **pstr, func_t func, int nbops, int prio)
109 {
110 element_t *new = newelement (func, nbops, prio);
111 if (new == NULL) {
112 return ERROR_OP;
113 }
114 new->ops[0] = *proot;
115 new->ops[1] = parser (*pstr, pstr, new->prio);
116 if (new->ops[1] == ERROR_OP) {
117 delelement (new);
118 *proot = NULL;
119 return ERROR_OP;
120 }
121 *proot = newelement (Val, 1, 5);
122 if (*proot == NULL) {
123 delelement (new);
124 return ERROR_OP;
125 }
126 (*proot)->ops[0] = new;
127
128 return *proot;
129 }
130
131 /* parser function */
132
133 element_t *parser (char *str, char **next, int prio)
134 {
135 element_t *root = NULL;
136 int i;
137
138 VERBOSE (DEBUG, fprintf (stdout, "Starting parsing\n"));
139
140 /* main loop */
141 while (*str != '\0') {
142 int found = 0;
143 element_t *new = NULL;
144 VERBOSE (INFO, fprintf (stdout, "Processing: %s\n", str));
145
146 /* skip spaces and tabs */
147
148 if ((*str == ' ') || (*str == '\t')) {
149 str++;
150 continue;
151 }
152
153 /* check for open bracket */
154
155 if (*str == '(') {
156 VERBOSE (DEBUG, fprintf (stdout, "start processing bracket\n"));
157 if (root) {
158 do {
159 found = 0;
160 new = parser (str + 1, &str, 0);
161 if (new == ERROR_OP) {
162 delelement (root);
163 return ERROR_OP;
164 }
165 for (i = 0; i < root->nbops; i++) {
166 if (root->ops[i] == NULL) {
167 root->ops[i] = new;
168 found = 1;
169 break;
170 }
171 }
172 if (!found) {
173 delelement (new);
174 delelement (root);
175 return ERROR_OP;
176 }
177 } while (*str == ',');
178 } else {
179 root = newelement (Val, 1, 5);
180 if (root == NULL) {
181 return ERROR_OP;
182 }
183 new = parser (str + 1, &str, 0);
184 if ((new == ERROR_OP) || (*str == ',')) {
185 delelement (new);
186 delelement (root);
187 return ERROR_OP;
188 }
189 root->ops[0] = new;
190 }
191 str++;
192 VERBOSE (DEBUG, fprintf (stdout, "stop processing bracket\n"));
193 continue;
194 }
195
196 /* check for closing bracket or koma */
197
198 if ((*str == ')') || (*str == ',')) {
199 if (next != NULL) {
200 *next = str;
201 }
202 return root;
203 }
204
205 /* look for operators */
206
207 for (i = 0; i < NB_OPERATORS; i++) {
208 keyword_t *operator = operators + i;
209 if (codecmp (operator->keyword, str) == 0) {
210 VERBOSE (DEBUG, fprintf (stdout, "start processing operator\n"));
211 if (root) {
212 if ((prio) && (prio > operator->prio)) {
213 VERBOSE (DEBUG, fprintf (stdout, "stop because operator priority\n"));
214 *next = str;
215 return root;
216 }
217 str += operator->offset;
218 VERBOSE (INFO, fprintf (stdout, "Oper: %d\n", operator->func));
219 if (subparser (&root, &str, operator->func, operator->nbops, operator->prio) == ERROR_OP) {
220 delelement (root);
221 return ERROR_OP;
222 }
223 } else if (*str == '-') {
224 new = newelement (Sig, 1, 9);
225 if (new == NULL) {
226 return ERROR_OP;
227 }
228 root = new;
229 } else {
230 return ERROR_OP;
231 }
232 found = 1;
233 VERBOSE (DEBUG, fprintf (stdout, "stop processing operator\n"));
234 break;
235 }
236 }
237 if (found) {
238 continue;
239 }
240
241 /* look for functions */
242
243 for (i = 0; i < NB_FUNCTIONS; i++) {
244 keyword_t *function = functions + i;
245 if (codecmp (function->keyword, str) == 0) {
246 VERBOSE (DEBUG, fprintf (stdout, "start processing function\n"));
247 if (root == NULL) {
248 VERBOSE (INFO, fprintf (stdout, "Func: %d\n", function->func));
249 new = newelement (function->func, function->nbops, function->prio);
250 if (new == NULL) {
251 return ERROR_OP;
252 }
253 root = new;
254 } else {
255 delelement (root);
256 return ERROR_OP;
257 }
258 str += function->offset;
259 found = 1;
260 VERBOSE (DEBUG, fprintf (stdout, "stop processing function\n"));
261 break;
262 }
263 }
264 if (found) {
265 continue;
266 }
267
268 /* look for constant */
269
270 for (i = 0; i < NB_CONSTANTS; i++) {
271 keyword_t *constant = constants + i;
272 if (codecmp (constant->keyword, str) == 0) {
273 VERBOSE (DEBUG, fprintf (stdout, "start processing constant\n"));
274 if (root == NULL) {
275 VERBOSE (INFO, fprintf (stdout, "Const: %d\n", constant->func));
276 new = newelement (constant->func, constant->nbops, constant->prio);
277 if (new == NULL) {
278 return ERROR_OP;
279 }
280 root = new;
281 } else {
282 delelement (root);
283 return ERROR_OP;
284 }
285 str += constant->offset;
286 found = 1;
287 VERBOSE (DEBUG, fprintf (stdout, "stop processing constant\n"));
288 break;
289 }
290 }
291 if (found) {
292 continue;
293 }
294
295 /* look for number */
296
297 if (((*str >= '0') && (*str <= '9')) ||
298 (*str == '.') || (*str == '+') || (*str == '-')) {
299 VERBOSE (DEBUG, fprintf (stdout, "start processing value\n"));
300 char *pt;
301 double value = strtod (str, &pt);
302 VERBOSE (INFO, fprintf (stdout, "Value: %f\n", value));
303 if (str != pt) {
304 if (root == NULL) {
305 new = newelement (Val, 1, 5);
306 if (new == NULL) {
307 return ERROR_OP;
308 }
309 new->value = value;
310 root = new;
311 str = pt;
312 } else if ((*str == '+') || (*str == '-')) {
313 if ((prio) && (prio > 1)) {
314 VERBOSE (DEBUG, fprintf (stdout, "stop because operator priority\n"));
315 *next = str;
316 return root;
317 }
318 if (subparser (&root, &str, Add, 2, 1) == ERROR_OP) {
319 delelement (root);
320 return ERROR_OP;
321 }
322 } else {
323 delelement (root);
324 return ERROR_OP;
325 }
326 found = 1;
327 }
328 VERBOSE (DEBUG, fprintf (stdout, "stop processing value\n"));
329 }
330
331 /* error */
332
333 if (!found) {
334 delelement (root);
335 return ERROR_OP;
336 }
337
338 }
339
340 if (next != NULL) {
341 *next = str;
342 }
343
344 return root;
345 }
346
347 /* print element tree */
348
349 void print_element (element_t *root, int level)
350 {
351 char *func = NULL;
352 int i;
353
354 if ((root == NULL) || (root == ERROR_OP)) {
355 return;
356 }
357
358 for (i = 0; i < level; i++) {
359 fprintf (stdout, " ");
360 }
361
362 switch (root->func) {
363 case Val: func = "Value"; break;
364 case Sig: func = "Sign"; break;
365 case Add: func = "Addition"; break;
366 case Sub: func = "Subtraction"; break;
367 case Mul: func = "Multiplication"; break;
368 case Div: func = "Division"; break;
369 case Mod: func = "Modulo"; break;
370 case Pow: func = "Power"; break;
371 case Sqr: func = "Square Root"; break;
372 case Cos: func = "Cosine"; break;
373 case Sin: func = "Sine"; break;
374 case Atan: func = "Arc Tangent"; break;
375 case Log: func = "Logarithm"; break;
376 case Exp: func = "Exponantial"; break;
377 case Store: func = "Store"; break;
378 case Recall: func = "Recall"; break;
379 case Disp: func = "Display"; break;
380 case Quit: func = "Quit"; break;
381 case Help: func = "Help"; break;
382 case Ans: func = "Ans"; break;
383 case Pi: func = "Pi"; break;
384 case E: func = "E"; break;
385 }
386
387 fprintf (stdout, "Function: %s\n", func);
388
389 if ((root->func == Val) && (root->ops[0] == NULL)) {
390 for (i = 0; i < level; i++) {
391 fprintf (stdout, " ");
392 }
393 fprintf (stdout, "value: %f\n", root->value);
394 } else {
395 for (i = 0; i < root->nbops; i++) {
396 print_element (root->ops[i], level + 1);
397 }
398 }
399 }
400
401 /* storage functions */
402
403 double store (int index)
404 {
405 if ((index > 0) && (index <= STORAGE_SIZE)) {
406 storage[index - 1] = answer;
407 } else {
408 VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [1, %d]\n", index, STORAGE_SIZE));
409 }
410 return answer;
411 }
412
413 double recall (int index)
414 {
415 if ((index > 0) && (index <= STORAGE_SIZE)) {
416 return storage[index - 1];
417 } else {
418 VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [1, %d]\n", index, STORAGE_SIZE));
419 }
420 return 0;
421 }
422
423 void display (void)
424 {
425 int i;
426 fprintf (stdout, "storage:");
427 for (i = 0; i < STORAGE_SIZE; i++) {
428 fprintf (stdout, " %g", storage[i]);
429 }
430 fprintf (stdout, "\n");
431 }
432
433 /* quit function */
434
435 void quit (void)
436 {
437 fprintf (stdout, "bye\n");
438 exit (0);
439 }
440
441 /* help message */
442
443 void help (void)
444 {
445 fprintf (stdout, "calc is a simple calculator\n\n");
446 fprintf (stdout, "supported operators:\n");
447 fprintf (stdout, " + - * / %% ^\n\n");
448 fprintf (stdout, "supported functions:\n");
449 fprintf (stdout, " pow sqrt cos sin atan log exp\n\n");
450 fprintf (stdout, "storage functions:\n");
451 fprintf (stdout, " sto rcl\n\n");
452 fprintf (stdout, "miscellaneous functions:\n");
453 fprintf (stdout, " quit help\n\n");
454 fprintf (stdout, "supported constants:\n");
455 fprintf (stdout, " e pi\n");
456 }
457
458 /* evaluate element tree */
459
460 #define MASK_SUB 0x1
461 #define MASK_DIV 0x2
462
463 double evaluate_element (element_t *root, char mask)
464 {
465 double op0 = 0, op1 = 0;
466 char nextmask = mask;
467
468 if ((root == NULL) || (root == ERROR_OP)) {
469 VERBOSE (WARNING, fprintf (stdout, "error while evaluating\n"));
470 return 0;
471 }
472
473 /* mask to manage sub operator sub and div */
474 switch (root->func) {
475 case Add:
476 nextmask &= ~MASK_SUB;
477 nextmask &= ~MASK_DIV;
478 break;
479 case Sub:
480 nextmask |= MASK_SUB;
481 nextmask &= ~MASK_DIV;
482 break;
483 case Mul:
484 nextmask &= ~MASK_DIV;
485 break;
486 case Div:
487 nextmask |= MASK_DIV;
488 break;
489 default:
490 nextmask = mask;
491 }
492
493 switch (root->func) {
494 case Val:
495 case Sig:
496 op0 = (root->ops[0]) ? evaluate_element (root->ops[0], nextmask) : root->value;
497 break;
498 case Add:
499 case Sub:
500 case Mul:
501 case Div:
502 case Mod:
503 case Pow:
504 if (root->ops[1]) {
505 op1 = evaluate_element (root->ops[1], nextmask);
506 } else {
507 VERBOSE (WARNING, fprintf (stdout, "error while evaluating (op[1])\n"));
508 return 0;
509 }
510 /* fallthrough */
511 case Sqr:
512 case Cos:
513 case Sin:
514 case Atan:
515 case Log:
516 case Exp:
517 case Store:
518 case Recall:
519 if (root->ops[0]) {
520 op0 = evaluate_element (root->ops[0], 0);
521 } else {
522 VERBOSE (WARNING, fprintf (stdout, "error while evaluating (op[0])\n"));
523 return 0;
524 }
525 break;
526 case Disp:
527 case Quit:
528 case Help:
529 case Ans:
530 case Pi:
531 case E:
532 break;
533 }
534
535 switch (root->func) {
536 case Val: return op0;
537 case Sig: return -op0;
538 case Add: return ((mask & MASK_SUB) == 0) ? op0 + op1 : op0 - op1;
539 case Sub: return ((mask & MASK_SUB) == 0) ? op0 - op1 : op0 + op1;
540 case Mul: return ((mask & MASK_DIV) == 0) ? op0 * op1 : op0 / op1;
541 case Div: return ((mask & MASK_DIV) == 0) ? op0 / op1 : op0 * op1;
542 case Mod: return fmod (op0, op1);
543 case Pow: return pow (op0, op1);
544 case Sqr: return sqrt (op0);
545 case Cos: return cos (op0);
546 case Sin: return sin (op0);
547 case Atan: return atan (op0);
548 case Log: return log (op0);
549 case Exp: return exp (op0);
550 case Store: return store ((int)op0);
551 case Recall: return recall ((int)op0);
552 case Disp: display (); break;
553 case Quit: quit (); break;
554 case Help: help (); break;
555 case Ans: return answer;
556 case Pi: return M_PI;
557 case E: return M_E;
558 }
559
560 return 0;
561 }
562
563 /* vim: set ts=4 sw=4 et: */