diff options
Diffstat (limited to '')
-rw-r--r-- | parex/egg.h | 127 | ||||
-rw-r--r-- | parex/eval.c | 651 | ||||
-rw-r--r-- | parex/evaltest.c | 50 |
3 files changed, 828 insertions, 0 deletions
diff --git a/parex/egg.h b/parex/egg.h new file mode 100644 index 0000000..6830edd --- /dev/null +++ b/parex/egg.h | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * EGG.H - part of the EGG system. | ||
3 | * | ||
4 | * Global definitions and function prototypes. | ||
5 | * | ||
6 | * By Shawn Hargreaves. | ||
7 | */ | ||
8 | |||
9 | |||
10 | #ifndef __EGG_H__ | ||
11 | #define __EGG_H__ | ||
12 | |||
13 | |||
14 | #ifndef TRUE | ||
15 | #define TRUE -1 | ||
16 | #define FALSE 0 | ||
17 | #endif | ||
18 | |||
19 | #ifndef MIN | ||
20 | #define MIN(x,y) (((x) < (y)) ? (x) : (y)) | ||
21 | #define MAX(x,y) (((x) > (y)) ? (x) : (y)) | ||
22 | #define MID(x,y,z) MAX((x), MIN((y), (z))) | ||
23 | #endif | ||
24 | |||
25 | #ifndef ABS | ||
26 | #define ABS(x) (((x) >= 0) ? (x) : (-(x))) | ||
27 | #endif | ||
28 | |||
29 | #ifndef ALLEGRO_H | ||
30 | struct BITMAP; | ||
31 | #endif | ||
32 | |||
33 | |||
34 | |||
35 | /* possible particle commands (ie. language keywords) */ | ||
36 | #define EGG_COMMAND_INIT 1 | ||
37 | #define EGG_COMMAND_SET 2 | ||
38 | #define EGG_COMMAND_IF 3 | ||
39 | #define EGG_COMMAND_LAY 4 | ||
40 | #define EGG_COMMAND_DIE 5 | ||
41 | |||
42 | |||
43 | |||
44 | /* each particle is controlled by a command list */ | ||
45 | typedef struct EGG_COMMAND | ||
46 | { | ||
47 | int type; /* command type */ | ||
48 | int line; /* source line number */ | ||
49 | char *var; /* variable to be set */ | ||
50 | char *exp; /* arithmetic expression */ | ||
51 | struct EGG_COMMAND *cmd; /* nested, child command list (if) */ | ||
52 | struct EGG_COMMAND *cmd2; /* more child commands (else) */ | ||
53 | struct EGG_COMMAND *next; /* linked list pointer */ | ||
54 | } EGG_COMMAND; | ||
55 | |||
56 | |||
57 | |||
58 | /* each type of particle is defined by one of these structures */ | ||
59 | typedef struct EGG_TYPE | ||
60 | { | ||
61 | char *name; /* type name */ | ||
62 | EGG_COMMAND *cmd; /* command list */ | ||
63 | struct EGG_TYPE *next; /* linked list pointer */ | ||
64 | } EGG_TYPE; | ||
65 | |||
66 | |||
67 | |||
68 | /* particles store their state variables in these structures */ | ||
69 | typedef struct EGG_VARIABLE | ||
70 | { | ||
71 | char *name; /* variable name */ | ||
72 | double val; /* current value */ | ||
73 | struct EGG_VARIABLE *next; /* linked list pointer */ | ||
74 | } EGG_VARIABLE; | ||
75 | |||
76 | |||
77 | |||
78 | /* a specific particle instance */ | ||
79 | typedef struct EGG_PARTICLE | ||
80 | { | ||
81 | int num; /* unique ID number */ | ||
82 | EGG_TYPE *type; /* type information */ | ||
83 | EGG_VARIABLE *var; /* list of variables */ | ||
84 | struct EGG_PARTICLE *next; /* linked list pointer */ | ||
85 | } EGG_PARTICLE; | ||
86 | |||
87 | |||
88 | |||
89 | /* everything you need to know about an EGG particle system */ | ||
90 | typedef struct EGG | ||
91 | { | ||
92 | int frame; /* animation frame number */ | ||
93 | int part_count; /* number of active particles */ | ||
94 | int part_num; /* particle ID counter */ | ||
95 | EGG_PARTICLE *part; /* list of particle instances */ | ||
96 | EGG_TYPE *type; /* list of particle types */ | ||
97 | EGG_VARIABLE *var; /* list of global variables */ | ||
98 | } EGG; | ||
99 | |||
100 | |||
101 | |||
102 | /* script loading functions */ | ||
103 | EGG *load_egg(char *filename, char *error); | ||
104 | EGG *use_egg(void *data, int length, char *error); | ||
105 | |||
106 | /* script unloading function */ | ||
107 | void destroy_egg(EGG *egg); | ||
108 | |||
109 | /* script interpreter */ | ||
110 | int update_egg(EGG *egg, char *error); | ||
111 | |||
112 | /* renders the current animation state into an Allegro bitmap */ | ||
113 | void lay_egg(EGG *egg, struct BITMAP *bmp); | ||
114 | |||
115 | /* internal utility functions */ | ||
116 | double evaluate(char *equation, int *error, double (*variable)(char *name)); | ||
117 | |||
118 | int process_egg_cmd(EGG *egg, EGG_PARTICLE *part, EGG_PARTICLE *other, EGG_COMMAND *cmd, int init, int set, char *error); | ||
119 | void destroy_egg_cmd(EGG_COMMAND *cmd); | ||
120 | |||
121 | double get_egg_variable(EGG_PARTICLE *part, EGG_PARTICLE *other, EGG *egg, char *name); | ||
122 | void set_egg_variable(EGG_PARTICLE *part, EGG_PARTICLE *other, EGG *egg, char *name, double value); | ||
123 | |||
124 | |||
125 | |||
126 | #endif /* __EGG_H__ */ | ||
127 | |||
diff --git a/parex/eval.c b/parex/eval.c new file mode 100644 index 0000000..7eb9607 --- /dev/null +++ b/parex/eval.c | |||
@@ -0,0 +1,651 @@ | |||
1 | /* | ||
2 | * EVAL.C - part of the EGG system. | ||
3 | * | ||
4 | * Helper routine for evaluating arithmetic expressions. | ||
5 | * | ||
6 | * By Shawn Hargreaves. | ||
7 | */ | ||
8 | |||
9 | |||
10 | #include <stdlib.h> | ||
11 | #include <string.h> | ||
12 | #include <stdio.h> | ||
13 | #include <ctype.h> | ||
14 | #include <math.h> | ||
15 | |||
16 | #ifndef M_PI | ||
17 | #define M_PI 3.14159265358979323846 | ||
18 | #endif | ||
19 | |||
20 | #ifndef M_E | ||
21 | #define M_E 2.7182818284590452354 | ||
22 | #endif | ||
23 | |||
24 | #include "egg.h" | ||
25 | |||
26 | |||
27 | |||
28 | /* convert radians <-> degrees */ | ||
29 | #define DEG2RAD(x) ((x)*M_PI/180.0) | ||
30 | #define RAD2DEG(x) ((x)*180.0/M_PI) | ||
31 | |||
32 | |||
33 | |||
34 | /* internal state information */ | ||
35 | static int evaluate_error; | ||
36 | |||
37 | static char operator_stack[256]; | ||
38 | static double value_stack[256]; | ||
39 | |||
40 | static int stack_depth; | ||
41 | |||
42 | static double current_val; | ||
43 | |||
44 | static int current_valid; | ||
45 | |||
46 | |||
47 | |||
48 | /* operator tokens */ | ||
49 | #define OP_OPEN_PAREN '(' | ||
50 | #define OP_CLOSE_PAREN ')' | ||
51 | #define OP_PLUS '+' | ||
52 | #define OP_MINUS '-' | ||
53 | #define OP_MUL '*' | ||
54 | #define OP_DIV '/' | ||
55 | #define OP_POWER '^' | ||
56 | #define OP_NEGATE '~' | ||
57 | #define OP_SQRT 'q' | ||
58 | #define OP_SIN 's' | ||
59 | #define OP_COS 'c' | ||
60 | #define OP_TAN 't' | ||
61 | #define OP_ASIN 'S' | ||
62 | #define OP_ACOS 'C' | ||
63 | #define OP_ATAN 'T' | ||
64 | #define OP_LOG 'l' | ||
65 | #define OP_LN 'L' | ||
66 | #define OP_CEIL 'e' | ||
67 | #define OP_FLOOR 'f' | ||
68 | #define OP_ROUND 'r' | ||
69 | #define OP_ABS 'a' | ||
70 | #define OP_MOD '%' | ||
71 | #define OP_EQUALS '=' | ||
72 | #define OP_NOT_EQUALS '#' | ||
73 | #define OP_LESS '<' | ||
74 | #define OP_GREATER '>' | ||
75 | #define OP_LESS_EQUALS '{' | ||
76 | #define OP_GREATER_EQUALS '}' | ||
77 | #define OP_OR '|' | ||
78 | #define OP_AND '&' | ||
79 | #define OP_NOT '!' | ||
80 | #define OP_TERMINATOR ' ' | ||
81 | |||
82 | |||
83 | |||
84 | /* precedence: | ||
85 | * Returns the precedence of the specified operator. | ||
86 | */ | ||
87 | static int precedence(char op) | ||
88 | { | ||
89 | switch (op) { | ||
90 | |||
91 | case OP_OPEN_PAREN: | ||
92 | case OP_CLOSE_PAREN: | ||
93 | return 1; | ||
94 | |||
95 | case OP_TERMINATOR: | ||
96 | return 2; | ||
97 | |||
98 | case OP_OR: | ||
99 | case OP_AND: | ||
100 | return 3; | ||
101 | |||
102 | case OP_EQUALS: | ||
103 | case OP_NOT_EQUALS: | ||
104 | case OP_LESS: | ||
105 | case OP_GREATER: | ||
106 | case OP_LESS_EQUALS: | ||
107 | case OP_GREATER_EQUALS: | ||
108 | return 4; | ||
109 | |||
110 | case OP_PLUS: | ||
111 | case OP_MINUS: | ||
112 | return 5; | ||
113 | |||
114 | case OP_MUL: | ||
115 | case OP_DIV: | ||
116 | case OP_MOD: | ||
117 | return 6; | ||
118 | |||
119 | case OP_POWER: | ||
120 | return 7; | ||
121 | |||
122 | case OP_NEGATE: | ||
123 | case OP_NOT: | ||
124 | case OP_SQRT: | ||
125 | case OP_SIN: | ||
126 | case OP_COS: | ||
127 | case OP_TAN: | ||
128 | case OP_ASIN: | ||
129 | case OP_ACOS: | ||
130 | case OP_ATAN: | ||
131 | case OP_LOG: | ||
132 | case OP_LN: | ||
133 | case OP_CEIL: | ||
134 | case OP_FLOOR: | ||
135 | case OP_ROUND: | ||
136 | case OP_ABS: | ||
137 | return 8; | ||
138 | |||
139 | default: | ||
140 | return -1; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | |||
145 | |||
146 | /* is_unary: | ||
147 | * Checks whether an operator is unary. | ||
148 | */ | ||
149 | static int is_unary(char op) | ||
150 | { | ||
151 | if ((op == OP_NEGATE) || (op == OP_SQRT) || (op == OP_SIN) || | ||
152 | (op == OP_COS) || (op == OP_TAN) || (op == OP_ASIN) || | ||
153 | (op == OP_ACOS) || (op == OP_ATAN) || (op == OP_LOG) || | ||
154 | (op == OP_LN) || (op == OP_CEIL) || (op == OP_FLOOR) || | ||
155 | (op == OP_ROUND) || (op == OP_ABS) || (op == OP_NOT)) | ||
156 | return TRUE; | ||
157 | |||
158 | return FALSE; | ||
159 | } | ||
160 | |||
161 | |||
162 | |||
163 | /* add_value: | ||
164 | * Processes a new numeric value from the input string. | ||
165 | */ | ||
166 | static void add_value(double val) | ||
167 | { | ||
168 | if (current_valid) { | ||
169 | evaluate_error = TRUE; | ||
170 | return; | ||
171 | } | ||
172 | |||
173 | current_val = val; | ||
174 | current_valid = TRUE; | ||
175 | } | ||
176 | |||
177 | |||
178 | |||
179 | /* add_operator: | ||
180 | * Processes a new operator from the input string. | ||
181 | */ | ||
182 | static void add_operator(char op) | ||
183 | { | ||
184 | /* bodge for unary negation */ | ||
185 | if ((op == OP_MINUS) && (!current_valid)) | ||
186 | op = OP_NEGATE; | ||
187 | |||
188 | /* check validity */ | ||
189 | if ((op == OP_PLUS) || (op == OP_MINUS) || | ||
190 | (op == OP_MUL) || (op == OP_DIV) || | ||
191 | (op == OP_POWER) || (op == OP_MOD) || | ||
192 | (op == OP_EQUALS) || (op == OP_NOT_EQUALS) || | ||
193 | (op == OP_LESS) || (op == OP_GREATER) || | ||
194 | (op == OP_LESS_EQUALS) || (op == OP_GREATER_EQUALS) || | ||
195 | (op == OP_OR) || (op == OP_AND)) { | ||
196 | |||
197 | if (!current_valid) { | ||
198 | evaluate_error = TRUE; | ||
199 | return; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | /* evaluate */ | ||
204 | if (op != OP_OPEN_PAREN) { | ||
205 | while ((stack_depth > 0) && | ||
206 | ((precedence(op) <= precedence(operator_stack[stack_depth-1]) && (!is_unary(operator_stack[stack_depth-1]))) || | ||
207 | (precedence(op) < precedence(operator_stack[stack_depth-1]) && (is_unary(operator_stack[stack_depth-1]))))) { | ||
208 | |||
209 | stack_depth--; | ||
210 | |||
211 | switch (operator_stack[stack_depth]) { | ||
212 | |||
213 | case OP_PLUS: | ||
214 | current_val = value_stack[stack_depth] + current_val; | ||
215 | break; | ||
216 | |||
217 | case OP_MINUS: | ||
218 | current_val = value_stack[stack_depth] - current_val; | ||
219 | break; | ||
220 | |||
221 | case OP_MUL: | ||
222 | current_val = value_stack[stack_depth] * current_val; | ||
223 | break; | ||
224 | |||
225 | case OP_DIV: | ||
226 | if (current_val != 0) | ||
227 | current_val = value_stack[stack_depth] / current_val; | ||
228 | else | ||
229 | current_val = 0; | ||
230 | break; | ||
231 | |||
232 | case OP_POWER: | ||
233 | current_val = pow(value_stack[stack_depth], current_val); | ||
234 | break; | ||
235 | |||
236 | case OP_NEGATE: | ||
237 | current_val = -current_val; | ||
238 | break; | ||
239 | |||
240 | case OP_SQRT: | ||
241 | if (current_val >= 0) | ||
242 | current_val = sqrt(current_val); | ||
243 | else | ||
244 | current_val = 0; | ||
245 | break; | ||
246 | |||
247 | case OP_SIN: | ||
248 | current_val = sin(DEG2RAD(current_val)); | ||
249 | break; | ||
250 | |||
251 | case OP_COS: | ||
252 | current_val = cos(DEG2RAD(current_val)); | ||
253 | break; | ||
254 | |||
255 | case OP_TAN: | ||
256 | current_val = tan(DEG2RAD(current_val)); | ||
257 | break; | ||
258 | |||
259 | case OP_ASIN: | ||
260 | if ((current_val >= -1) && (current_val <= 1)) | ||
261 | current_val = RAD2DEG(asin(current_val)); | ||
262 | else | ||
263 | current_val = 0; | ||
264 | break; | ||
265 | |||
266 | case OP_ACOS: | ||
267 | if ((current_val >= -1) && (current_val <= 1)) | ||
268 | current_val = RAD2DEG(acos(current_val)); | ||
269 | else | ||
270 | current_val = 0; | ||
271 | break; | ||
272 | |||
273 | case OP_ATAN: | ||
274 | current_val = RAD2DEG(atan(current_val)); | ||
275 | break; | ||
276 | |||
277 | case OP_LOG: | ||
278 | if (current_val > 0) | ||
279 | current_val = log10(current_val); | ||
280 | else | ||
281 | current_val = 0; | ||
282 | break; | ||
283 | |||
284 | case OP_LN: | ||
285 | if (current_val > 0) | ||
286 | current_val = log(current_val); | ||
287 | else | ||
288 | current_val = 0; | ||
289 | break; | ||
290 | |||
291 | case OP_CEIL: | ||
292 | current_val = ceil(current_val); | ||
293 | break; | ||
294 | |||
295 | case OP_FLOOR: | ||
296 | current_val = floor(current_val); | ||
297 | break; | ||
298 | |||
299 | case OP_ROUND: | ||
300 | if (current_val < 0) | ||
301 | current_val = (int)(current_val - 0.5); | ||
302 | else | ||
303 | current_val = (int)(current_val + 0.5); | ||
304 | break; | ||
305 | |||
306 | case OP_ABS: | ||
307 | current_val = fabs(current_val); | ||
308 | break; | ||
309 | |||
310 | case OP_MOD: | ||
311 | if (current_val >= 1) | ||
312 | current_val = fmod(value_stack[stack_depth], current_val); | ||
313 | else | ||
314 | current_val = 0; | ||
315 | break; | ||
316 | |||
317 | case OP_EQUALS: | ||
318 | current_val = (value_stack[stack_depth] == current_val); | ||
319 | break; | ||
320 | |||
321 | case OP_NOT_EQUALS: | ||
322 | current_val = (value_stack[stack_depth] != current_val); | ||
323 | break; | ||
324 | |||
325 | case OP_LESS: | ||
326 | current_val = (value_stack[stack_depth] < current_val); | ||
327 | break; | ||
328 | |||
329 | case OP_GREATER: | ||
330 | current_val = (value_stack[stack_depth] > current_val); | ||
331 | break; | ||
332 | |||
333 | case OP_LESS_EQUALS: | ||
334 | current_val = (value_stack[stack_depth] <= current_val); | ||
335 | break; | ||
336 | |||
337 | case OP_GREATER_EQUALS: | ||
338 | current_val = (value_stack[stack_depth] >= current_val); | ||
339 | break; | ||
340 | |||
341 | case OP_OR: | ||
342 | current_val = ((int)value_stack[stack_depth] || (int)current_val); | ||
343 | break; | ||
344 | |||
345 | case OP_AND: | ||
346 | current_val = ((int)value_stack[stack_depth] && (int)current_val); | ||
347 | break; | ||
348 | |||
349 | case OP_NOT: | ||
350 | current_val = !(int)current_val; | ||
351 | break; | ||
352 | |||
353 | case OP_OPEN_PAREN: | ||
354 | if (op == OP_CLOSE_PAREN) | ||
355 | return; | ||
356 | break; | ||
357 | } | ||
358 | } | ||
359 | } | ||
360 | |||
361 | /* push onto the stack */ | ||
362 | if (op != OP_CLOSE_PAREN) { | ||
363 | operator_stack[stack_depth] = op; | ||
364 | value_stack[stack_depth] = current_val; | ||
365 | stack_depth++; | ||
366 | current_val = 0; | ||
367 | current_valid = FALSE; | ||
368 | } | ||
369 | else { | ||
370 | if (stack_depth <= 0) | ||
371 | evaluate_error = TRUE; | ||
372 | } | ||
373 | } | ||
374 | |||
375 | |||
376 | |||
377 | /* evaluate: | ||
378 | * Top level evaluation function. | ||
379 | */ | ||
380 | double evaluate(char *equation, int *error, double (*variable)(char *name)) | ||
381 | { | ||
382 | char buf[256]; | ||
383 | double val; | ||
384 | int i; | ||
385 | |||
386 | stack_depth = 0; | ||
387 | current_val = 0; | ||
388 | current_valid = FALSE; | ||
389 | evaluate_error = FALSE; | ||
390 | |||
391 | while ((*equation) && (!evaluate_error)) { | ||
392 | /* skip whitespace */ | ||
393 | while (isspace(*equation)) | ||
394 | equation++; | ||
395 | |||
396 | switch (*equation) { | ||
397 | |||
398 | case '+': | ||
399 | /* addition */ | ||
400 | add_operator(OP_PLUS); | ||
401 | equation++; | ||
402 | break; | ||
403 | |||
404 | case '-': | ||
405 | /* subtraction */ | ||
406 | add_operator(OP_MINUS); | ||
407 | equation++; | ||
408 | break; | ||
409 | |||
410 | case '*': | ||
411 | /* multiplication */ | ||
412 | add_operator(OP_MUL); | ||
413 | equation++; | ||
414 | break; | ||
415 | |||
416 | case '/': | ||
417 | /* division */ | ||
418 | add_operator(OP_DIV); | ||
419 | equation++; | ||
420 | break; | ||
421 | |||
422 | case '^': | ||
423 | /* rasing to a power (_not_ XOR!) */ | ||
424 | add_operator(OP_POWER); | ||
425 | equation++; | ||
426 | break; | ||
427 | |||
428 | case '%': | ||
429 | /* modulus */ | ||
430 | add_operator(OP_MOD); | ||
431 | equation++; | ||
432 | break; | ||
433 | |||
434 | case '|': | ||
435 | /* logical or */ | ||
436 | add_operator(OP_OR); | ||
437 | equation++; | ||
438 | break; | ||
439 | |||
440 | case '&': | ||
441 | /* logical and */ | ||
442 | add_operator(OP_AND); | ||
443 | equation++; | ||
444 | break; | ||
445 | |||
446 | case '=': | ||
447 | /* equality test (requires dual ==) */ | ||
448 | if (equation[1] == '=') { | ||
449 | add_operator(OP_EQUALS); | ||
450 | equation += 2; | ||
451 | } | ||
452 | else | ||
453 | evaluate_error = TRUE; | ||
454 | break; | ||
455 | |||
456 | case '!': | ||
457 | /* could be inequality test or logical not */ | ||
458 | if (equation[1] == '=') { | ||
459 | add_operator(OP_NOT_EQUALS); | ||
460 | equation += 2; | ||
461 | } | ||
462 | else { | ||
463 | add_operator(OP_NOT); | ||
464 | equation++; | ||
465 | } | ||
466 | break; | ||
467 | |||
468 | case '<': | ||
469 | /* could be less than or less/equal test */ | ||
470 | if (equation[1] == '=') { | ||
471 | add_operator(OP_LESS_EQUALS); | ||
472 | equation += 2; | ||
473 | } | ||
474 | else { | ||
475 | add_operator(OP_LESS); | ||
476 | equation++; | ||
477 | } | ||
478 | break; | ||
479 | |||
480 | case '>': | ||
481 | /* could be greater than or greater/equal test */ | ||
482 | if (equation[1] == '=') { | ||
483 | add_operator(OP_GREATER_EQUALS); | ||
484 | equation += 2; | ||
485 | } | ||
486 | else { | ||
487 | add_operator(OP_GREATER); | ||
488 | equation++; | ||
489 | } | ||
490 | break; | ||
491 | |||
492 | case '(': | ||
493 | /* open bracket */ | ||
494 | add_operator(OP_OPEN_PAREN); | ||
495 | equation++; | ||
496 | break; | ||
497 | |||
498 | case ')': | ||
499 | /* close bracket */ | ||
500 | add_operator(OP_CLOSE_PAREN); | ||
501 | equation++; | ||
502 | break; | ||
503 | |||
504 | case '0': | ||
505 | /* special case for hex constants (0x prefix) */ | ||
506 | if (equation[1] == 'x') { | ||
507 | equation += 2; | ||
508 | |||
509 | for (i=0; isxdigit(equation[i]); i++) | ||
510 | buf[i] = equation[i]; | ||
511 | |||
512 | buf[i] = 0; | ||
513 | equation += i; | ||
514 | |||
515 | val = strtol(buf, NULL, 16); | ||
516 | add_value(val); | ||
517 | break; | ||
518 | } | ||
519 | /* else fall through */ | ||
520 | |||
521 | case '1': | ||
522 | case '2': | ||
523 | case '3': | ||
524 | case '4': | ||
525 | case '5': | ||
526 | case '6': | ||
527 | case '7': | ||
528 | case '8': | ||
529 | case '9': | ||
530 | /* floating point constant */ | ||
531 | for (i=0; isdigit(equation[i]) || (equation[i] == '.'); i++) | ||
532 | buf[i] = equation[i]; | ||
533 | |||
534 | buf[i] = 0; | ||
535 | equation += i; | ||
536 | |||
537 | val = atof(buf); | ||
538 | add_value(val); | ||
539 | break; | ||
540 | |||
541 | default: | ||
542 | /* this is a string, could be a variable or function */ | ||
543 | for (i=0; (isalpha(equation[i])) || (equation[i] == '_'); i++) | ||
544 | buf[i] = tolower(equation[i]); | ||
545 | |||
546 | buf[i] = 0; | ||
547 | equation += i; | ||
548 | |||
549 | if (strcmp(buf, "pi") == 0) { | ||
550 | /* pi (built in constant) */ | ||
551 | add_value(M_PI); | ||
552 | } | ||
553 | else if (strcmp(buf, "e") == 0) { | ||
554 | /* e (built in constant) */ | ||
555 | add_value(M_E); | ||
556 | } | ||
557 | else if (strcmp(buf, "sqrt") == 0) { | ||
558 | /* square root function */ | ||
559 | add_operator(OP_SQRT); | ||
560 | } | ||
561 | else if (strcmp(buf, "sin") == 0) { | ||
562 | /* sin function */ | ||
563 | add_operator(OP_SIN); | ||
564 | } | ||
565 | else if (strcmp(buf, "cos") == 0) { | ||
566 | /* cos function */ | ||
567 | add_operator(OP_COS); | ||
568 | } | ||
569 | else if (strcmp(buf, "tan") == 0) { | ||
570 | /* tan function */ | ||
571 | add_operator(OP_TAN); | ||
572 | } | ||
573 | else if (strcmp(buf, "asin") == 0) { | ||
574 | /* inverse sin function */ | ||
575 | add_operator(OP_ASIN); | ||
576 | } | ||
577 | else if (strcmp(buf, "acos") == 0) { | ||
578 | /* inverse cos function */ | ||
579 | add_operator(OP_ACOS); | ||
580 | } | ||
581 | else if (strcmp(buf, "atan") == 0) { | ||
582 | /* inverse tan function */ | ||
583 | add_operator(OP_ATAN); | ||
584 | } | ||
585 | else if (strcmp(buf, "log") == 0) { | ||
586 | /* base 10 logarithm function */ | ||
587 | add_operator(OP_LOG); | ||
588 | } | ||
589 | else if (strcmp(buf, "ln") == 0) { | ||
590 | /* natural logarithm function */ | ||
591 | add_operator(OP_LN); | ||
592 | } | ||
593 | else if (strcmp(buf, "ceil") == 0) { | ||
594 | /* round upwards function */ | ||
595 | add_operator(OP_CEIL); | ||
596 | } | ||
597 | else if (strcmp(buf, "floor") == 0) { | ||
598 | /* round downwards function */ | ||
599 | add_operator(OP_FLOOR); | ||
600 | } | ||
601 | else if (strcmp(buf, "round") == 0) { | ||
602 | /* round to nearest integer function */ | ||
603 | add_operator(OP_ROUND); | ||
604 | } | ||
605 | else if (strcmp(buf, "abs") == 0) { | ||
606 | /* absolute value function */ | ||
607 | add_operator(OP_ABS); | ||
608 | } | ||
609 | else if (strcmp(buf, "rand") == 0) { | ||
610 | /* random number between 0 and 1 */ | ||
611 | add_value((rand()&32767)/32767.0); | ||
612 | } | ||
613 | else { | ||
614 | /* user-supplied callback for looking up variables */ | ||
615 | if ((buf[0]) && (variable)) { | ||
616 | add_value(variable(buf)); | ||
617 | } | ||
618 | else { | ||
619 | if (error) | ||
620 | *error = TRUE; | ||
621 | |||
622 | return 0; | ||
623 | } | ||
624 | } | ||
625 | break; | ||
626 | } | ||
627 | } | ||
628 | |||
629 | if ((evaluate_error) || (!current_valid)) { | ||
630 | if (error) | ||
631 | *error = TRUE; | ||
632 | |||
633 | return 0; | ||
634 | } | ||
635 | |||
636 | /* force a stack flush */ | ||
637 | add_operator(OP_TERMINATOR); | ||
638 | |||
639 | if (stack_depth != 1) { | ||
640 | if (error) | ||
641 | *error = TRUE; | ||
642 | |||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | if (error) | ||
647 | *error = FALSE; | ||
648 | |||
649 | return value_stack[0]; | ||
650 | } | ||
651 | |||
diff --git a/parex/evaltest.c b/parex/evaltest.c new file mode 100644 index 0000000..7e8641e --- /dev/null +++ b/parex/evaltest.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * EVALTEST.C - part of the EGG system. | ||
3 | * | ||
4 | * Test program for the expression evaluator. | ||
5 | * | ||
6 | * By Shawn Hargreaves. | ||
7 | */ | ||
8 | |||
9 | |||
10 | #define USE_CONSOLE | ||
11 | |||
12 | |||
13 | #include <stdlib.h> | ||
14 | #include <stdio.h> | ||
15 | #include <time.h> | ||
16 | |||
17 | #include "egg.h" | ||
18 | |||
19 | |||
20 | |||
21 | int main() | ||
22 | { | ||
23 | char buf[256]; | ||
24 | double result; | ||
25 | int error; | ||
26 | |||
27 | srand(time(NULL)); | ||
28 | |||
29 | printf("\nTest program for the EGG expression evaluator module.\n\nEnter a formula, or a blank line to quit.\n\n\n"); | ||
30 | |||
31 | for (;;) { | ||
32 | printf("> "); | ||
33 | fflush(stdout); | ||
34 | |||
35 | if (!fgets(buf, sizeof(buf), stdin) || (!buf[0])) | ||
36 | break; | ||
37 | |||
38 | result = evaluate(buf, &error, NULL); | ||
39 | |||
40 | if (error) | ||
41 | printf("\nError in expression!\n\n\n"); | ||
42 | else | ||
43 | printf("\nevaluate(\"%s\") = %f\n\n\n", buf, result); | ||
44 | } | ||
45 | |||
46 | printf("\n\n"); | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||