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