5749367 [rkeene@sledge /home/rkeene/projects/ircbot/bot]$ cat -n dcalc.c
  1 /* contributed by demoncrat@efnet.#c on march 2001. */
  2 /* edited by megaton. added double precision numbers */
  3 
  4 #include <assert.h>
  5 #include <math.h>
  6 #include <stdio.h>
  7 #include <stdlib.h>
  8 #include "dcalc.h"
  9 
 10 
 11 static const char *complaint = NULL;
 12 
 13 static void complain (const char *msg)
 14 {
 15   if (complaint == NULL)
 16     complaint = msg;
 17 }
 18 
 19 
 20 enum {
 21   HALT, PUSH, ADD, SUB, MUL, DIV, MOD, POWER
 22 };
 23 
 24 typedef Value instruc;
 25 
 26 static instruc code[CODESIZE];
 27 static instruc *here = code;
 28 
 29 static void gen (instruc opcode)
 30 {
 31   if (code + CODESIZE <= here)
 32     {
 33       complain ("Expression too complicated");
 34       return;
 35     }
 36 
 37   *here++ = opcode;
 38 }
 39 
 40 static void gen_push (Value v)
 41 {
 42   gen (PUSH);
 43   gen ((instruc) v);
 44 }
 45 
 46 static Value run()
 47 {
 48   Value stack[STACKSIZE];
 49   Value *sp = stack + STACKSIZE;
 50   instruc *pc = code;
 51 
 52 #define need(n)                         \
 53   do {                                  \
 54     if (sp - (n) < stack)               \
 55       {                                 \
 56         complain ("Stack overflow");    \
 57         return 0;                       \
 58       }                                 \
 59   } while (0)
 60 
 61   for (;;)
 62     switch ((unsigned)*pc++)
 63       {
 64       case HALT: return sp[0]; break;
 65       case PUSH: need (1); *--sp = (Value) *pc++; break;
 66       case ADD: sp[1] += sp[0]; ++sp; break;
 67       case SUB: sp[1] -= sp[0]; ++sp; break;
 68       case MUL: sp[1] *= sp[0]; ++sp; break;
 69       case DIV: sp[1] /= sp[0]; ++sp; break;
 70       case MOD: (long)sp[1] %= (long)sp[0]; ++sp; break;
 71       case POWER: sp[1] = pow (sp[1], sp[0]); ++sp; break;
 72       default: assert (0);
 73       }
 74 }
 75 
 76 
 77 static const char *p;
 78 static int token;
 79 static Value token_value;
 80 
 81 static void next () 
 82 {
 83   char *endptr;
 84 
 85   switch (*p)
 86     {
 87     case '0':
 88     case '1':
 89     case '2':
 90     case '3':
 91     case '4':
 92     case '5':
 93     case '6':
 94     case '7':
 95     case '8':
 96     case '9':
 97       token = PUSH;
 98       token_value = strtod (p, &endptr);
 99       p = endptr;
100       break;
101 
102     case '+': 
103     case '-': 
104     case '*': 
105     case '/': 
106     case '%': 
107     case '^':
108     case '(':
109     case ')':
110       token = *p++;
111       break;
112 
113     case ' ':
114     case '\t':
115       ++p;
116       next ();
117       break;
118 
119     case '\0':
120       token = '\0';
121       break;
122 
123     default:
124       complain ("Syntax error: unknown token type");
125       token = '\0';
126       break;
127     }
128 }
129 
130 static void parse_expr (int precedence);
131 
132 static void parse_factor () 
133 {
134   switch (token)
135     {
136     case PUSH:
137       gen_push (token_value);
138       next ();
139       break;
140 
141     case '-':           /* unary minus */
142       next ();
143       gen_push (0);
144       parse_factor ();
145       gen (SUB);
146       break;
147 
148     case '(':
149       next ();
150       parse_expr (0);
151       if (token != ')')
152     complain ("Syntax error: expected ')'");
153       next ();
154       break;
155 
156     default:
157       complain ("Syntax error: expected a factor");
158       next ();
159     }
160 }
161 
162 static void parse_expr (int precedence) 
163 {
164   parse_factor ();
165   for (;;) 
166     {
167       int l, r, rator;   /* left precedence, right precedence, and operator */
168 
169       switch (token) {
170       case '+': l = 1; r = 2; rator = ADD; break;
171       case '-': l = 1; r = 2; rator = SUB; break;
172     
173       case '*': l = 3; r = 4; rator = MUL; break;
174       case '/': l = 3; r = 4; rator = DIV; break;
175       case '%': l = 3; r = 4; rator = MOD; break;
176 
177       case '^': l = 5; r = 5; rator = POWER; break;
178     
179       default: return;
180       }
181 
182       if (l < precedence)
183     return;
184 
185       next ();
186       parse_expr (r);
187       gen (rator);
188     }
189 }
190 
191 const char *dcalc (Value *result, const char *expression)
192 {
193   *result = 0;
194 
195   complaint = NULL;
196   p = expression;
197   here = code;
198   next ();
199   parse_expr (0);
200   if (*p != '\0')
201     complain ("Syntax error: unexpected token");
202 
203   if (!complaint)
204     {
205       gen (HALT);
206       *result = run ();
207     }
208 
209   return complaint;
210 }
5749368 [rkeene@sledge /home/rkeene/projects/ircbot/bot]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2003-12-11 08:06:35