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