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