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