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