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