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