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