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