c3472876572965c8ee7ce7a92c50d9b635fc6186
[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 14
73 keyword_t operators[NB_OPERATORS] = {
74 { "+\t", Add, 2, 1, 1},
75 { "-\t", Sub, 2, 1, 1},
76 { "*", Mul, 2, 1, 2},
77 { "/", Div, 2, 1, 2},
78 { "%", Mod, 2, 1, 3},
79 { "^", Pow, 2, 1, 4},
80 { "==", Equal, 2, 2, -1},
81 { "!=", Diff, 2, 2, -1},
82 { ">=", Ge, 2, 2, -1},
83 { "<=", Le, 2, 2, -1},
84 { ">", Gt, 2, 1, -1},
85 { "<", Lt, 2, 1, -1},
86 { "&", And, 2, 1, -2},
87 { "|", Or, 2, 1, -2}
88 };
89
90 #define NB_FUNCTIONS 16
91 keyword_t functions[NB_FUNCTIONS] = {
92 { "sqrt", Sqr, 1, 4, 5},
93 { "pow", Pow, 2, 3, 5},
94 { "cos", Cos, 1, 3, 5},
95 { "sin", Sin, 1, 3, 5},
96 { "atan", Atan, 1, 4, 5},
97 { "exp", Exp, 1, 3, 5},
98 { "log", Log, 1, 3, 5},
99 { "sto", Store, 2, 3, 9},
100 { "rcl", Recall, 1, 3, 5},
101 { "inc", Inc, 1, 3, 5},
102 { "dec", Dec, 1, 3, 5},
103 { "disp", Disp, 0, 4, 9},
104 { "quit", Quit, 0, 4, 9},
105 { "help", Help, 0, 4, 9},
106 { "!", Not, 1, 1, 6},
107 { "cond", Cond, 3, 4, 5}
108 };
109
110 #define NB_CONSTANTS 3
111 keyword_t constants[NB_CONSTANTS] = {
112 { "ans", Ans, 0, 3, 5},
113 { "e", E, 0, 1, 5},
114 { "pi", Pi, 0, 2, 5}
115 };
116
117 /* subparser function */
118
119 element_t *subparser (element_t **proot, char **pstr, func_t func, int nbops, int prio)
120 {
121 element_t *new = newelement (func, nbops, prio);
122 if (new == NULL) {
123 return ERROR_OP;
124 }
125 new->ops[0] = *proot;
126 new->ops[1] = parser (*pstr, pstr, new->prio);
127 if ((new->ops[1] == NULL) || ((new->ops[1] != ERROR_OP) && (new->ops[1]->prio == 9))) {
128 delelement (new->ops[1]);
129 new->ops[1] = ERROR_OP;
130 }
131 if (new->ops[1] == ERROR_OP) {
132 delelement (new);
133 *proot = NULL;
134 return ERROR_OP;
135 }
136 *proot = newelement (Val, 1, 5);
137 if (*proot == NULL) {
138 delelement (new);
139 return ERROR_OP;
140 }
141 (*proot)->ops[0] = new;
142
143 return *proot;
144 }
145
146 /* parser function */
147
148 element_t *parser (char *str, char **next, int prio)
149 {
150 element_t *root = NULL;
151 int i;
152
153 VERBOSE (DEBUG, fprintf (stdout, "Starting parsing\n"));
154
155 /* main loop */
156 while (*str != '\0') {
157 int found = 0;
158 element_t *new = NULL;
159 VERBOSE (INFO, fprintf (stdout, "Processing: %s\n", str));
160
161 /* skip spaces and tabs */
162
163 if ((*str == ' ') || (*str == '\t')) {
164 str++;
165 continue;
166 }
167
168 /* check for open bracket */
169
170 if (*str == '(') {
171 VERBOSE (DEBUG, fprintf (stdout, "start processing bracket\n"));
172 if (root) {
173 do {
174 found = 0;
175 new = parser (str + 1, &str, 0);
176 if ((new == NULL) || ((new != ERROR_OP) && (new->prio == 9))) {
177 delelement (new);
178 new = ERROR_OP;
179 }
180 if ((new == NULL) || (new == ERROR_OP)) {
181 delelement (root);
182 return ERROR_OP;
183 }
184 for (i = 0; i < root->nbops; i++) {
185 if (root->ops[i] == NULL) {
186 root->ops[i] = new;
187 found = 1;
188 break;
189 }
190 }
191 if (!found) {
192 delelement (new);
193 delelement (root);
194 return ERROR_OP;
195 }
196 } while (*str == ',');
197 } else {
198 root = newelement (Val, 1, 5);
199 if (root == NULL) {
200 return ERROR_OP;
201 }
202 new = parser (str + 1, &str, 0);
203 if ((new == NULL) || ((new != ERROR_OP) && (new->prio == 9))) {
204 delelement (new);
205 new = ERROR_OP;
206 }
207 if ((new == NULL) || (new == ERROR_OP) || (*str == ',')) {
208 delelement (new);
209 delelement (root);
210 return ERROR_OP;
211 }
212 root->ops[0] = new;
213 }
214 if (*str != ')') {
215 delelement (root);
216 return ERROR_OP;
217 }
218 str++;
219 VERBOSE (DEBUG, fprintf (stdout, "stop processing bracket\n"));
220 continue;
221 }
222
223 /* check for closing bracket or koma */
224
225 if ((*str == ')') || (*str == ',')) {
226 if (next != NULL) {
227 *next = str;
228 }
229 return root;
230 }
231
232 /* look for operators */
233
234 for (i = 0; i < NB_OPERATORS; i++) {
235 keyword_t *operator = operators + i;
236 if (codecmp (operator->keyword, str) == 0) {
237 VERBOSE (DEBUG, fprintf (stdout, "start processing operator\n"));
238 if (root) {
239 if ((prio) && (prio > operator->prio)) {
240 VERBOSE (DEBUG, fprintf (stdout, "stop because operator priority\n"));
241 *next = str;
242 return root;
243 }
244 str += operator->offset;
245 VERBOSE (INFO, fprintf (stdout, "Oper: %d\n", operator->func));
246 if (subparser (&root, &str, operator->func, operator->nbops, operator->prio) == ERROR_OP) {
247 delelement (root);
248 return ERROR_OP;
249 }
250 } else if (*str == '-') {
251 new = newelement (Sig, 1, 9);
252 if (new == NULL) {
253 return ERROR_OP;
254 }
255 root = new;
256 } else {
257 return ERROR_OP;
258 }
259 found = 1;
260 VERBOSE (DEBUG, fprintf (stdout, "stop processing operator\n"));
261 break;
262 }
263 }
264 if (found) {
265 continue;
266 }
267
268 /* look for functions */
269
270 for (i = 0; i < NB_FUNCTIONS; i++) {
271 keyword_t *function = functions + i;
272 if (codecmp (function->keyword, str) == 0) {
273 VERBOSE (DEBUG, fprintf (stdout, "start processing function\n"));
274 if (root == NULL) {
275 VERBOSE (INFO, fprintf (stdout, "Func: %d\n", function->func));
276 new = newelement (function->func, function->nbops, function->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 += function->offset;
286 found = 1;
287 VERBOSE (DEBUG, fprintf (stdout, "stop processing function\n"));
288 break;
289 }
290 }
291 if (found) {
292 continue;
293 }
294
295 /* look for constant */
296
297 for (i = 0; i < NB_CONSTANTS; i++) {
298 keyword_t *constant = constants + i;
299 if (codecmp (constant->keyword, str) == 0) {
300 VERBOSE (DEBUG, fprintf (stdout, "start processing constant\n"));
301 if (root == NULL) {
302 VERBOSE (INFO, fprintf (stdout, "Const: %d\n", constant->func));
303 new = newelement (constant->func, constant->nbops, constant->prio);
304 if (new == NULL) {
305 return ERROR_OP;
306 }
307 root = new;
308 } else {
309 delelement (root);
310 return ERROR_OP;
311 }
312 str += constant->offset;
313 found = 1;
314 VERBOSE (DEBUG, fprintf (stdout, "stop processing constant\n"));
315 break;
316 }
317 }
318 if (found) {
319 continue;
320 }
321
322 /* look for number */
323
324 if (((*str >= '0') && (*str <= '9')) ||
325 (*str == '.') || (*str == '+') || (*str == '-')) {
326 VERBOSE (DEBUG, fprintf (stdout, "start processing value\n"));
327 char *pt;
328 double value = strtod (str, &pt);
329 VERBOSE (INFO, fprintf (stdout, "Value: %f\n", value));
330 if (str != pt) {
331 if ((root == NULL) || (root->prio == 6)) {
332 new = newelement (Val, 1, 5);
333 if (new == NULL) {
334 return ERROR_OP;
335 }
336 new->value = value;
337 if (root == NULL) {
338 root = new;
339 } else {
340 for (i = 0; i < root->nbops; i++) {
341 if (root->ops[i] == NULL) {
342 root->ops[i] = new;
343 found = 1;
344 break;
345 }
346 }
347 if (!found) {
348 delelement (new);
349 delelement (root);
350 return ERROR_OP;
351 }
352 }
353 str = pt;
354 } else if ((*str == '+') || (*str == '-')) {
355 if ((prio) && (prio > 1)) {
356 VERBOSE (DEBUG, fprintf (stdout, "stop because operator priority\n"));
357 *next = str;
358 return root;
359 }
360 if (subparser (&root, &str, Add, 2, 1) == ERROR_OP) {
361 delelement (root);
362 return ERROR_OP;
363 }
364 } else {
365 delelement (root);
366 return ERROR_OP;
367 }
368 found = 1;
369 }
370 VERBOSE (DEBUG, fprintf (stdout, "stop processing value\n"));
371 }
372
373 /* error */
374
375 if (!found) {
376 delelement (root);
377 return ERROR_OP;
378 }
379
380 }
381
382 if (next != NULL) {
383 *next = str;
384 }
385
386 return root;
387 }
388
389 /* print element tree */
390
391 void print_element (element_t *root, int level)
392 {
393 char *func = NULL;
394 int i;
395
396 if ((root == NULL) || (root == ERROR_OP)) {
397 return;
398 }
399
400 for (i = 0; i < level; i++) {
401 fprintf (stdout, " ");
402 }
403
404 switch (root->func) {
405 case Val: func = "Value"; break;
406 case Sig: func = "Sign"; break;
407 case Add: func = "Addition"; break;
408 case Sub: func = "Subtraction"; break;
409 case Mul: func = "Multiplication"; break;
410 case Div: func = "Division"; break;
411 case Mod: func = "Modulo"; break;
412 case Pow: func = "Power"; break;
413 case Sqr: func = "Square Root"; break;
414 case Cos: func = "Cosine"; break;
415 case Sin: func = "Sine"; break;
416 case Atan: func = "Arc Tangent"; break;
417 case Log: func = "Logarithm"; break;
418 case Exp: func = "Exponantial"; break;
419 case Store: func = "Store"; break;
420 case Recall: func = "Recall"; break;
421 case Inc: func = "Increase"; break;
422 case Dec: func = "Decrease"; break;
423 case Disp: func = "Display"; break;
424 case Quit: func = "Quit"; break;
425 case Help: func = "Help"; break;
426 case Ans: func = "Ans"; break;
427 case Pi: func = "Pi"; break;
428 case E: func = "E"; break;
429 case Equal: func = "Equal"; break;
430 case Diff: func = "Different"; break;
431 case Ge: func = "Greater or equal"; break;
432 case Le: func = "Lesser or equal"; break;
433 case Gt: func = "Greater"; break;
434 case Lt: func = "Lesser"; break;
435 case And: func = "And"; break;
436 case Or: func = "Or"; break;
437 case Not: func = "Not"; break;
438 case Cond: func = "Condition"; break;
439 }
440
441 fprintf (stdout, "Function: %s\n", func);
442
443 if ((root->func == Val) && (root->ops[0] == NULL)) {
444 for (i = 0; i < level; i++) {
445 fprintf (stdout, " ");
446 }
447 fprintf (stdout, "value: %f\n", root->value);
448 } else {
449 for (i = 0; i < root->nbops; i++) {
450 print_element (root->ops[i], level + 1);
451 }
452 }
453 }
454
455 /* storage functions */
456
457 double store (int index, double value)
458 {
459 if ((index > 0) && (index <= STORAGE_SIZE)) {
460 storage[index - 1] = value;
461 } else {
462 VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [1, %d]\n", index, STORAGE_SIZE));
463 }
464 return value;
465 }
466
467 double recall (int index)
468 {
469 if ((index > 0) && (index <= STORAGE_SIZE)) {
470 return storage[index - 1];
471 } else {
472 VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [1, %d]\n", index, STORAGE_SIZE));
473 }
474 return 0;
475 }
476
477 double increase (int index)
478 {
479 if ((index > 0) && (index <= STORAGE_SIZE)) {
480 return storage[index - 1]++;
481 } else {
482 VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [1, %d]\n", index, STORAGE_SIZE));
483 }
484 return 0;
485 }
486
487 double decrease (int index)
488 {
489 if ((index > 0) && (index <= STORAGE_SIZE)) {
490 return storage[index - 1]--;
491 } else {
492 VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [1, %d]\n", index, STORAGE_SIZE));
493 }
494 return 0;
495 }
496
497 void display (void)
498 {
499 int i;
500 fprintf (stdout, "storage:");
501 for (i = 0; i < STORAGE_SIZE; i++) {
502 fprintf (stdout, " %g", storage[i]);
503 }
504 fprintf (stdout, "\n");
505 }
506
507 /* quit function */
508
509 void quit (void)
510 {
511 fprintf (stdout, "bye\n");
512 exit (0);
513 }
514
515 /* help message */
516
517 void help (void)
518 {
519 fprintf (stdout, "calc is a simple calculator\n\n");
520 fprintf (stdout, "supported operators:");
521 fprintf (stdout, " + - * / %% ^\n");
522 fprintf (stdout, "camparison operators:");
523 fprintf (stdout, " == != >= <= > <\n");
524 fprintf (stdout, "logical operators:");
525 fprintf (stdout, " & | !\n");
526 fprintf (stdout, "supported functions:");
527 fprintf (stdout, " pow sqrt cos sin atan log exp\n");
528 fprintf (stdout, "storage functions:");
529 fprintf (stdout, " sto rcl inc dec\n");
530 fprintf (stdout, "conditional functions:");
531 fprintf (stdout, " cond\n");
532 fprintf (stdout, "miscellaneous functions:");
533 fprintf (stdout, " quit help\n");
534 fprintf (stdout, "supported constants:");
535 fprintf (stdout, " e pi\n");
536 }
537
538 /* evaluate element tree */
539
540 #define MASK_SUB 0x1
541 #define MASK_DIV 0x2
542
543 double evaluate_element (element_t *root, char mask)
544 {
545 double op0 = 0, op1 = 0;
546 char nextmask = mask;
547
548 if ((root == NULL) || (root == ERROR_OP)) {
549 VERBOSE (WARNING, fprintf (stdout, "error while evaluating\n"));
550 return 0;
551 }
552
553 /* mask to manage sub operator sub and div */
554 switch (root->func) {
555 case Add:
556 nextmask &= ~MASK_SUB;
557 nextmask &= ~MASK_DIV;
558 break;
559 case Sub:
560 nextmask |= MASK_SUB;
561 nextmask &= ~MASK_DIV;
562 break;
563 case Mul:
564 nextmask &= ~MASK_DIV;
565 break;
566 case Div:
567 nextmask |= MASK_DIV;
568 break;
569 default:
570 nextmask = mask;
571 }
572
573 switch (root->func) {
574 case Val:
575 case Sig:
576 op0 = (root->ops[0]) ? evaluate_element (root->ops[0], nextmask) : root->value;
577 break;
578 case Add:
579 case Sub:
580 case Mul:
581 case Div:
582 case Mod:
583 case Pow:
584 case Store:
585 case Equal:
586 case Diff:
587 case Ge:
588 case Le:
589 case Gt:
590 case Lt:
591 case And:
592 case Or:
593 if (root->ops[1]) {
594 op1 = evaluate_element (root->ops[1], nextmask);
595 } else if (root->func != Store) {
596 VERBOSE (WARNING, fprintf (stdout, "error while evaluating (op[1])\n"));
597 return 0;
598 }
599 /* fallthrough */
600 case Sqr:
601 case Cos:
602 case Sin:
603 case Atan:
604 case Log:
605 case Exp:
606 case Recall:
607 case Inc:
608 case Dec:
609 case Not:
610 case Cond:
611 if (root->ops[0]) {
612 op0 = evaluate_element (root->ops[0], 0);
613 } else {
614 VERBOSE (WARNING, fprintf (stdout, "error while evaluating (op[0])\n"));
615 return 0;
616 }
617 break;
618 case Disp:
619 case Quit:
620 case Help:
621 case Ans:
622 case Pi:
623 case E:
624 break;
625 }
626
627 switch (root->func) {
628 case Val: return op0;
629 case Sig: return -op0;
630 case Add: return ((mask & MASK_SUB) == 0) ? op0 + op1 : op0 - op1;
631 case Sub: return ((mask & MASK_SUB) == 0) ? op0 - op1 : op0 + op1;
632 case Mul: return ((mask & MASK_DIV) == 0) ? op0 * op1 : op0 / op1;
633 case Div: return ((mask & MASK_DIV) == 0) ? op0 / op1 : op0 * op1;
634 case Mod: return fmod (op0, op1);
635 case Pow: return pow (op0, op1);
636 case Sqr: return sqrt (op0);
637 case Cos: return cos (op0);
638 case Sin: return sin (op0);
639 case Atan: return atan (op0);
640 case Log: return log (op0);
641 case Exp: return exp (op0);
642 case Store: return store ((int)op0, (op1) ? op1 : answer);
643 case Recall: return recall ((int)op0);
644 case Inc: return increase ((int)op0);
645 case Dec: return decrease ((int)op0);
646 case Disp: display (); break;
647 case Quit: quit (); break;
648 case Help: help (); break;
649 case Ans: return answer;
650 case Pi: return M_PI;
651 case E: return M_E;
652 case Equal: return op0 == op1;
653 case Diff: return op0 != op1;
654 case Ge: return op0 >= op1;
655 case Le: return op0 <= op1;
656 case Gt: return op0 > op1;
657 case Lt: return op0 < op1;
658 case And: return (op0 != 0) && (op1 != 0);
659 case Or: return (op0 != 0) || (op1 != 0);
660 case Not: return (op0 == 0);
661 case Cond:
662 if ((op0) && (root->ops[1])) {
663 return evaluate_element (root->ops[1], 0);
664 } else if ((!op0) && (root->ops[2])) {
665 return evaluate_element (root->ops[2], 0);
666 } else {
667 return 0;
668 }
669 }
670
671 return 0;
672 }
673
674 /* vim: set ts=4 sw=4 et: */