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