enhance prompt and format management
[calc.git] / parser.c
CommitLineData
bc97a989 1#include <malloc.h>
f2927108 2#include <math.h>
87621fe1 3#include <stdio.h>
bc97a989 4#include <stdlib.h>
b9c1c40d 5#include <string.h>
bc97a989
LM
6
7#include "debug.h"
bc97a989
LM
8
9#include "parser.h"
10
5075f6ea
LM
11/* global variables */
12
13double answer = 0;
14
6ba1dd0f
LM
15#define STORAGE_SIZE 10
16double storage[STORAGE_SIZE] = {0};
17
2a5ec9d1 18char *format = NULL;
715580ff 19
bc97a989
LM
20/* compare codes */
21
22int codecmp (char *ref, char *str)
23{
24 int sig;
25
26 while (*ref != '\0') {
0b9cc9b0
LM
27 if (*ref == '\t') {
28 sig = (*str == '.') ? -1 : ((*str >= '0') && (*str <= '9'));
29 } else {
30 sig = *str - *ref;
31 }
bc97a989
LM
32 if (sig != 0) {
33 return (sig > 0) ? 1 : -1;
34 }
0b9cc9b0
LM
35 str++;
36 ref++;
bc97a989
LM
37 }
38
39 return 0;
40}
41
42/* allocate new element */
43
11cda8d7 44element_t *newelement (func_t function, int nbops, int prio)
bc97a989
LM
45{
46 element_t *new = (element_t *) calloc (1, sizeof (element_t));
47 if (new == NULL) {
04d68907 48 VERBOSE (ERROR, fprintf (stderr, "can't allocate memory\n"));
d32ea0b0 49 exit (1);
bc97a989 50 }
62d56da6
LM
51 if (nbops) {
52 new->ops = (element_t **) calloc (nbops, sizeof (element_t *));
53 if (new->ops == NULL) {
62d56da6 54 VERBOSE (ERROR, fprintf (stderr, "can't allocate memory\n"));
d32ea0b0 55 exit (1);
62d56da6 56 }
0c95a3d3 57 }
bc97a989
LM
58 new->func = function;
59 new->nbops = nbops;
11cda8d7 60 new->prio = prio;
bc97a989
LM
61
62 return new;
63}
64
031d7bba
LM
65/* desallocate element */
66
67void delelement (element_t *root)
68{
031d7bba 69 if ((root != NULL) && (root != ERROR_OP)) {
0c95a3d3 70 int i;
031d7bba
LM
71 for (i = 0; i < root->nbops; i++) {
72 if ((root->ops[i] != NULL) && (root->ops[i] != ERROR_OP)) {
73 delelement (root->ops[i]);
74 }
75 }
0c95a3d3
LM
76 if (root->nbops) {
77 free (root->ops);
78 }
031d7bba
LM
79 free (root);
80 }
81}
82
2a688642
LM
83/* duplicate element */
84
85element_t *dupelement (element_t *root)
86{
87 element_t *tmp = NULL;
88 int i;
89
90 if ((root == NULL) || (root == ERROR_OP)) {
91 return root;
92 }
93 tmp = newelement (root->func, root->nbops, root->prio);
2a688642
LM
94 tmp->value = root->value;
95 for (i = 0; i < root->nbops; i++) {
96 tmp->ops[i] = dupelement (root->ops[i]);
2a688642
LM
97 }
98 return tmp;
99}
100
bc97a989
LM
101/* functions */
102
ca3e2a2f 103#define NB_OPERATORS 14
bc97a989 104keyword_t operators[NB_OPERATORS] = {
11cda8d7
LM
105 { "+\t", Add, 2, 1, 1},
106 { "-\t", Sub, 2, 1, 1},
107 { "*", Mul, 2, 1, 2},
108 { "/", Div, 2, 1, 2},
c47a9298 109 { "%", Mod, 2, 1, 3},
7fe742c9 110 { "^", Pow, 2, 1, 4},
ca3e2a2f
LM
111 { "==", Equal, 2, 2, -1},
112 { "!=", Diff, 2, 2, -1},
113 { ">=", Ge, 2, 2, -1},
114 { "<=", Le, 2, 2, -1},
115 { ">", Gt, 2, 1, -1},
116 { "<", Lt, 2, 1, -1},
117 { "&", And, 2, 1, -2},
118 { "|", Or, 2, 1, -2}
bc97a989
LM
119};
120
715580ff 121#define NB_FUNCTIONS 24
bc97a989 122keyword_t functions[NB_FUNCTIONS] = {
c47a9298
LM
123 { "sqrt", Sqr, 1, 4, 5},
124 { "pow", Pow, 2, 3, 5},
125 { "cos", Cos, 1, 3, 5},
126 { "sin", Sin, 1, 3, 5},
9e52bbc5
LM
127 { "tan", Tan, 1, 3, 5},
128 { "acos", Acos, 1, 4, 5},
129 { "asin", Asin, 1, 4, 5},
471da7c9 130 { "atan", Atan, 1, 4, 5},
89cf0955 131 { "log", Log, 1, 3, 5},
9e52bbc5
LM
132 { "exp", Exp, 1, 3, 5},
133 { "abs", Abs, 1, 3, 5},
134 { "floor", Floor, 1, 5, 5},
135 { "ceil", Ceil, 1, 4, 5},
2a688642 136 { "sto", Store, 2, 3, 5},
6ba1dd0f 137 { "rcl", Recall, 1, 3, 5},
a8cf32ba
LM
138 { "inc", Inc, 1, 3, 5},
139 { "dec", Dec, 1, 3, 5},
ca3e2a2f
LM
140 { "disp", Disp, 0, 4, 9},
141 { "quit", Quit, 0, 4, 9},
142 { "help", Help, 0, 4, 9},
94b4e517 143 { "!", Not, 1, 1, 6},
2a688642 144 { "cond", Cond, 3, 4, 5},
715580ff
LM
145 { "while", While, 2, 5, 5},
146 { "print", Print, 1, 5, 5}
471da7c9
LM
147};
148
5075f6ea 149#define NB_CONSTANTS 3
471da7c9 150keyword_t constants[NB_CONSTANTS] = {
5075f6ea
LM
151 { "ans", Ans, 0, 3, 5},
152 { "e", E, 0, 1, 5},
153 { "pi", Pi, 0, 2, 5}
bc97a989
LM
154};
155
db660e60
LM
156#define NB_SYMBOLS 4
157char *symbols[NB_SYMBOLS] = {
158 "(", ")", "{", "}"
159};
160
d2ff8478
LM
161/* subparser function */
162
163element_t *subparser (element_t **proot, char **pstr, func_t func, int nbops, int prio)
164{
165 element_t *new = newelement (func, nbops, prio);
d2ff8478
LM
166 new->ops[0] = *proot;
167 new->ops[1] = parser (*pstr, pstr, new->prio);
686c4bc2 168 if ((new->ops[1] == NULL) || ((new->ops[1] != ERROR_OP) && (new->ops[1]->prio == 9))) {
67b13e3d
LM
169 delelement (new->ops[1]);
170 new->ops[1] = ERROR_OP;
171 }
d2ff8478 172 if (new->ops[1] == ERROR_OP) {
031d7bba
LM
173 delelement (new);
174 *proot = NULL;
d2ff8478
LM
175 return ERROR_OP;
176 }
3b4b0bbe 177 *proot = newelement (Val, 1, 5);
d2ff8478
LM
178 (*proot)->ops[0] = new;
179
180 return *proot;
181}
182
bc97a989
LM
183/* parser function */
184
ef37d966 185element_t *parser (char *str, char **next, int prio)
0b489a77 186{
bc97a989 187 element_t *root = NULL;
85b4a72c 188 int i;
bc97a989 189
04d68907 190 VERBOSE (DEBUG, fprintf (stdout, "Starting parsing\n"));
49223129 191
bc97a989
LM
192 /* main loop */
193 while (*str != '\0') {
194 int found = 0;
195 element_t *new = NULL;
04d68907 196 VERBOSE (INFO, fprintf (stdout, "Processing: %s\n", str));
bc97a989
LM
197
198 /* skip spaces and tabs */
199
200 if ((*str == ' ') || (*str == '\t')) {
201 str++;
202 continue;
203 }
204
124da7fd
LM
205 /* check for open brace */
206
207 if (*str == '{') {
208 VERBOSE (DEBUG, fprintf (stdout, "start processing brace\n"));
62d56da6 209 if (root != NULL) {
124da7fd
LM
210 delelement (root);
211 return ERROR_OP;
212 }
62d56da6
LM
213 element_t **prog = NULL;
214 new = newelement (Prog, 0, 5);
62d56da6
LM
215 root = new;
216 prog = &root;
124da7fd
LM
217
218 do {
124da7fd
LM
219 new = parser (str + 1, &str, 0);
220 if ((new == NULL) || ((new != ERROR_OP) && (new->prio == 9))) {
221 delelement (new);
222 new = ERROR_OP;
223 }
7929d368 224 if (new == ERROR_OP) {
124da7fd 225 delelement (root);
62d56da6 226 return ERROR_OP;
124da7fd 227 }
62d56da6
LM
228 element_t *newprog = newelement (Prog, (*prog)->nbops + 1, 5);
229 for (i = 0; i < (*prog)->nbops; i++) {
230 newprog->ops[i] = (*prog)->ops[i];
231 (*prog)->ops[i] = NULL;
124da7fd 232 }
62d56da6
LM
233 newprog->ops[(*prog)->nbops] = new;
234 delelement (*prog);
235 (*prog) = newprog;
124da7fd
LM
236 } while (*str == ',');
237
238 if (*str != '}') {
239 delelement (root);
240 return ERROR_OP;
241 }
242 str++;
243 VERBOSE (DEBUG, fprintf (stdout, "stop processing brace\n"));
244 continue;
245 }
246
85b4a72c 247 /* check for open bracket */
0b489a77 248
0b489a77 249 if (*str == '(') {
04d68907 250 VERBOSE (DEBUG, fprintf (stdout, "start processing bracket\n"));
0b489a77 251 if (root) {
85b4a72c
LM
252 do {
253 found = 0;
ef37d966 254 new = parser (str + 1, &str, 0);
686c4bc2 255 if ((new == NULL) || ((new != ERROR_OP) && (new->prio == 9))) {
67b13e3d
LM
256 delelement (new);
257 new = ERROR_OP;
258 }
686c4bc2 259 if ((new == NULL) || (new == ERROR_OP)) {
031d7bba 260 delelement (root);
85b4a72c
LM
261 return ERROR_OP;
262 }
263 for (i = 0; i < root->nbops; i++) {
264 if (root->ops[i] == NULL) {
0b489a77
LM
265 root->ops[i] = new;
266 found = 1;
267 break;
268 }
269 }
85b4a72c 270 if (!found) {
031d7bba
LM
271 delelement (new);
272 delelement (root);
85b4a72c
LM
273 return ERROR_OP;
274 }
275 } while (*str == ',');
276 } else {
3b4b0bbe 277 root = newelement (Val, 1, 5);
ef37d966 278 new = parser (str + 1, &str, 0);
686c4bc2 279 if ((new == NULL) || ((new != ERROR_OP) && (new->prio == 9))) {
67b13e3d
LM
280 delelement (new);
281 new = ERROR_OP;
282 }
686c4bc2 283 if ((new == NULL) || (new == ERROR_OP) || (*str == ',')) {
031d7bba
LM
284 delelement (new);
285 delelement (root);
efdfb543
LM
286 return ERROR_OP;
287 }
85b4a72c 288 root->ops[0] = new;
0b489a77 289 }
3c0db5bc
LM
290 if (*str != ')') {
291 delelement (root);
292 return ERROR_OP;
293 }
85b4a72c 294 str++;
04d68907 295 VERBOSE (DEBUG, fprintf (stdout, "stop processing bracket\n"));
efdfb543 296 continue;
49223129 297 }
85b4a72c 298
124da7fd 299 /* check for closing bracket, closing brace or koma */
85b4a72c 300
124da7fd 301 if ((*str == ')') || (*str == '}') || (*str == ',')) {
45a631a8
LM
302 if (prio == -9) {
303 delelement (root);
304 return ERROR_OP;
305 }
49223129 306 if (next != NULL) {
85b4a72c 307 *next = str;
49223129
LM
308 }
309 return root;
0b489a77
LM
310 }
311
bc97a989
LM
312 /* look for operators */
313
314 for (i = 0; i < NB_OPERATORS; i++) {
315 keyword_t *operator = operators + i;
316 if (codecmp (operator->keyword, str) == 0) {
04d68907 317 VERBOSE (DEBUG, fprintf (stdout, "start processing operator\n"));
11cda8d7 318 if (root) {
ef37d966 319 if ((prio) && (prio > operator->prio)) {
04d68907 320 VERBOSE (DEBUG, fprintf (stdout, "stop because operator priority\n"));
ef37d966
LM
321 *next = str;
322 return root;
323 }
324 str += operator->offset;
04d68907 325 VERBOSE (INFO, fprintf (stdout, "Oper: %d\n", operator->func));
d2ff8478 326 if (subparser (&root, &str, operator->func, operator->nbops, operator->prio) == ERROR_OP) {
031d7bba 327 delelement (root);
ef37d966 328 return ERROR_OP;
11cda8d7 329 }
3b4b0bbe 330 } else if (*str == '-') {
d32ea0b0 331 root = newelement (Sig, 1, 9);
49223129 332 } else {
0b489a77 333 return ERROR_OP;
bc97a989 334 }
bc97a989 335 found = 1;
04d68907 336 VERBOSE (DEBUG, fprintf (stdout, "stop processing operator\n"));
bc97a989
LM
337 break;
338 }
339 }
340 if (found) {
bc97a989
LM
341 continue;
342 }
49223129 343
bc97a989
LM
344 /* look for functions */
345
346 for (i = 0; i < NB_FUNCTIONS; i++) {
347 keyword_t *function = functions + i;
348 if (codecmp (function->keyword, str) == 0) {
04d68907 349 VERBOSE (DEBUG, fprintf (stdout, "start processing function\n"));
bc97a989 350 if (root == NULL) {
04d68907 351 VERBOSE (INFO, fprintf (stdout, "Func: %d\n", function->func));
d32ea0b0 352 root = newelement (function->func, function->nbops, function->prio);
031d7bba
LM
353 } else {
354 delelement (root);
0b489a77 355 return ERROR_OP;
bc97a989
LM
356 }
357 str += function->offset;
358 found = 1;
04d68907 359 VERBOSE (DEBUG, fprintf (stdout, "stop processing function\n"));
bc97a989
LM
360 break;
361 }
362 }
363 if (found) {
bc97a989
LM
364 continue;
365 }
366
471da7c9
LM
367 /* look for constant */
368
369 for (i = 0; i < NB_CONSTANTS; i++) {
370 keyword_t *constant = constants + i;
371 if (codecmp (constant->keyword, str) == 0) {
372 VERBOSE (DEBUG, fprintf (stdout, "start processing constant\n"));
373 if (root == NULL) {
5075f6ea 374 VERBOSE (INFO, fprintf (stdout, "Const: %d\n", constant->func));
d32ea0b0 375 root = newelement (constant->func, constant->nbops, constant->prio);
471da7c9
LM
376 } else {
377 delelement (root);
378 return ERROR_OP;
379 }
380 str += constant->offset;
381 found = 1;
382 VERBOSE (DEBUG, fprintf (stdout, "stop processing constant\n"));
383 break;
384 }
385 }
386 if (found) {
387 continue;
388 }
389
bc97a989
LM
390 /* look for number */
391
0b9cc9b0
LM
392 if (((*str >= '0') && (*str <= '9')) ||
393 (*str == '.') || (*str == '+') || (*str == '-')) {
04d68907 394 VERBOSE (DEBUG, fprintf (stdout, "start processing value\n"));
bc97a989 395 char *pt;
fd88e359 396 double value = strtod (str, &pt);
04d68907 397 VERBOSE (INFO, fprintf (stdout, "Value: %f\n", value));
bc97a989 398 if (str != pt) {
ce6627f2 399 if ((root == NULL) || (root->prio == 6)) {
3b4b0bbe 400 new = newelement (Val, 1, 5);
c47a9298 401 new->value = value;
ce6627f2
LM
402 if (root == NULL) {
403 root = new;
404 } else {
405 for (i = 0; i < root->nbops; i++) {
406 if (root->ops[i] == NULL) {
407 root->ops[i] = new;
408 found = 1;
409 break;
410 }
411 }
412 if (!found) {
413 delelement (new);
414 delelement (root);
415 return ERROR_OP;
416 }
417 }
c47a9298 418 str = pt;
32741902
LM
419 } else if ((*str == '+') || (*str == '-')) {
420 if ((prio) && (prio > 1)) {
421 VERBOSE (DEBUG, fprintf (stdout, "stop because operator priority\n"));
422 *next = str;
423 return root;
424 }
425 if (subparser (&root, &str, Add, 2, 1) == ERROR_OP) {
031d7bba 426 delelement (root);
0b489a77 427 return ERROR_OP;
bc97a989 428 }
0b9cc9b0 429 } else {
031d7bba 430 delelement (root);
0b9cc9b0 431 return ERROR_OP;
bc97a989 432 }
bc97a989
LM
433 found = 1;
434 }
04d68907 435 VERBOSE (DEBUG, fprintf (stdout, "stop processing value\n"));
bc97a989
LM
436 }
437
438 /* error */
439
440 if (!found) {
031d7bba 441 delelement (root);
0b489a77 442 return ERROR_OP;
bc97a989
LM
443 }
444
445 }
446
49223129
LM
447 if (next != NULL) {
448 *next = str;
449 }
031d7bba 450
bc97a989
LM
451 return root;
452}
453
454/* print element tree */
455
456void print_element (element_t *root, int level)
457{
458 char *func = NULL;
459 int i;
460
49223129 461 if ((root == NULL) || (root == ERROR_OP)) {
bc97a989 462 return;
49223129
LM
463 }
464
bc97a989 465 for (i = 0; i < level; i++) {
04d68907 466 fprintf (stdout, " ");
bc97a989
LM
467 }
468
469 switch (root->func) {
470 case Val: func = "Value"; break;
89cf0955 471 case Sig: func = "Sign"; break;
bc97a989
LM
472 case Add: func = "Addition"; break;
473 case Sub: func = "Subtraction"; break;
474 case Mul: func = "Multiplication"; break;
475 case Div: func = "Division"; break;
c47a9298 476 case Mod: func = "Modulo"; break;
bc97a989
LM
477 case Pow: func = "Power"; break;
478 case Sqr: func = "Square Root"; break;
479 case Cos: func = "Cosine"; break;
480 case Sin: func = "Sine"; break;
9e52bbc5
LM
481 case Tan: func = "Tangent"; break;
482 case Acos: func = "Arc Cosine"; break;
483 case Asin: func = "Arc Sine"; break;
471da7c9 484 case Atan: func = "Arc Tangent"; break;
bc97a989
LM
485 case Log: func = "Logarithm"; break;
486 case Exp: func = "Exponantial"; break;
9e52bbc5
LM
487 case Abs: func = "Absolute value"; break;
488 case Ceil: func = "Ceil value"; break;
489 case Floor: func = "Floor value"; break;
6ba1dd0f
LM
490 case Store: func = "Store"; break;
491 case Recall: func = "Recall"; break;
a8cf32ba
LM
492 case Inc: func = "Increase"; break;
493 case Dec: func = "Decrease"; break;
6ba1dd0f 494 case Disp: func = "Display"; break;
471da7c9
LM
495 case Quit: func = "Quit"; break;
496 case Help: func = "Help"; break;
5075f6ea 497 case Ans: func = "Ans"; break;
471da7c9
LM
498 case Pi: func = "Pi"; break;
499 case E: func = "E"; break;
7fe742c9
LM
500 case Equal: func = "Equal"; break;
501 case Diff: func = "Different"; break;
502 case Ge: func = "Greater or equal"; break;
503 case Le: func = "Lesser or equal"; break;
504 case Gt: func = "Greater"; break;
505 case Lt: func = "Lesser"; break;
ca3e2a2f
LM
506 case And: func = "And"; break;
507 case Or: func = "Or"; break;
508 case Not: func = "Not"; break;
94b4e517 509 case Cond: func = "Condition"; break;
2a688642 510 case While: func = "While"; break;
124da7fd 511 case Prog: func = "Program"; break;
715580ff 512 case Print: func = "Print"; break;
bc97a989
LM
513 }
514
04d68907 515 fprintf (stdout, "Function: %s\n", func);
bc97a989 516
85b4a72c 517 if ((root->func == Val) && (root->ops[0] == NULL)) {
bc97a989 518 for (i = 0; i < level; i++) {
04d68907 519 fprintf (stdout, " ");
bc97a989 520 }
04d68907 521 fprintf (stdout, "value: %f\n", root->value);
bc97a989
LM
522 } else {
523 for (i = 0; i < root->nbops; i++) {
524 print_element (root->ops[i], level + 1);
525 }
526 }
527}
528
6ba1dd0f
LM
529/* storage functions */
530
3639df66 531double store (int index, double value)
6ba1dd0f
LM
532{
533 if ((index > 0) && (index <= STORAGE_SIZE)) {
3639df66 534 storage[index - 1] = value;
6ba1dd0f
LM
535 } else {
536 VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [1, %d]\n", index, STORAGE_SIZE));
537 }
3639df66 538 return value;
6ba1dd0f
LM
539}
540
541double recall (int index)
542{
543 if ((index > 0) && (index <= STORAGE_SIZE)) {
544 return storage[index - 1];
545 } else {
546 VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [1, %d]\n", index, STORAGE_SIZE));
547 }
548 return 0;
549}
550
a8cf32ba
LM
551double increase (int index)
552{
553 if ((index > 0) && (index <= STORAGE_SIZE)) {
554 return storage[index - 1]++;
555 } else {
556 VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [1, %d]\n", index, STORAGE_SIZE));
557 }
558 return 0;
559}
560
561double decrease (int index)
562{
563 if ((index > 0) && (index <= STORAGE_SIZE)) {
564 return storage[index - 1]--;
565 } else {
566 VERBOSE (WARNING, fprintf (stdout, "invalid index (%d) [1, %d]\n", index, STORAGE_SIZE));
567 }
568 return 0;
569}
570
6ba1dd0f
LM
571void display (void)
572{
573 int i;
574 fprintf (stdout, "storage:");
575 for (i = 0; i < STORAGE_SIZE; i++) {
576 fprintf (stdout, " %g", storage[i]);
577 }
578 fprintf (stdout, "\n");
579}
580
2a688642
LM
581/* While do function */
582
583double while_do (element_t *cond, element_t *action)
584{
585 double ret = 0;
586 element_t *temp = NULL;
587
588 VERBOSE (DEBUG, fprintf (stdout, "starting while loop\n"));
2a688642
LM
589 while (1) {
590 VERBOSE (DEBUG, fprintf (stdout, "loop...\n"));
591
592 temp = dupelement (cond);
593 if (!evaluate_element (temp, 0)) {
594 break;
595 }
596 if (action) {
597 temp = dupelement (action);
598 ret = evaluate_element (temp, 0);
599 }
600 }
601
602 VERBOSE (DEBUG, fprintf (stdout, "ending while loop\n"));
603
604 return ret;
605}
606
124da7fd
LM
607/* program function */
608
609double program_do (element_t **prog, int nbcalls)
610{
611 double ret = 0;
612 int i;
613 for (i = 0; i < nbcalls; i++) {
614 ret = evaluate_element (prog[i], 0);
615 prog[i] = NULL;
616 }
617 return ret;
618}
619
2a5ec9d1
LM
620/* print function */
621
622void set_format (char *prompt, int precision)
623{
624 char buffer[128] = {0};
625 sprintf (buffer, "%s%%.%dg\n", prompt, precision);
626 free_format ();
627 format = strdup (buffer);
628}
629
630void free_format ()
631{
632 if (format) {
633 free (format);
634 format = NULL;
635 }
636}
637
638double print (double value)
639{
640 fprintf (stdout, format ? format : "=> %.6g\n", value);
641 fflush (stdout);
642 return value;
643}
644
89cf0955
LM
645/* quit function */
646
647void quit (void)
648{
04d68907 649 fprintf (stdout, "bye\n");
89cf0955
LM
650 exit (0);
651}
652
653/* help message */
654
655void help (void)
656{
04d68907 657 fprintf (stdout, "calc is a simple calculator\n\n");
94b4e517
LM
658 fprintf (stdout, "supported operators:");
659 fprintf (stdout, " + - * / %% ^\n");
660 fprintf (stdout, "camparison operators:");
661 fprintf (stdout, " == != >= <= > <\n");
662 fprintf (stdout, "logical operators:");
663 fprintf (stdout, " & | !\n");
9e52bbc5 664 fprintf (stdout, "mathematic functions:");
b9c1c40d
LM
665 fprintf (stdout, " pow sqrt log exp\n");
666 fprintf (stdout, "trigonometric functions:");
667 fprintf (stdout, " cos sin tan acos asin atan\n");
94b4e517 668 fprintf (stdout, "supported functions:");
9e52bbc5 669 fprintf (stdout, " abs ceil floor\n");
94b4e517 670 fprintf (stdout, "storage functions:");
a8cf32ba 671 fprintf (stdout, " sto rcl inc dec\n");
94b4e517 672 fprintf (stdout, "conditional functions:");
715580ff 673 fprintf (stdout, " cond while print {}\n");
94b4e517
LM
674 fprintf (stdout, "miscellaneous functions:");
675 fprintf (stdout, " quit help\n");
676 fprintf (stdout, "supported constants:");
471da7c9 677 fprintf (stdout, " e pi\n");
89cf0955 678}
3b4b0bbe 679
f2927108
LM
680/* evaluate element tree */
681
89cf0955
LM
682#define MASK_SUB 0x1
683#define MASK_DIV 0x2
684
3b4b0bbe 685double evaluate_element (element_t *root, char mask)
f2927108
LM
686{
687 double op0 = 0, op1 = 0;
3b4b0bbe 688 char nextmask = mask;
f2927108
LM
689
690 if ((root == NULL) || (root == ERROR_OP)) {
04d68907 691 VERBOSE (WARNING, fprintf (stdout, "error while evaluating\n"));
f2927108
LM
692 return 0;
693 }
694
3b4b0bbe
LM
695 /* mask to manage sub operator sub and div */
696 switch (root->func) {
697 case Add:
698 nextmask &= ~MASK_SUB;
699 nextmask &= ~MASK_DIV;
700 break;
701 case Sub:
702 nextmask |= MASK_SUB;
703 nextmask &= ~MASK_DIV;
704 break;
705 case Mul:
706 nextmask &= ~MASK_DIV;
707 break;
708 case Div:
709 nextmask |= MASK_DIV;
710 break;
711 default:
712 nextmask = mask;
713 }
714
f2927108
LM
715 switch (root->func) {
716 case Val:
3b4b0bbe
LM
717 case Sig:
718 op0 = (root->ops[0]) ? evaluate_element (root->ops[0], nextmask) : root->value;
f2927108
LM
719 break;
720 case Add:
721 case Sub:
722 case Mul:
723 case Div:
c47a9298 724 case Mod:
f2927108 725 case Pow:
3639df66 726 case Store:
7fe742c9
LM
727 case Equal:
728 case Diff:
729 case Ge:
730 case Le:
731 case Gt:
732 case Lt:
ca3e2a2f
LM
733 case And:
734 case Or:
f2927108 735 if (root->ops[1]) {
3b4b0bbe 736 op1 = evaluate_element (root->ops[1], nextmask);
3639df66 737 } else if (root->func != Store) {
04d68907 738 VERBOSE (WARNING, fprintf (stdout, "error while evaluating (op[1])\n"));
f2927108
LM
739 return 0;
740 }
741 /* fallthrough */
742 case Sqr:
743 case Cos:
744 case Sin:
9e52bbc5
LM
745 case Tan:
746 case Acos:
747 case Asin:
471da7c9 748 case Atan:
f2927108
LM
749 case Log:
750 case Exp:
9e52bbc5
LM
751 case Abs:
752 case Ceil:
753 case Floor:
6ba1dd0f 754 case Recall:
a8cf32ba
LM
755 case Inc:
756 case Dec:
ca3e2a2f 757 case Not:
94b4e517 758 case Cond:
f2927108 759 if (root->ops[0]) {
3b4b0bbe 760 op0 = evaluate_element (root->ops[0], 0);
f2927108 761 } else {
04d68907 762 VERBOSE (WARNING, fprintf (stdout, "error while evaluating (op[0])\n"));
f2927108
LM
763 return 0;
764 }
89cf0955 765 break;
6ba1dd0f 766 case Disp:
471da7c9
LM
767 case Quit:
768 case Help:
5075f6ea 769 case Ans:
471da7c9
LM
770 case Pi:
771 case E:
124da7fd 772 case Prog:
09d87cae 773 break;
2a688642 774 case While:
09d87cae
LM
775 if (root->ops[0] == NULL) {
776 VERBOSE (WARNING, fprintf (stdout, "error while evaluating (op[0])\n"));
777 return 0;
778 }
89cf0955 779 break;
715580ff
LM
780 case Print:
781 op0 = (root->ops[0]) ? evaluate_element (root->ops[0], 0) : answer;
782 break;
f2927108
LM
783 }
784
785 switch (root->func) {
3b4b0bbe
LM
786 case Val: return op0;
787 case Sig: return -op0;
788 case Add: return ((mask & MASK_SUB) == 0) ? op0 + op1 : op0 - op1;
789 case Sub: return ((mask & MASK_SUB) == 0) ? op0 - op1 : op0 + op1;
790 case Mul: return ((mask & MASK_DIV) == 0) ? op0 * op1 : op0 / op1;
791 case Div: return ((mask & MASK_DIV) == 0) ? op0 / op1 : op0 * op1;
c47a9298 792 case Mod: return fmod (op0, op1);
f2927108
LM
793 case Pow: return pow (op0, op1);
794 case Sqr: return sqrt (op0);
795 case Cos: return cos (op0);
796 case Sin: return sin (op0);
9e52bbc5
LM
797 case Tan: return tan (op0);
798 case Acos: return acos (op0);
799 case Asin: return asin (op0);
471da7c9 800 case Atan: return atan (op0);
f2927108
LM
801 case Log: return log (op0);
802 case Exp: return exp (op0);
9e52bbc5
LM
803 case Abs: return fabs (op0);
804 case Ceil: return ceil (op0);
805 case Floor: return floor (op0);
3639df66 806 case Store: return store ((int)op0, (op1) ? op1 : answer);
6ba1dd0f 807 case Recall: return recall ((int)op0);
a8cf32ba
LM
808 case Inc: return increase ((int)op0);
809 case Dec: return decrease ((int)op0);
6ba1dd0f 810 case Disp: display (); break;
471da7c9
LM
811 case Quit: quit (); break;
812 case Help: help (); break;
5075f6ea 813 case Ans: return answer;
471da7c9
LM
814 case Pi: return M_PI;
815 case E: return M_E;
7fe742c9
LM
816 case Equal: return op0 == op1;
817 case Diff: return op0 != op1;
818 case Ge: return op0 >= op1;
819 case Le: return op0 <= op1;
820 case Gt: return op0 > op1;
821 case Lt: return op0 < op1;
ca3e2a2f
LM
822 case And: return (op0 != 0) && (op1 != 0);
823 case Or: return (op0 != 0) || (op1 != 0);
824 case Not: return (op0 == 0);
94b4e517
LM
825 case Cond:
826 if ((op0) && (root->ops[1])) {
827 return evaluate_element (root->ops[1], 0);
828 } else if ((!op0) && (root->ops[2])) {
829 return evaluate_element (root->ops[2], 0);
830 } else {
831 return 0;
832 }
2a688642 833 case While: return while_do (root->ops[0], root->ops[1]);
124da7fd 834 case Prog: return program_do (root->ops, root->nbops);
2a5ec9d1 835 case Print: return print (op0);
f2927108
LM
836 }
837
838 return 0;
839}
840
b9c1c40d
LM
841char **generate_completion_list ()
842{
db660e60
LM
843 int i, j, l = 0;
844 char **list = (char **) calloc (NB_OPERATORS + NB_FUNCTIONS + NB_CONSTANTS + NB_SYMBOLS + 1, sizeof (char *));
b9c1c40d
LM
845 if (list == NULL) {
846 VERBOSE (ERROR, fprintf (stderr, "can't allocate memory\n"));
847 exit (1);
848 }
849
db660e60
LM
850 for (i = 0; i < NB_OPERATORS; i++) {
851 list[l] = strdup ((operators + i)->keyword);
852 for (j = 0; j < (int)strlen (list[l]); j++) {
853 if (list[i][j] == '\t') {
854 list[i][j] = '\0';
855 }
856 }
d8f4df0f
LM
857 if (list[l] != NULL) {
858 l++;
db660e60 859 }
db660e60
LM
860 }
861
b9c1c40d
LM
862 for (i = 0; i < NB_FUNCTIONS; i++) {
863 list[l] = strdup ((functions + i)->keyword);
d8f4df0f
LM
864 if (list[l] != NULL) {
865 l++;
b9c1c40d 866 }
b9c1c40d
LM
867 }
868
869 for (i = 0; i < NB_CONSTANTS; i++) {
870 list[l] = strdup ((constants + i)->keyword);
d8f4df0f
LM
871 if (list[l] != NULL) {
872 l++;
b9c1c40d 873 }
b9c1c40d
LM
874 }
875
db660e60
LM
876 for (i = 0; i < NB_SYMBOLS; i++) {
877 list[l] = strdup (symbols[i]);
d8f4df0f
LM
878 if (list[l] != NULL) {
879 l++;
db660e60 880 }
db660e60
LM
881 }
882
b9c1c40d
LM
883 return (list);
884}
885
886void free_completion_list (char **list)
887{
888 int i;
889
890 if (list) {
891 for (i = 0; i < NB_FUNCTIONS + NB_CONSTANTS; i++) {
892 if (list[i] != NULL) {
893 free (list[i]);
894 }
895 }
896 free (list);
897 }
898}
899
900
bc97a989 901/* vim: set ts=4 sw=4 et: */