1 /* calc.c 01/13/1996
2 * a simple calculator.
3 */
4
5 /* Copyright (c) 1995,1996 Sascha Demetrio
6 * Copyright (c) 2009, 2010, 2015, 2016 Peter Pentchev
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * If you modify any part of HEXER and redistribute it, you must add
15 * a notice to the `README' file and the modified source files containing
16 * information about the changes you made. I do not want to take
17 * credit or be blamed for your modifications.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * If you modify any part of HEXER and redistribute it in binary form,
22 * you must supply a `README' file containing information about the
23 * changes you made.
24 * 3. The name of the developer may not be used to endorse or promote
25 * products derived from this software without specific prior written
26 * permission.
27 *
28 * HEXER WAS DEVELOPED BY SASCHA DEMETRIO.
29 * THIS SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
30 * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
31 * NOT MAKE USE OF THIS WORK.
32 *
33 * DISCLAIMER:
34 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE
38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 * SUCH DAMAGE.
45 */
46
47 #include "config.h"
48 #include "defs.h"
49
50 #define NDEBUG
51
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <ctype.h>
56 #include <assert.h>
57 #include <math.h>
58 #if HAVE_FLOAT_H
59 #include <float.h>
60 #endif
61 #include <limits.h>
62
63 #include "buffer.h"
64 #include "hexer.h"
65 #include "calc.h"
66 #include "readline.h"
67 #include "tio.h"
68 #include "util.h"
69
70 #define CALC_STACKSIZE 1024
71
72 #ifndef DBL_EPSILON
73 #define DBL_EPSILON (1e-9)
74 #endif
75
76 #ifndef LONG_BITS
77 #define LONG_BITS 32
78 #endif
79
80 #ifndef DEBUG
81 #define DEBUG 0
82 #endif
83
84 static int calc_stack_initialized_f = 0;
85 static int calc_command_counter = 0;
86
87 enum calc_object_e {
88 CO_NONE, /* uninitialized */
89 CO_INTEGER, CO_FLOAT, CO_BOOLEAN, /* numeric values */
90 CO_UNARY_OPERATOR, /* unary operator sign */
91 CO_BINARY_OPERATOR, /* binary operator sign */
92 CO_VARIABLE, /* variable name */
93 CO_ERROR /* error message */
94 };
95
96 #define CO_VALUE(x) (x.type == CO_INTEGER \
97 || x.type == CO_FLOAT \
98 || x.type == CO_BOOLEAN)
99
100 static const char *calc_object_names[] = {
101 "none", "integer", "float", "boolean", "unary operator", "binary operator",
102 "variable", "error", 0
103 };
104
105 enum calc_unary_operator_e {
106 OP_NEG, OP_NOT, OP_COMP,
107 OP_PAROPEN, OP_PARCLOSE,
108 OP_EXEC,
109 OP_max_unary_operator
110 };
111
112 static const char *calc_unary_operator_names[OP_max_unary_operator] = {
113 "- neg", "! not", "~ comp", "( paropen", ") parclose", ": exec"
114 };
115
116 enum calc_binary_operator_e {
117 OP_POW,
118 OP_MUL, OP_DIV, OP_MOD,
119 OP_ADD, OP_SUB,
120 OP_SHL, OP_SHR,
121 OP_LES, OP_LEQ, OP_GRT, OP_GEQ,
122 OP_EQU, OP_NEQ,
123 OP_AND, OP_XOR, OP_OR,
124 OP_LAND, OP_LOR,
125 OP_ASSIGN,
126 OP_max_binary_operator
127 };
128
129 static int prec[OP_max_binary_operator] = {
130 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 6, 7, 7, 8
131 };
132
133 static const char *calc_binary_operator_names[OP_max_binary_operator] = {
134 "** pow",
135 "* mul", "/ div", "% mod", "+ add", "- sub", "<< shl", ">> shr",
136 "< les", "<= leq", "> grt", ">= geq", "== equ", "!= neq",
137 "& and", "^ xor", "| or", "&& land", "|| lor", "= assign"
138 };
139
140 struct calc_object_s {
141 enum calc_object_e type;
142 union {
143 long i; /* `CO_INTEGER', `CO_BOOLEAN' */
144 double f; /* `CO_FLOAT' */
145 char *s; /* `CO_VARIABLE', `CO_ERROR' */
146 enum calc_unary_operator_e uo; /* `CO_UNARY_OPERATOR' */
147 enum calc_binary_operator_e bo; /* `CO_BINARY_OPERATOR' */
148 } u;
149 };
150
151 /* a simple list of variables.
152 */
153 struct calc_variable_s {
154 char *name;
155 struct calc_object_s object;
156 struct calc_variable_s *next;
157 } *calc_variable_list = 0;
158
159 #ifdef CALC_COMPILE
160 enum calc_code_e {
161 CC_VALUE, /* immediate value */
162 CC_INSTRUCTION /* instruction */
163 };
164
165 static char *calc_code_names[] = {
166 "VALUE", "INSTRUCTION", 0
167 };
168
169 #if 0
170 enum calc_instruction_e {
171 CI_ADD, /* add the top two elements on the stack */
172 CI_ADDI, /* add an immediate value to the top element */
173 CI_SUB, /* substact the top two elements */
174 CI_SUBI, /* substact immediate value from the top element */
175 CI_MUL, /* multiply the top two elements */
176 CI_MULI, /* multiply an immediate value with the top element */
177 CI_POW, /* compute s[-2] ** s[-1] */
178 CI_POWI, /* compute s[-1] ** i (immediate value) */
179 CI_IDIV, /* integer divide the top two elements */
180 CI_IDIVI, /* integer divide the top element by an immediate value */
181 CI_DIV, /* divide the top two elements */
182 CI_DIVI, /* divide the top element by an immediate value */
183 CI_SHL, /* shift left s[-2] by s[-1] bits */
184 CI_SHLI, /* shift left the top element by an immediate value */
185 CI_SHR, /* shift right s[-2] by s[-1] bits */
186 CI_SHRI, /* shift right the top element by an immediate value */
187 CI_LES, /* check if the top element is less than zero */
188 CI_LEQ, /* check if the top element is less or equal than zero */
189 CI_GRT, /* check if the top element is greater than zero */
190 CI_GEQ, /* check if the top element is greater or equal than zero */
191 CI_EQU, /* check if the top element is equal to zero */
192 CI_NEQ, /* check if the top element is not equal to zero */
193 CI_PUSH, /* push an immediate value onto the execution stack */
194 CI_POP, /* remove an element from the execution stack */
195 CI_VALUE, /* push the value of a variable onto the execution stack */
196 CI_ASSIGN, /* assign the top element to a variable */
197 #if 0
198 CI_BEQ, /* branch on equal */
199 CI_BNE, /* branch on not equal */
200 #endif
201 CI_MAX /* number of instructions */
202 };
203
204 static char *calc_instruction_names[] = {
205 "ADD", "ADDI", "SUB", "SUBI", "MUL", "MULI", "POW", "POWI", "IDIV", "IDIVI",
206 "DIV", "DIVI", "SHL", "SHLI", "SHR", "SHRI", "LES", "LEQ", "EQU", "NEQ",
207 "PUSH", "POP", "VALUE", "ASSIGN",
208 "BEQ", "BNE", 0
209 };
210 #endif
211
212 struct calc_code_s {
213 enum calc_code_e type;
214 union {
215 enum calc_instruction_e instruction;
216 struct calc_object_s object;
217 } u;
218 };
219 #endif
220
221 static struct calc_object_s stack[CALC_STACKSIZE];
222 static int sp;
223
224 static int
calc_initialize_stack(void)225 calc_initialize_stack(void)
226 {
227 int i;
228
229 if (calc_stack_initialized_f) return 0;
230 ++calc_stack_initialized_f;
231 for (i = 0; i < CALC_STACKSIZE; ++i) stack[i].type = CO_NONE;
232 return 0;
233 }
234 /* calc_initialize_stack */
235
236 static int
calc_clear_stack(int count)237 calc_clear_stack(int count)
238 /* remove the trailing `count' stack elements from the stack.
239 */
240 {
241 for (--sp; count; --count, --sp) {
242 switch (stack[sp].type) {
243 case CO_VARIABLE:
244 case CO_ERROR:
245 free(stack[sp].u.s);
246 stack[sp].u.s = 0;
247 break;
248 default:
249 break;
250 }
251 stack[sp].type = CO_NONE;
252 }
253 ++sp;
254 return 0;
255 }
256 /* calc_clear_stack */
257
258 static int
calc_set_stack(int position,struct calc_object_s object)259 calc_set_stack(int position, struct calc_object_s object)
260 {
261 if (stack[position].type == CO_ERROR || stack[position].type == CO_VARIABLE)
262 free(stack[position].u.s);
263 stack[position] = object;
264 return 0;
265 }
266 /* calc_set_stack */
267
268 static char *
calc_sprint(char * s,struct calc_object_s object)269 calc_sprint(char *s, struct calc_object_s object)
270 {
271 switch(object.type) {
272 case CO_BINARY_OPERATOR:
273 sprintf(s, "%s", calc_binary_operator_names[(int)object.u.bo] + 3);
274 break;
275 case CO_UNARY_OPERATOR:
276 sprintf(s, "%s", calc_unary_operator_names[(int)object.u.uo] + 3);
277 break;
278 case CO_INTEGER:
279 sprintf(s, "%li 0%lo 0x%lx", object.u.i, object.u.i, object.u.i);
280 break;
281 case CO_FLOAT:
282 sprintf(s, "%g", object.u.f);
283 break;
284 case CO_BOOLEAN:
285 sprintf(s, "%s", object.u.i ? "true" : "false");
286 break;
287 case CO_ERROR:
288 case CO_VARIABLE:
289 sprintf(s, "%s", object.u.s);
290 break;
291 default:
292 sprintf(s, "INVALID OBJECT");
293 }
294 return s;
295 }
296 /* calc_sprint */
297
298 #if DEBUG || MYCALC
299 static void
calc_print(struct calc_object_s x)300 calc_print(struct calc_object_s x)
301 {
302 char result[256];
303 calc_sprint(result, x);
304 printf("%s", result);
305 }
306
307 static void
calc_stack(void)308 calc_stack(void)
309 {
310 size_t i;
311 for (i = 0; i < sp; i++)
312 {
313 calc_print(stack[i]);
314 putchar('\n');
315 }
316 }
317 #endif
318
319 static int
calc_error(struct calc_object_s * x,const char * fmt,...)320 calc_error(struct calc_object_s *x, const char *fmt, ...)
321 {
322 va_list ap;
323 char buf[256];
324
325 va_start(ap, fmt);
326 vsprintf(buf, fmt, ap);
327 if (x->type != CO_ERROR) {
328 x->type = CO_ERROR;
329 x->u.s = strdup_fatal(buf);
330 }
331 va_end(ap);
332 return 0;
333 }
334 /* calc_error */
335
336 static int
calc_evaluate(struct calc_object_s * object)337 calc_evaluate(struct calc_object_s *object)
338 {
339 struct calc_variable_s *i;
340
341 assert(object->type == CO_VARIABLE);
342 for (i = calc_variable_list; i; i = i->next)
343 if (!strcmp(object->u.s, i->name)) {
344 *object = i->object;
345 return 0;
346 }
347 calc_error(object, "undefined variable `%s'", object->u.s);
348 return -1;
349 }
350 /* calc_evaluate */
351
352 static int
calc_assign(struct calc_object_s x,struct calc_object_s y)353 calc_assign(struct calc_object_s x, struct calc_object_s y)
354 {
355 struct calc_variable_s *i;
356
357 assert(x.type == CO_VARIABLE);
358 assert(y.type != CO_VARIABLE);
359 assert(y.type != CO_ERROR);
360 for (i = calc_variable_list; i; i = i->next)
361 if (!strcmp(x.u.s, i->name)) {
362 i->object = y;
363 return 0;
364 }
365 i = (struct calc_variable_s *)malloc_fatal(sizeof *i);
366 i->object = y;
367 i->name = strdup_fatal(x.u.s);
368 i->next = calc_variable_list;
369 calc_variable_list = i;
370 return 0;
371 }
372 /* calc_assign */
373
374 static int
calc_operation(int position,int binary)375 calc_operation(int position, int binary)
376 /* evaluate the simple expression on stack position `position' and
377 * update the stack. if `binary == 0', a unary expression is expected,
378 * else a binary expression is expected. the function returns 0 on
379 * success and -1 on error.
380 */
381 {
382 struct calc_object_s x, y, op;
383 int int_f;
384 int error_f = 0;
385 int nremove; /* number of elements to remove from the stack */
386 int i;
387
388 if (binary) { /* binary operator */
389 nremove = 2;
390 assert(position + 2 < sp);
391 x = stack[position];
392 op = stack[position + 1];
393 y = stack[position + 2];
394 if (x.type == CO_VARIABLE && op.u.bo != OP_ASSIGN) calc_evaluate(&x);
395 if (y.type == CO_VARIABLE) calc_evaluate(&y);
396 if (op.type != CO_BINARY_OPERATOR || !CO_VALUE(y)) {
397 if (y.type == CO_ERROR) x = y; else calc_error(&x, "syntax error");
398 ++error_f;
399 goto exit;
400 }
401 switch (op.u.bo) {
402 case OP_POW:
403 int_f = 0;
404 switch (x.type) {
405 case CO_BOOLEAN:
406 case CO_INTEGER:
407 int_f = 1;
408 x.type = CO_FLOAT;
409 x.u.f = (double)x.u.i;
410 case CO_FLOAT:
411 if (y.type != CO_FLOAT) {
412 y.type = CO_FLOAT;
413 y.u.f = (double)y.u.i;
414 } else
415 int_f = 0;
416 x.u.f = pow(x.u.f, y.u.f);
417 if (int_f && x.u.f < (unsigned)(1 << (LONG_BITS - 1)) - 1) {
418 x.type = CO_INTEGER;
419 x.u.i = (int)x.u.f;
420 }
421 break;
422 default:
423 calc_error(&x, "syntax error");
424 ++error_f;
425 break;
426 }
427 break;
428 case OP_MUL:
429 switch (x.type) {
430 case CO_BOOLEAN:
431 if (y.type == CO_INTEGER) x.type = CO_INTEGER;
432 case CO_INTEGER:
433 if (y.type != CO_FLOAT) {
434 x.u.i *= y.u.i;
435 break;
436 } else {
437 x.u.f = (double)x.u.i;
438 x.type = CO_FLOAT;
439 }
440 case CO_FLOAT:
441 x.u.f *= y.type == CO_FLOAT ? y.u.f : (double)y.u.i;
442 break;
443 default:
444 calc_error(&x, "syntax error");
445 ++error_f;
446 break;
447 }
448 break;
449 case OP_DIV:
450 if (y.type == CO_FLOAT ? fabs(y.u.f) < DBL_EPSILON : !y.u.i) {
451 calc_error(&x, "division by zero");
452 ++error_f;
453 break;
454 }
455 switch (x.type) {
456 case CO_BOOLEAN:
457 if (y.type == CO_INTEGER) x.type = CO_INTEGER;
458 case CO_INTEGER:
459 if (y.type != CO_FLOAT) {
460 x.u.i /= y.u.i;
461 break;
462 } else {
463 x.u.f = (double)x.u.i;
464 x.type = CO_FLOAT;
465 }
466 case CO_FLOAT:
467 x.u.f /= y.type == CO_FLOAT ? y.u.f : (double)y.u.i;
468 break;
469 default:
470 calc_error(&x, "syntax error");
471 ++error_f;
472 break;
473 }
474 break;
475 case OP_MOD:
476 if (x.type == CO_FLOAT || y.type == CO_FLOAT) {
477 calc_error(&x, "invalid type in binary operator MOD (%%)");
478 ++error_f;
479 break;
480 }
481 switch (x.type) {
482 case CO_BOOLEAN:
483 if (y.type == CO_INTEGER) x.type = CO_INTEGER;
484 case CO_INTEGER:
485 x.u.i %= y.u.i;
486 break;
487 case CO_FLOAT:
488 default:
489 calc_error(&x, "syntax error");
490 ++error_f;
491 break;
492 }
493 break;
494 case OP_ADD:
495 switch (x.type) {
496 case CO_BOOLEAN:
497 if (y.type == CO_INTEGER) x.type = CO_INTEGER;
498 case CO_INTEGER:
499 if (y.type != CO_FLOAT) {
500 x.u.i += y.u.i;
501 break;
502 } else {
503 x.u.f = (double)x.u.i;
504 x.type = CO_FLOAT;
505 }
506 case CO_FLOAT:
507 x.u.f += y.type == CO_FLOAT ? y.u.f : (double)y.u.i;
508 break;
509 default:
510 calc_error(&x, "syntax error");
511 ++error_f;
512 break;
513 }
514 break;
515 case OP_SUB:
516 switch (x.type) {
517 case CO_BOOLEAN:
518 if (y.type == CO_INTEGER) x.type = CO_INTEGER;
519 case CO_INTEGER:
520 if (y.type != CO_FLOAT) {
521 x.u.i -= y.u.i;
522 break;
523 } else {
524 x.u.f = (double)x.u.i;
525 x.type = CO_FLOAT;
526 }
527 case CO_FLOAT:
528 x.u.f -= y.type == CO_FLOAT ? y.u.f : (double)y.u.i;
529 break;
530 default:
531 calc_error(&x, "syntax error");
532 ++error_f;
533 break;
534 }
535 break;
536 case OP_SHL:
537 if (x.type == CO_FLOAT || y.type == CO_FLOAT) {
538 calc_error(&x, "invalid type in binary operator SHL (<<)");
539 ++error_f;
540 break;
541 }
542 switch (x.type) {
543 case CO_BOOLEAN:
544 if (y.type == CO_INTEGER) x.type = CO_INTEGER;
545 case CO_INTEGER:
546 if (y.u.i >= LONG_BITS) y.u.i = LONG_BITS - 1;
547 x.u.i <<= y.u.i;
548 break;
549 case CO_FLOAT:
550 default:
551 calc_error(&x, "syntax error");
552 ++error_f;
553 break;
554 }
555 break;
556 case OP_SHR:
557 if (x.type == CO_FLOAT || y.type == CO_FLOAT) {
558 calc_error(&x, "invalid type in binary operator SHR (>>)");
559 ++error_f;
560 break;
561 }
562 switch (x.type) {
563 case CO_BOOLEAN:
564 if (y.type == CO_INTEGER) x.type = CO_INTEGER;
565 case CO_INTEGER:
566 if (y.u.i >= LONG_BITS) y.u.i = LONG_BITS - 1;
567 x.u.i >>= y.u.i;
568 break;
569 case CO_FLOAT:
570 default:
571 calc_error(&x, "syntax error");
572 ++error_f;
573 break;
574 }
575 break;
576 case OP_LES:
577 switch (x.type) {
578 case CO_BOOLEAN:
579 case CO_INTEGER:
580 if (y.type != CO_FLOAT) {
581 x.u.i = x.u.i < y.u.i;
582 break;
583 } else
584 x.u.f = (double)x.u.i;
585 case CO_FLOAT:
586 x.u.i = x.u.f < (y.type == CO_FLOAT ? y.u.f : (double)y.u.i);
587 break;
588 default:
589 calc_error(&x, "syntax error");
590 ++error_f;
591 break;
592 }
593 x.type = CO_BOOLEAN;
594 break;
595 case OP_LEQ:
596 switch (x.type) {
597 case CO_BOOLEAN:
598 case CO_INTEGER:
599 if (y.type != CO_FLOAT) {
600 x.u.i = x.u.i <= y.u.i;
601 break;
602 } else
603 x.u.f = (double)x.u.i;
604 case CO_FLOAT:
605 x.u.i = x.u.f <= (y.type == CO_FLOAT ? y.u.f : (double)y.u.i);
606 break;
607 default:
608 calc_error(&x, "syntax error");
609 ++error_f;
610 break;
611 }
612 x.type = CO_BOOLEAN;
613 break;
614 case OP_GRT:
615 switch (x.type) {
616 case CO_BOOLEAN:
617 case CO_INTEGER:
618 if (y.type != CO_FLOAT) {
619 x.u.i = x.u.i > y.u.i;
620 break;
621 } else
622 x.u.f = (double)x.u.i;
623 case CO_FLOAT:
624 x.u.i = x.u.f > (y.type == CO_FLOAT ? y.u.f : (double)y.u.i);
625 break;
626 default:
627 calc_error(&x, "syntax error");
628 ++error_f;
629 break;
630 }
631 x.type = CO_BOOLEAN;
632 break;
633 case OP_GEQ:
634 switch (x.type) {
635 case CO_BOOLEAN:
636 case CO_INTEGER:
637 if (y.type != CO_FLOAT) {
638 x.u.i = x.u.i >= y.u.i;
639 break;
640 } else
641 x.u.f = (double)x.u.i;
642 case CO_FLOAT:
643 x.u.i = x.u.f >= (y.type == CO_FLOAT ? y.u.f : (double)y.u.i);
644 break;
645 default:
646 calc_error(&x, "syntax error");
647 ++error_f;
648 break;
649 }
650 x.type = CO_BOOLEAN;
651 break;
652 case OP_EQU:
653 switch (x.type) {
654 case CO_BOOLEAN:
655 case CO_INTEGER:
656 if (y.type != CO_FLOAT) {
657 x.u.i = x.u.i == y.u.i;
658 break;
659 } else
660 x.u.f = (double)x.u.i;
661 case CO_FLOAT:
662 if (y.type == CO_INTEGER) y.u.f = (double)y.u.i;
663 x.u.i = fabs(x.u.f - y.u.f) < DBL_EPSILON;
664 break;
665 default:
666 calc_error(&x, "syntax error");
667 ++error_f;
668 break;
669 }
670 x.type = CO_BOOLEAN;
671 break;
672 case OP_NEQ:
673 switch (x.type) {
674 case CO_BOOLEAN:
675 case CO_INTEGER:
676 if (y.type != CO_FLOAT) {
677 x.u.i = x.u.i != y.u.i;
678 break;
679 } else
680 x.u.f = (double)x.u.i;
681 case CO_FLOAT:
682 if (y.type == CO_INTEGER) y.u.f = (double)y.u.i;
683 x.u.i = fabs(x.u.f - y.u.f) >= DBL_EPSILON;
684 break;
685 default:
686 calc_error(&x, "syntax error");
687 ++error_f;
688 break;
689 }
690 x.type = CO_BOOLEAN;
691 break;
692 case OP_AND:
693 if (x.type == CO_FLOAT || y.type == CO_FLOAT) {
694 calc_error(&x, "invalid type in binary operator AND (&)");
695 ++error_f;
696 break;
697 }
698 switch (x.type) {
699 case CO_BOOLEAN:
700 if (y.type == CO_INTEGER) x.type = CO_INTEGER;
701 case CO_INTEGER:
702 if (y.u.i >= LONG_BITS) y.u.i = LONG_BITS - 1;
703 x.u.i &= y.u.i;
704 break;
705 case CO_FLOAT:
706 default:
707 calc_error(&x, "syntax error");
708 ++error_f;
709 break;
710 }
711 break;
712 case OP_XOR:
713 if (x.type == CO_FLOAT || y.type == CO_FLOAT) {
714 calc_error(&x, "invalid type in binary operator XOR (^)");
715 ++error_f;
716 break;
717 }
718 switch (x.type) {
719 case CO_BOOLEAN:
720 if (y.type == CO_INTEGER) x.type = CO_INTEGER;
721 case CO_INTEGER:
722 if (y.u.i >= LONG_BITS) y.u.i = LONG_BITS - 1;
723 x.u.i ^= y.u.i;
724 break;
725 case CO_FLOAT:
726 default:
727 calc_error(&x, "syntax error");
728 ++error_f;
729 break;
730 }
731 break;
732 case OP_OR:
733 if (x.type == CO_FLOAT || y.type == CO_FLOAT) {
734 calc_error(&x, "invalid type in binary operator OR (|)");
735 ++error_f;
736 break;
737 }
738 switch (x.type) {
739 case CO_BOOLEAN:
740 if (y.type == CO_INTEGER) x.type = CO_INTEGER;
741 case CO_INTEGER:
742 if (y.u.i >= LONG_BITS) y.u.i = LONG_BITS - 1;
743 x.u.i |= y.u.i;
744 break;
745 case CO_FLOAT:
746 default:
747 calc_error(&x, "syntax error");
748 ++error_f;
749 break;
750 }
751 break;
752 case OP_LAND: /* logical AND */
753 switch (x.type) {
754 case CO_BOOLEAN:
755 case CO_INTEGER:
756 x.u.i = x.u.i
757 && (y.type == CO_FLOAT ? fabs(y.u.f) >= DBL_EPSILON : y.u.i);
758 break;
759 case CO_FLOAT:
760 x.u.i = fabs(x.u.f) >= DBL_EPSILON
761 && (y.type == CO_FLOAT ? fabs(y.u.f) >= DBL_EPSILON : y.u.i);
762 break;
763 default:
764 calc_error(&x, "syntax error");
765 ++error_f;
766 break;
767 }
768 x.type = CO_BOOLEAN;
769 break;
770 case OP_LOR: /* logical OR */
771 switch (x.type) {
772 case CO_BOOLEAN:
773 case CO_INTEGER:
774 x.u.i = x.u.i
775 || (y.type == CO_FLOAT ? fabs(y.u.f) >= DBL_EPSILON : y.u.i);
776 break;
777 case CO_FLOAT:
778 x.u.i = fabs(x.u.f) >= DBL_EPSILON
779 || (y.type == CO_FLOAT ? fabs(y.u.f) >= DBL_EPSILON : y.u.i);
780 break;
781 default:
782 calc_error(&x, "syntax error");
783 ++error_f;
784 break;
785 }
786 x.type = CO_BOOLEAN;
787 break;
788 case OP_ASSIGN:
789 if (x.type != CO_VARIABLE) {
790 calc_error(&x, "invalid l-value in assignment");
791 ++error_f;
792 break;
793 }
794 calc_assign(x, y);
795 x = y;
796 break;
797 default:
798 calc_error(&x, "syntax error");
799 ++error_f;
800 break;
801 }
802 } else { /* unary operator */
803 nremove = 1;
804 assert(position + 1 < sp);
805 op = stack[position];
806 x = stack[position + 1];
807 assert(op.type == CO_UNARY_OPERATOR);
808 if (x.type == CO_VARIABLE) calc_evaluate(&x);
809 switch (op.u.uo) {
810 case OP_NEG:
811 switch (x.type) {
812 case CO_BOOLEAN:
813 case CO_INTEGER:
814 x.u.i = -x.u.i;
815 break;
816 case CO_FLOAT:
817 x.u.f = -x.u.f;
818 break;
819 default:
820 calc_error(&x, "syntax error");
821 ++error_f;
822 break;
823 }
824 break;
825 case OP_NOT: /* logical NOT */
826 switch (x.type) {
827 case CO_INTEGER:
828 x.type = CO_BOOLEAN;
829 case CO_BOOLEAN:
830 x.u.i = !x.u.i;
831 break;
832 case CO_FLOAT:
833 x.u.i = !x.u.f;
834 x.type = CO_BOOLEAN;
835 break;
836 default:
837 calc_error(&x, "syntax error");
838 ++error_f;
839 break;
840 }
841 break;
842 case OP_COMP: /* bit complement */
843 if (x.type == CO_FLOAT) {
844 calc_error(&x, "invalid type in unary operator COMP (~)");
845 ++error_f;
846 break;
847 }
848 switch (x.type) {
849 case CO_BOOLEAN:
850 x.type = CO_INTEGER;
851 case CO_INTEGER:
852 x.u.i = ~x.u.i;
853 break;
854 default:
855 calc_error(&x, "syntax error");
856 ++error_f;
857 break;
858 }
859 break;
860 case OP_PAROPEN:
861 break;
862 case OP_PARCLOSE:
863 case OP_EXEC:
864 /* `calc_operation()' should never be called for `OP_EXEC' or
865 * `OP_PARCLOSE'. */
866 default:
867 calc_error(&x, "syntax error");
868 ++error_f;
869 break;
870 }
871 }
872 exit:
873 for (i = position + 1; i < sp; ++i) calc_set_stack(i, stack[i + nremove]);
874 calc_clear_stack(nremove);
875 calc_set_stack(position, x);
876 return error_f;
877 }
878 /* calc_operation */
879
880 static int
calc_reduce(void)881 calc_reduce(void)
882 /* try to reduce to top of the stack. return values:
883 * -1: reduction failed due to an error. an error element has been put
884 * onto the stack.
885 * 0: no reduction.
886 * 1: reduction succeeded.
887 */
888 {
889 struct calc_object_s x, y, z;
890 int error_f = 0;
891 int reduce_f = 0;
892
893 if (sp < 2) goto exit_calc_reduce;
894 x = stack[sp - 1];
895 y = stack[sp - 2];
896 switch (x.type) {
897 case CO_INTEGER: case CO_FLOAT: case CO_BOOLEAN: case CO_VARIABLE:
898 switch (y.type) {
899 case CO_UNARY_OPERATOR:
900 if (y.u.uo != OP_PAROPEN) {
901 unary: error_f = calc_operation(sp - 2, 0);
902 ++reduce_f;
903 }
904 break;
905 case CO_BINARY_OPERATOR:
906 /* check if `y' is a unary minus */
907 if (y.u.bo == OP_SUB && (sp == 2 ? 1 : !CO_VALUE(stack[sp - 3]))) {
908 stack[sp - 2].type = CO_UNARY_OPERATOR;
909 stack[sp - 2].u.uo = OP_NEG;
910 goto unary;
911 }
912 break;
913 default:
914 calc_error(stack + sp++, "syntax error");
915 ++error_f;
916 break;
917 }
918 break;
919 case CO_UNARY_OPERATOR:
920 if (x.u.uo == OP_PARCLOSE)
921 goto eval;
922 else if (x.u.uo == OP_EXEC && sp > 3)
923 goto exec;
924 break;
925 case CO_BINARY_OPERATOR:
926 if (sp > 3) {
927 exec: z = stack[sp - 3];
928 if (z.type == CO_BINARY_OPERATOR) {
929 if (!CO_VALUE(y) && y.type != CO_VARIABLE) {
930 calc_error(stack + sp++, "syntax error");
931 ++error_f;
932 break;
933 } else if (prec[(int)z.u.bo] <= prec[(int)x.u.bo]
934 || x.type == CO_UNARY_OPERATOR) {
935 error_f = calc_operation(sp - 4, 1);
936 ++reduce_f;
937 break;
938 }
939 } else {
940 if (z.type != CO_UNARY_OPERATOR || z.u.uo != OP_PAROPEN) {
941 calc_error(stack + sp++, "syntax error");
942 ++error_f;
943 break;
944 }
945 }
946 }
947 break;
948 default: abort();
949 }
950 exit_calc_reduce:
951 return error_f ? -1 : reduce_f;
952
953 eval: /* evaluate a parenthesized expression */
954 if (sp > 1 && y.type == CO_UNARY_OPERATOR ? y.u.uo == OP_PAROPEN : 0) {
955 calc_clear_stack(2);
956 calc_error(stack + sp++, "empty parentheses");
957 ++error_f;
958 } else if (sp > 2) {
959 z = stack[sp - 3];
960 if (z.type == CO_BINARY_OPERATOR && sp > 3)
961 goto exec;
962 else if (z.type == CO_UNARY_OPERATOR) {
963 assert(z.u.uo == OP_PAROPEN);
964 if (!CO_VALUE(y)) {
965 calc_error(&y, "invalid object (%s) in parentheses",
966 calc_object_names[(int)y.type]);
967 ++error_f;
968 }
969 stack[sp - 3] = y;
970 calc_clear_stack(2);
971 ++reduce_f;
972 }
973 } else {
974 calc_clear_stack(1);
975 calc_error(stack + sp++, "unmatched ')'");
976 ++error_f;
977 }
978 return error_f ? -1 : reduce_f;
979 }
980 /* calc_reduce */
981
982 static int
istrue(char * s,char ** endptr)983 istrue(char *s, char **endptr)
984 {
985 static const char *true_strings[] = { "true", "t", "TRUE", "True", "T",
986 "yes", "y", "YES", "Yes", "on", "ON", "On", 0 };
987 int i, l;
988
989 for (i = 0; (l = (true_strings[i] ? strlen(true_strings[i]) : 0)); ++i)
990 if (!strncmp(true_strings[i], s, l)) {
991 *endptr = s + l;
992 return 1;
993 }
994 *endptr = s;
995 return 0;
996 }
997 /* istrue */
998
999 static int
isfalse(char * s,char ** endptr)1000 isfalse(char *s, char **endptr)
1001 {
1002 static const char *false_strings[] = { "false", "f", "FALSE", "False", "F",
1003 "no", "n", "NO", "No", "off", "OFF", "Off", 0 };
1004 int i, l;
1005
1006 for (i = 0; (l = (false_strings[i] ? strlen(false_strings[i]) : 0)); ++i)
1007 if (!strncmp(false_strings[i], s, l)) {
1008 *endptr = s + l;
1009 return 1;
1010 }
1011 *endptr = s;
1012 return 0;
1013 }
1014 /* isfalse */
1015
1016 #ifndef XDIGIT
1017 #define XDIGIT(x) (isdigit(x) ? x - '0' : tolower(x) - 'a' + 0xa)
1018 #endif
1019
1020 static int
calc_scan(char * expr)1021 calc_scan(char *expr)
1022 {
1023 char *p, *q, *r;
1024 long val;
1025 double fval;
1026 struct calc_object_s x;
1027 int float_f = 0;
1028 int base;
1029 int i;
1030
1031 calc_clear_stack(sp);
1032 for (p = expr; p;) {
1033 while (isspace(*p)) ++p;
1034 if (!*p) break;
1035 if (isdigit(*p) || *p == '.') {
1036 if (*p == '0') {
1037 if (tolower(p[1]) == 'x') /* hex */
1038 base = 0x10, r = p + 2;
1039 else if (isdigit(p[1])) /* oct */
1040 base = 010, r = p + 1;
1041 else
1042 goto dec;
1043 } else { /* dec */
1044 dec: base = 10, r = p;
1045 for (q = p, val = 0; isdigit(*q); ++q);
1046 if (*q == '.' || *q == 'e' || *q == 'E') ++float_f;
1047 }
1048 if (float_f) {
1049 fval = strtod(r, &p);
1050 x.type = CO_FLOAT;
1051 x.u.f = fval;
1052 } else {
1053 val = strtol(r, &p, base);
1054 x.type = CO_INTEGER;
1055 x.u.i = val;
1056 }
1057 } else if (istrue(p, &p)) {
1058 x.type = CO_BOOLEAN;
1059 x.u.i = 1;
1060 } else if (isfalse(p, &p)) {
1061 x.type = CO_BOOLEAN;
1062 x.u.i = 0;
1063 } else if (isalpha(*p) || *p == '_' || *p == '$') {
1064 for (q = p + 1; isalnum(*q) || *q == '_' || *q == '$'; ++q);
1065 x.type = CO_VARIABLE;
1066 x.u.s = strdup_fatal(p);
1067 x.u.s[q - p] = 0;
1068 p = q;
1069 } else {
1070 switch (*p) {
1071 case '*':
1072 ++p;
1073 x.type = CO_BINARY_OPERATOR;
1074 if (*p == '*') {
1075 ++p;
1076 x.u.bo = OP_POW;
1077 } else
1078 x.u.bo = OP_MUL;
1079 break;
1080 case '/':
1081 ++p;
1082 x.type = CO_BINARY_OPERATOR;
1083 x.u.bo = OP_DIV;
1084 break;
1085 case '%':
1086 ++p;
1087 x.type = CO_BINARY_OPERATOR;
1088 x.u.bo = OP_MOD;
1089 break;
1090 case '+':
1091 ++p;
1092 x.type = CO_BINARY_OPERATOR;
1093 x.u.bo = OP_ADD;
1094 break;
1095 case '-':
1096 ++p;
1097 x.type = CO_BINARY_OPERATOR;
1098 x.u.bo = OP_SUB;
1099 break;
1100 case '<':
1101 ++p;
1102 switch (*p) {
1103 case '<':
1104 ++p;
1105 x.type = CO_BINARY_OPERATOR;
1106 x.u.bo = OP_SHL;
1107 break;
1108 case '=':
1109 ++p;
1110 x.type = CO_BINARY_OPERATOR;
1111 x.u.bo = OP_LEQ;
1112 break;
1113 default:
1114 x.type = CO_BINARY_OPERATOR;
1115 x.u.bo = OP_LES;
1116 }
1117 break;
1118 case '>':
1119 ++p;
1120 switch (*p) {
1121 case '>':
1122 ++p;
1123 x.type = CO_BINARY_OPERATOR;
1124 x.u.bo = OP_SHR;
1125 break;
1126 case '=':
1127 ++p;
1128 x.type = CO_BINARY_OPERATOR;
1129 x.u.bo = OP_GEQ;
1130 break;
1131 default:
1132 x.type = CO_BINARY_OPERATOR;
1133 x.u.bo = OP_GRT;
1134 }
1135 break;
1136 case '=':
1137 ++p;
1138 switch (*p) {
1139 case '=':
1140 ++p;
1141 x.type = CO_BINARY_OPERATOR;
1142 x.u.bo = OP_EQU;
1143 break;
1144 default:
1145 x.type = CO_BINARY_OPERATOR;
1146 x.u.bo = OP_ASSIGN;
1147 }
1148 break;
1149 case '!':
1150 ++p;
1151 switch (*p) {
1152 case '=':
1153 ++p;
1154 x.type = CO_BINARY_OPERATOR;
1155 x.u.bo = OP_NEQ;
1156 break;
1157 default:
1158 x.type = CO_UNARY_OPERATOR;
1159 x.u.uo = OP_NOT;
1160 }
1161 break;
1162 case '&':
1163 ++p;
1164 switch (*p) {
1165 case '&':
1166 ++p;
1167 x.type = CO_BINARY_OPERATOR;
1168 x.u.bo = OP_LAND;
1169 break;
1170 default:
1171 x.type = CO_BINARY_OPERATOR;
1172 x.u.bo = OP_AND;
1173 }
1174 break;
1175 case '|':
1176 ++p;
1177 switch (*p) {
1178 case '|':
1179 ++p;
1180 x.type = CO_BINARY_OPERATOR;
1181 x.u.bo = OP_LOR;
1182 break;
1183 default:
1184 x.type = CO_BINARY_OPERATOR;
1185 x.u.bo = OP_OR;
1186 }
1187 break;
1188 case '^':
1189 ++p;
1190 x.type = CO_BINARY_OPERATOR;
1191 x.u.bo = OP_XOR;
1192 break;
1193 case '~':
1194 ++p;
1195 x.type = CO_UNARY_OPERATOR;
1196 x.u.uo = OP_COMP;
1197 break;
1198 case '(':
1199 ++p;
1200 x.type = CO_UNARY_OPERATOR;
1201 x.u.uo = OP_PAROPEN;
1202 break;
1203 case ')':
1204 ++p;
1205 x.type = CO_UNARY_OPERATOR;
1206 x.u.uo = OP_PARCLOSE;
1207 break;
1208 default:
1209 calc_error(stack + sp++, "unexpected character %c (0x%x)",
1210 isprint(*p) ? *p : ' ', (int)(unsigned char)*p);
1211 return -1;
1212 }
1213 }
1214 stack[sp++] = x;
1215 # if DEBUG
1216 calc_stack();
1217 while ((i = calc_reduce()) > 0) calc_stack();
1218 if (i < 0) {
1219 calc_stack();
1220 return -1;
1221 }
1222 # else
1223 while ((i = calc_reduce()) > 0);
1224 if (i < 0) return -1;
1225 # endif
1226 }
1227 x.type = CO_UNARY_OPERATOR;
1228 x.u.uo = OP_EXEC;
1229 stack[sp++] = x;
1230 # if DEBUG
1231 calc_stack();
1232 while ((i = calc_reduce()) > 0) calc_stack();
1233 if (i < 0) calc_stack();
1234 # else
1235 while ((i = calc_reduce()) > 0);
1236 # endif
1237 return i;
1238 }
1239 /* calc_scan */
1240
1241 #ifdef MYCALC
1242 int
main(int argc,char ** argv)1243 main(int argc, char **argv)
1244 {
1245 char buf[256];
1246 int error_f = 0;
1247 int i;
1248 struct calc_object_s x;
1249
1250 calc_initialize_stack();
1251 for (;;) {
1252 *buf = 0;
1253 if (argc > 1)
1254 for (i = 1; i < argc; ++i)
1255 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s", argv[i]);
1256 else
1257 fgets(buf, 256, stdin);
1258 if (!*buf) break;
1259 if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = 0;
1260 if (calc_scan(buf)) {
1261 /* search for error objects on the stack */
1262 for (i = sp - 1; i >= 0; --i)
1263 if (stack[i].type == CO_ERROR) {
1264 calc_print(stack[i]);
1265 ++error_f;
1266 putchar('\n');
1267 }
1268 if (!error_f) {
1269 printf("unknown error\nstack:\n");
1270 calc_stack();
1271 }
1272 } else {
1273 if (stack[1].type != CO_UNARY_OPERATOR || stack[1].u.uo != OP_EXEC)
1274 printf("syntax error");
1275 else {
1276 if (stack[0].type == CO_VARIABLE) calc_evaluate(stack);
1277 if (stack[0].type == CO_ERROR)
1278 calc_print(stack[0]);
1279 else if (!CO_VALUE(stack[0]))
1280 printf("syntax error");
1281 else {
1282 if (argc == 1) printf("$%i = ", ++calc_command_counter);
1283 calc_print(stack[0]);
1284 x.type = CO_VARIABLE;
1285 x.u.s = (char *)alloca(256);
1286 sprintf(x.u.s, "$%i", calc_command_counter);
1287 calc_assign(x, stack[0]);
1288 sprintf(x.u.s, "$$");
1289 calc_assign(x, stack[0]);
1290 }
1291 putchar('\n');
1292 }
1293 }
1294 calc_clear_stack(sp);
1295 if (argc > 1) break;
1296 }
1297 return 0;
1298 }
1299 /* main */
1300 #else
1301 char *
calculator(char * expr)1302 calculator(char *expr)
1303 {
1304 int i;
1305 int error_f = 0;
1306 static char result[256];
1307 struct calc_object_s x;
1308
1309 calc_initialize_stack();
1310 if (calc_scan(expr)) {
1311 /* search for error objects on the stack */
1312 for (i = sp - 1; i >= 0; --i)
1313 if (stack[i].type == CO_ERROR) {
1314 calc_sprint(result, stack[i]);
1315 ++error_f;
1316 break;
1317 }
1318 if (!error_f)
1319 sprintf(result, "unknown error");
1320 } else {
1321 if (stack[1].type != CO_UNARY_OPERATOR || stack[1].u.uo != OP_EXEC)
1322 sprintf(result, "syntax error");
1323 else {
1324 if (stack[0].type == CO_VARIABLE) calc_evaluate(stack);
1325 if (stack[0].type == CO_ERROR)
1326 calc_sprint(result, stack[0]);
1327 else if (!CO_VALUE(stack[0]))
1328 sprintf(result, "syntax error");
1329 else {
1330 sprintf(result, "$%i = ", ++calc_command_counter);
1331 calc_sprint(result + strlen(result), stack[0]);
1332 x.type = CO_VARIABLE;
1333 x.u.s = (char *)alloca(256);
1334 sprintf(x.u.s, "$%i", calc_command_counter);
1335 calc_assign(x, stack[0]);
1336 sprintf(x.u.s, "$$");
1337 calc_assign(x, stack[0]);
1338 }
1339 }
1340 }
1341 calc_clear_stack(sp);
1342 return result;
1343 }
1344 /* calculator */
1345 #endif
1346
1347 /* end of calc.c */
1348
1349 /* VIM configuration: (do not delete this line)
1350 *
1351 * vim:bk:nodg:efm=%f\:%l\:%m:hid:icon:
1352 * vim:sw=2:sm:textwidth=79:ul=1024:wrap:
1353 */
1354
1355