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