Mercurial > hg > dmlib
comparison dmeval.c @ 0:32250b436bca
Initial re-import.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 28 Sep 2012 01:54:23 +0300 |
parents | |
children | 05eb24a608f0 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:32250b436bca |
---|---|
1 #include "dmeval.h" | |
2 #include <stdio.h> | |
3 #include <math.h> | |
4 | |
5 #define DM_MAX_ID_LEN 16 | |
6 #define DM_MAX_BUF 512 | |
7 #define DM_STACK_SIZE 512 | |
8 | |
9 static DMValue int_clip(DMValue v) | |
10 { | |
11 return (v < -1.0f) ? -1.0f : ((v > 1.0f) ? 1.0f : v); | |
12 } | |
13 | |
14 | |
15 /* Some basic functions | |
16 */ | |
17 static const DMEvalId dm_eval_basic[] = | |
18 { | |
19 { "sin", ID_FUNC, sin, NULL }, | |
20 { "cos", ID_FUNC, cos, NULL }, | |
21 { "clip", ID_FUNC, int_clip, NULL }, | |
22 }; | |
23 | |
24 static const int ndm_eval_basic = sizeof(dm_eval_basic) / sizeof(dm_eval_basic[0]); | |
25 | |
26 | |
27 void dm_eval_err_v(DMEvalContext *ev, const char *fmt, va_list ap) | |
28 { | |
29 #if 1 | |
30 char *tmp = dm_strdup_vprintf(fmt, ap); | |
31 | |
32 ev->err = TRUE; | |
33 | |
34 if (ev->errStr != NULL) | |
35 { | |
36 ev->errStr = dm_strdup_printf("%s%s", ev->errStr, tmp); | |
37 dmFree(tmp); | |
38 } | |
39 else | |
40 ev->errStr = tmp; | |
41 #else | |
42 vfprintf(stdout, fmt, ap); | |
43 #endif | |
44 } | |
45 | |
46 | |
47 void dm_eval_err(DMEvalContext *ev, const char *fmt, ...) | |
48 { | |
49 va_list ap; | |
50 va_start(ap, fmt); | |
51 dm_eval_err_v(ev, fmt, ap); | |
52 va_end(ap); | |
53 } | |
54 | |
55 | |
56 DMEvalId *dm_eval_find_id(DMEvalContext *ev, const char *name) | |
57 { | |
58 int i; | |
59 if (ev->ids == NULL) | |
60 return NULL; | |
61 | |
62 for (i = 0; i < ev->nids; i++) | |
63 if (strcmp(ev->ids[i].name, name) == 0) | |
64 return &(ev->ids[i]); | |
65 | |
66 return NULL; | |
67 } | |
68 | |
69 | |
70 static DMEvalId *dm_eval_add_id(DMEvalContext *ev, const char *name, const int type) | |
71 { | |
72 DMEvalId *id = dm_eval_find_id(ev, name); | |
73 if (id != NULL) | |
74 return NULL; | |
75 | |
76 ev->ids = dmRealloc(ev->ids, sizeof(DMEvalId) * (ev->nids + 1)); | |
77 if (ev->ids == NULL) | |
78 { | |
79 dm_eval_err(ev, "Could not reallocate eval ids array (#%d). Fatal error.\n", ev->nids + 1); | |
80 return NULL; | |
81 } | |
82 | |
83 id = &(ev->ids[ev->nids]); | |
84 ev->nids++; | |
85 | |
86 id->name = dm_strdup(name); | |
87 id->type = type; | |
88 id->func = NULL; | |
89 id->var = NULL; | |
90 | |
91 return id; | |
92 } | |
93 | |
94 | |
95 DMEvalId *dm_eval_add_var(DMEvalContext *ev, const char *name, DMValue *var) | |
96 { | |
97 DMEvalId *id = dm_eval_add_id(ev, name, ID_VAR); | |
98 if (id == NULL) | |
99 return NULL; | |
100 | |
101 id->var = var; | |
102 return id; | |
103 } | |
104 | |
105 | |
106 DMEvalId *dm_eval_add_func(DMEvalContext *ev, const char *name, DMValue (*func)(DMValue)) | |
107 { | |
108 DMEvalId *id = dm_eval_add_id(ev, name, ID_VAR); | |
109 if (id == NULL) | |
110 return NULL; | |
111 | |
112 id->func = func; | |
113 return id; | |
114 } | |
115 | |
116 | |
117 | |
118 DMEvalContext *dm_eval_new(void) | |
119 { | |
120 int i; | |
121 DMEvalContext *ev = dmCalloc(1, sizeof(DMEvalContext)); | |
122 | |
123 if (ev == NULL) | |
124 return NULL; | |
125 | |
126 for (i = 0; i < ndm_eval_basic; i++) | |
127 { | |
128 const DMEvalId *id = &dm_eval_basic[i]; | |
129 DMEvalId *nid = dm_eval_add_id(ev, id->name, id->type); | |
130 nid->func = id->func; | |
131 } | |
132 | |
133 return ev; | |
134 } | |
135 | |
136 void dm_eval_free(DMEvalNode *node) | |
137 { | |
138 while (node != NULL) | |
139 { | |
140 DMEvalNode *next = node->next; | |
141 | |
142 if (node->subexpr != NULL) | |
143 dm_eval_free(node->subexpr); | |
144 | |
145 dmFree(node); | |
146 node = next; | |
147 } | |
148 } | |
149 | |
150 | |
151 void dm_eval_clear_err(DMEvalContext *ev) | |
152 { | |
153 if (ev == NULL) | |
154 return; | |
155 | |
156 dmFree(ev->errStr); | |
157 ev->err = FALSE; | |
158 ev->errStr = NULL; | |
159 } | |
160 | |
161 | |
162 void dm_eval_close(DMEvalContext *ev) | |
163 { | |
164 int i; | |
165 | |
166 if (ev == NULL) | |
167 return; | |
168 | |
169 for (i = 0; i < ev->nids; i++) | |
170 dmFree(ev->ids[i].name); | |
171 | |
172 dmFree(ev->ids); | |
173 dm_eval_clear_err(ev); | |
174 dmFree(ev); | |
175 } | |
176 | |
177 | |
178 static DMEvalNode *dm_eval_pop_node(DMEvalNode **list) | |
179 { | |
180 DMEvalNode *node; | |
181 | |
182 if (*list == NULL) | |
183 return NULL; | |
184 | |
185 node = (*list)->prev; | |
186 | |
187 if (*list != node) | |
188 { | |
189 node->prev->next = NULL; | |
190 (*list)->prev = node->prev; | |
191 } | |
192 else | |
193 *list = NULL; | |
194 | |
195 return node; | |
196 } | |
197 | |
198 | |
199 static DMEvalNode *dm_eval_insert_node(DMEvalNode **list, DMEvalNode *node) | |
200 { | |
201 if (*list != NULL) | |
202 { | |
203 node->prev = (*list)->prev; | |
204 (*list)->prev->next = node; | |
205 (*list)->prev = node; | |
206 } | |
207 else | |
208 { | |
209 *list = node; | |
210 node->prev = *list; | |
211 } | |
212 | |
213 node->next = NULL; | |
214 return node; | |
215 } | |
216 | |
217 | |
218 static DMEvalNode *dm_eval_push_node(DMEvalNode **list, DMEvalNode *src) | |
219 { | |
220 DMEvalNode *node = dmCalloc(1, sizeof(DMEvalNode)); | |
221 if (node == NULL) | |
222 return NULL; | |
223 | |
224 node->op = src->op; | |
225 node->val = src->val; | |
226 node->id = src->id; | |
227 node->subexpr = src->subexpr; | |
228 | |
229 return dm_eval_insert_node(list, node); | |
230 } | |
231 | |
232 | |
233 static DMEvalNode *dm_eval_add_node(DMEvalNode **list, const int op) | |
234 { | |
235 DMEvalNode *node = dmCalloc(1, sizeof(DMEvalNode)); | |
236 if (node == NULL) | |
237 return NULL; | |
238 | |
239 node->op = op; | |
240 | |
241 return dm_eval_insert_node(list, node); | |
242 } | |
243 | |
244 | |
245 enum | |
246 { | |
247 PARSE_NONE = 0x0000, | |
248 PARSE_START = 0x1000, | |
249 PARSE_END = 0x2000, | |
250 PARSE_ERROR = 0x8000, | |
251 | |
252 PARSE_IDENT = 0x0001, | |
253 PARSE_WS = 0x0002, | |
254 PARSE_CONST = 0x0004, | |
255 PARSE_OPER = 0x0008, | |
256 PARSE_SUBEXPR = 0x0010, | |
257 }; | |
258 | |
259 #define DM_CHECK(x) { if (mode & PARSE_ ## x ) { if (str[0]) strcat(str, " or "); strcat(str, # x ); } } | |
260 | |
261 static char *dm_get_mode(int mode) | |
262 { | |
263 char str[128] = ""; | |
264 | |
265 | |
266 DM_CHECK(START); | |
267 DM_CHECK(END); | |
268 DM_CHECK(IDENT); | |
269 DM_CHECK(WS); | |
270 DM_CHECK(CONST); | |
271 DM_CHECK(OPER); | |
272 DM_CHECK(SUBEXPR); | |
273 | |
274 return dm_strdup(str); | |
275 } | |
276 | |
277 | |
278 static void dm_set_mode(DMEvalContext *ev, const int mode) | |
279 { | |
280 if (mode != PARSE_ERROR && mode != PARSE_START && | |
281 ev->expect != PARSE_NONE && | |
282 (mode & ev->expect) == 0) | |
283 { | |
284 char *tmp1 = dm_get_mode(ev->expect), | |
285 *tmp2 = dm_get_mode(mode); | |
286 | |
287 dm_eval_err(ev, "Expected [%s], got %s.\n", tmp1, tmp2); | |
288 dmFree(tmp1); | |
289 dmFree(tmp2); | |
290 } | |
291 | |
292 ev->prev = ev->mode; | |
293 ev->mode = mode; | |
294 } | |
295 | |
296 | |
297 static int dm_eval_parse_expr_do(DMEvalContext *ev, DMEvalNode **list, char **str, int depth) | |
298 { | |
299 char *c = *str; | |
300 char tmpStr[DM_MAX_BUF + 2]; | |
301 int tmpStrLen = 0; | |
302 DMEvalNode *node = NULL, *func = NULL; | |
303 BOOL first = FALSE, decimal = FALSE; | |
304 | |
305 ev->expect = PARSE_CONST | PARSE_IDENT | PARSE_SUBEXPR; | |
306 ev->mode = PARSE_START; | |
307 | |
308 while (ev->mode != PARSE_ERROR && ev->mode != PARSE_END) | |
309 { | |
310 switch (ev->mode) | |
311 { | |
312 case PARSE_WS: | |
313 // Skip whitespace | |
314 if (isspace(*c)) | |
315 c++; | |
316 else | |
317 dm_set_mode(ev, PARSE_START); | |
318 break; | |
319 | |
320 case PARSE_SUBEXPR: | |
321 { | |
322 char *tmp = c + 1; | |
323 | |
324 ev->expect = PARSE_SUBEXPR | PARSE_IDENT | PARSE_CONST; | |
325 | |
326 if (func != NULL) | |
327 { | |
328 if (dm_eval_parse_expr_do(ev, &(func->subexpr), &tmp, depth + 1) != 0) | |
329 { | |
330 dm_eval_err(ev, "Function argument subexpression starting at '%s' contained errors.\n", c); | |
331 dm_set_mode(ev, PARSE_ERROR); | |
332 } | |
333 | |
334 func = NULL; | |
335 } | |
336 else | |
337 { | |
338 if ((node = dm_eval_add_node(list, OP_SUBEXPR)) == NULL) | |
339 dm_set_mode(ev, PARSE_ERROR); | |
340 else | |
341 if (dm_eval_parse_expr_do(ev, &(node->subexpr), &tmp, depth + 1) != 0) | |
342 { | |
343 dm_eval_err(ev, "Subexpression starting at '%s' contained errors.\n", c); | |
344 dm_set_mode(ev, PARSE_ERROR); | |
345 } | |
346 } | |
347 if (ev->mode != PARSE_ERROR) | |
348 { | |
349 dm_set_mode(ev, PARSE_START); | |
350 ev->expect = PARSE_OPER | PARSE_END; | |
351 c = tmp; | |
352 } | |
353 } | |
354 break; | |
355 | |
356 case PARSE_START: | |
357 // Start | |
358 if (*c == 0) | |
359 dm_set_mode(ev, PARSE_END); | |
360 | |
361 else if (isspace(*c)) | |
362 { | |
363 ev->mode = PARSE_WS; | |
364 } | |
365 | |
366 else if (*c == ')') | |
367 { | |
368 if (depth > 0) | |
369 dm_set_mode(ev, PARSE_END); | |
370 else | |
371 { | |
372 dm_eval_err(ev, "Invalid nesting near '%s' (depth %d).\n", c, depth); | |
373 dm_set_mode(ev, PARSE_ERROR); | |
374 } | |
375 c++; | |
376 } | |
377 | |
378 else if (*c == '(') | |
379 dm_set_mode(ev, PARSE_SUBEXPR); | |
380 | |
381 else if (strchr("+-*/<>%&|!^", *c)) | |
382 dm_set_mode(ev, PARSE_OPER); | |
383 | |
384 else if (isdigit(*c) || *c == '.') | |
385 dm_set_mode(ev, PARSE_CONST); | |
386 | |
387 else if (isalpha(*c) || *c == '_') | |
388 dm_set_mode(ev, PARSE_IDENT); | |
389 | |
390 else | |
391 { | |
392 dm_eval_err(ev, "Syntax error near '%s' (depth %d).\n", c, depth); | |
393 dm_set_mode(ev, PARSE_ERROR); | |
394 } | |
395 | |
396 first = TRUE; | |
397 break; | |
398 | |
399 case PARSE_CONST: | |
400 if (first) | |
401 { | |
402 first = FALSE; | |
403 decimal = FALSE; | |
404 tmpStrLen = 0; | |
405 | |
406 if (isdigit(*c) || *c == '-' || *c == '+' || *c == '.') | |
407 { | |
408 if (*c == '.') | |
409 decimal = TRUE; | |
410 tmpStr[tmpStrLen++] = *c++; | |
411 } | |
412 else | |
413 { | |
414 dm_eval_err(ev, "Invalid constant expression near '%s'.\n", c); | |
415 dm_set_mode(ev, PARSE_ERROR); | |
416 } | |
417 } | |
418 else | |
419 { | |
420 if (isdigit(*c) || (*c == '.' && !decimal)) | |
421 { | |
422 if (*c == '.') | |
423 decimal = TRUE; | |
424 tmpStr[tmpStrLen++] = *c++; | |
425 } | |
426 else | |
427 { | |
428 tmpStr[tmpStrLen] = 0; | |
429 | |
430 if ((node = dm_eval_add_node(list, OP_CONST)) == NULL) | |
431 { | |
432 dm_set_mode(ev, PARSE_ERROR); | |
433 break; | |
434 } | |
435 | |
436 node->val = atof(tmpStr); | |
437 dm_set_mode(ev, PARSE_START); | |
438 ev->expect = PARSE_OPER | PARSE_END; | |
439 } | |
440 } | |
441 break; | |
442 | |
443 case PARSE_OPER: | |
444 { | |
445 int op = OP_NONE; | |
446 | |
447 switch (*c) | |
448 { | |
449 case '+': op = OP_ADD; c++; break; | |
450 case '-': op = OP_SUB; c++; break; | |
451 case '*': op = OP_MUL; c++; break; | |
452 case '/': op = OP_DIV; c++; break; | |
453 case '%': op = OP_MOD; c++; break; | |
454 case '&': op = OP_AND; c++; break; | |
455 case '|': op = OP_OR; c++; break; | |
456 case '>': | |
457 if (c[1] == '>') | |
458 { | |
459 c += 2; | |
460 op = OP_RSHIFT; | |
461 } | |
462 else | |
463 { | |
464 dm_eval_err(ev, "Syntax error near '%s'.\n", c); | |
465 dm_set_mode(ev, PARSE_ERROR); | |
466 } | |
467 break; | |
468 | |
469 case '<': | |
470 if (c[1] == '<') | |
471 { | |
472 c += 2; | |
473 op = OP_LSHIFT; | |
474 } | |
475 else | |
476 { | |
477 dm_eval_err(ev, "Syntax error near '%s'.\n", c); | |
478 dm_set_mode(ev, PARSE_ERROR); | |
479 } | |
480 break; | |
481 | |
482 default: | |
483 dm_eval_err(ev, "Unknown operator '%c'.\n", *c); | |
484 dm_set_mode(ev, PARSE_ERROR); | |
485 } | |
486 | |
487 if (op != OP_NONE) | |
488 { | |
489 if ((node = dm_eval_add_node(list, op)) != NULL) | |
490 { | |
491 ev->expect = PARSE_IDENT | PARSE_CONST | PARSE_SUBEXPR; | |
492 dm_set_mode(ev, PARSE_START); | |
493 } | |
494 else | |
495 dm_set_mode(ev, PARSE_ERROR); | |
496 } | |
497 } | |
498 break; | |
499 | |
500 case PARSE_IDENT: | |
501 if (isalnum(*c) || *c == '_') | |
502 { | |
503 if (first) | |
504 { | |
505 tmpStrLen = 0; | |
506 first = FALSE; | |
507 } | |
508 | |
509 if (tmpStrLen < DM_MAX_ID_LEN) | |
510 tmpStr[tmpStrLen++] = *c++; | |
511 else | |
512 { | |
513 tmpStr[tmpStrLen] = 0; | |
514 dm_eval_err(ev, "Identifier too long! ('%s')\n", tmpStr); | |
515 } | |
516 } | |
517 else | |
518 { | |
519 tmpStr[tmpStrLen] = 0; | |
520 DMEvalId *id = dm_eval_find_id(ev, tmpStr); | |
521 if (id != NULL) | |
522 { | |
523 if ((node = dm_eval_add_node(list, id->type == ID_FUNC ? OP_FUNC : OP_VAR)) != NULL) | |
524 { | |
525 node->id = id; | |
526 if (id->type == ID_FUNC) | |
527 { | |
528 func = node; | |
529 ev->expect = PARSE_SUBEXPR; | |
530 } | |
531 else | |
532 ev->expect = PARSE_END | PARSE_OPER; | |
533 | |
534 dm_set_mode(ev, PARSE_START); | |
535 } | |
536 else | |
537 dm_set_mode(ev, PARSE_ERROR); | |
538 } | |
539 else | |
540 { | |
541 dm_eval_err(ev, "No such identifier '%s'.\n", tmpStr); | |
542 dm_set_mode(ev, PARSE_ERROR); | |
543 } | |
544 } | |
545 break; | |
546 } | |
547 } | |
548 | |
549 *str = c; | |
550 | |
551 return (ev->mode == PARSE_ERROR) ? -1 : 0; | |
552 } | |
553 | |
554 | |
555 int dm_eval_parse_expr(DMEvalContext *ev, char *expr, DMEvalNode **result) | |
556 { | |
557 int ret; | |
558 | |
559 if (ev == NULL || result == NULL) | |
560 return -1; | |
561 | |
562 ret = dm_eval_parse_expr_do(ev, result, &expr, 0); | |
563 | |
564 return ret; | |
565 } | |
566 | |
567 | |
568 static const char *dm_oper_names[OP_NOPERS] = | |
569 { | |
570 "NONE", | |
571 "+", | |
572 "-", | |
573 "*", | |
574 "/", | |
575 "%", | |
576 | |
577 "<<", | |
578 ">>", | |
579 | |
580 "&", | |
581 "|", | |
582 "^", | |
583 | |
584 "FUNC", | |
585 "VAR", | |
586 "SUBEXPR", | |
587 "CONST" | |
588 }; | |
589 | |
590 | |
591 static void dm_print_optree_do(DMEvalContext *ev, DMEvalNode *node, const int level) | |
592 { | |
593 while (node != NULL) | |
594 { | |
595 switch (node->op) | |
596 { | |
597 case OP_FUNC: | |
598 printf("%s(", node->id != NULL ? node->id->name : "?ERROR"); | |
599 dm_print_optree_do(ev, node->subexpr, level + 1); | |
600 printf(")"); | |
601 break; | |
602 | |
603 case OP_VAR: | |
604 printf("%s", node->id != NULL ? node->id->name : "?ERROR"); | |
605 break; | |
606 | |
607 case OP_CONST: | |
608 printf("%.1f", node->val); | |
609 break; | |
610 | |
611 case OP_SUBEXPR: | |
612 printf("("); | |
613 if (node->subexpr != NULL) | |
614 dm_print_optree_do(ev, node->subexpr, level + 1); | |
615 else | |
616 printf("?ERROR"); | |
617 printf(")"); | |
618 break; | |
619 | |
620 default: | |
621 if (node->op > 0 && node->op < OP_NOPERS) | |
622 printf("%s", dm_oper_names[node->op]); | |
623 else | |
624 printf("ERROR!"); | |
625 break; | |
626 } | |
627 node = node->next; | |
628 } | |
629 } | |
630 | |
631 | |
632 void dm_print_optree(DMEvalContext *ev, DMEvalNode *node) | |
633 { | |
634 dm_print_optree_do(ev, node, 0); | |
635 printf("\n"); | |
636 } | |
637 | |
638 | |
639 /* | |
640 operator precedence: | |
641 HIGHEST | |
642 "()" | |
643 | |
644 "*" | |
645 "/" | |
646 "%" | |
647 | |
648 "+" | |
649 "-" | |
650 | |
651 "<<" | |
652 ">>" | |
653 | |
654 "&" | |
655 "^" | |
656 "|" | |
657 LOWEST | |
658 */ | |
659 | |
660 int dm_eval_reorder(DMEvalContext *ev, DMEvalNode *node, DMEvalNode **result) | |
661 { | |
662 DMEvalNode *list = NULL; | |
663 | |
664 while (node != NULL) | |
665 { | |
666 DMEvalNode *tmp; | |
667 | |
668 switch (node->op) | |
669 { | |
670 case OP_SUBEXPR: | |
671 case OP_FUNC: | |
672 if ((tmp = dm_eval_push_node(&list, node)) == NULL) | |
673 return -1; | |
674 | |
675 if (dm_eval_reorder(ev, node->subexpr, &(tmp->subexpr)) != 0) | |
676 return -2; | |
677 break; | |
678 | |
679 case OP_MUL: | |
680 case OP_DIV: | |
681 case OP_MOD: | |
682 if ((tmp = dm_eval_pop_node(&list)) != NULL) | |
683 { | |
684 DMEvalNode *sub; | |
685 | |
686 if ((sub = dm_eval_add_node(&list, OP_SUBEXPR)) == NULL) | |
687 return -3; | |
688 | |
689 dm_eval_push_node(&(sub->subexpr), tmp); | |
690 dm_eval_add_node(&(sub->subexpr), node->op); | |
691 node = node->next; | |
692 if (node != NULL) | |
693 { | |
694 if (node->op == OP_FUNC || node->op == OP_SUBEXPR) | |
695 { | |
696 if ((tmp = dm_eval_push_node(&(sub->subexpr), node)) == NULL) | |
697 return -178; | |
698 | |
699 if (dm_eval_reorder(ev, node->subexpr, &(tmp->subexpr)) != 0) | |
700 return -66; | |
701 } | |
702 else | |
703 dm_eval_push_node(&(sub->subexpr), node); | |
704 } | |
705 else | |
706 return -72; | |
707 } | |
708 else | |
709 return -24; | |
710 break; | |
711 | |
712 case OP_LSHIFT: | |
713 case OP_RSHIFT: | |
714 | |
715 case OP_ADD: | |
716 case OP_SUB: | |
717 | |
718 case OP_AND: | |
719 case OP_XOR: | |
720 case OP_OR: | |
721 | |
722 case OP_VAR: | |
723 case OP_CONST: | |
724 if (dm_eval_push_node(&list, node) == NULL) | |
725 return -32; | |
726 break; | |
727 | |
728 default: | |
729 dm_eval_err(ev, "Invalid opcode %d in node %p.\n", node->op, node); | |
730 return -4; | |
731 } | |
732 | |
733 node = node->next; | |
734 } | |
735 | |
736 *result = list; | |
737 return 0; | |
738 } | |
739 | |
740 | |
741 static int dm_eval_get(DMEvalContext *ev, DMEvalNode *node, DMValue *result) | |
742 { | |
743 DMValue tmp; | |
744 | |
745 if (node == NULL) | |
746 return -32; | |
747 | |
748 switch (node->op) | |
749 { | |
750 case OP_VAR: | |
751 *result = *(node->id->var); | |
752 break; | |
753 | |
754 case OP_CONST: | |
755 *result = node->val; | |
756 break; | |
757 | |
758 case OP_SUBEXPR: | |
759 if (dm_eval_exec(ev, node->subexpr, result) != 0) | |
760 return -1; | |
761 break; | |
762 | |
763 case OP_FUNC: | |
764 if (dm_eval_exec(ev, node->subexpr, &tmp) != 0) | |
765 return -1; | |
766 | |
767 *result = node->id->func(tmp); | |
768 break; | |
769 | |
770 default: | |
771 return -16; | |
772 } | |
773 | |
774 return 0; | |
775 } | |
776 | |
777 | |
778 int dm_eval_exec(DMEvalContext *ev, DMEvalNode *tree, DMValue *presult) | |
779 { | |
780 DMValue result; | |
781 DMEvalNode *node = tree; | |
782 | |
783 while (node != NULL) | |
784 { | |
785 DMValue tmp; | |
786 | |
787 switch (node->op) | |
788 { | |
789 case OP_LSHIFT: | |
790 case OP_RSHIFT: | |
791 | |
792 case OP_AND: | |
793 case OP_XOR: | |
794 case OP_OR: | |
795 | |
796 case OP_MUL: | |
797 case OP_DIV: | |
798 case OP_MOD: | |
799 if (dm_eval_get(ev, node->next, &tmp) != 0) | |
800 return -6; | |
801 | |
802 switch (node->op) | |
803 { | |
804 case OP_DIV: | |
805 if (tmp == 0) | |
806 { | |
807 dm_eval_err(ev, "Division by zero.\n"); | |
808 return -1; | |
809 } | |
810 result /= tmp; | |
811 break; | |
812 | |
813 case OP_MUL: result *= tmp; break; | |
814 | |
815 case OP_MOD: | |
816 if (tmp == 0) | |
817 { | |
818 dm_eval_err(ev, "Division by zero.\n"); | |
819 return -1; | |
820 } | |
821 result = DMCONVTYPE result % DMCONVTYPE tmp; | |
822 break; | |
823 | |
824 case OP_LSHIFT: result = DMCONVTYPE result << DMCONVTYPE tmp; break; | |
825 case OP_RSHIFT: result = DMCONVTYPE result >> DMCONVTYPE tmp; break; | |
826 | |
827 case OP_AND: result = DMCONVTYPE result & DMCONVTYPE tmp; break; | |
828 case OP_OR: result = DMCONVTYPE result | DMCONVTYPE tmp; break; | |
829 case OP_XOR: result = DMCONVTYPE result ^ DMCONVTYPE tmp; break; | |
830 } | |
831 | |
832 node = node->next; | |
833 break; | |
834 | |
835 case OP_ADD: | |
836 case OP_SUB: | |
837 if (dm_eval_get(ev, node->next, &tmp) != 0) | |
838 return -6; | |
839 | |
840 switch (node->op) | |
841 { | |
842 case OP_ADD: result += tmp; break; | |
843 case OP_SUB: result -= tmp; break; | |
844 } | |
845 | |
846 node = node->next; | |
847 break; | |
848 | |
849 default: | |
850 if (dm_eval_get(ev, node, &result) != 0) | |
851 { | |
852 dm_eval_err(ev, "Invalid opcode %d in node %p.\n", node->op, node); | |
853 return -4; | |
854 } | |
855 } | |
856 | |
857 node = node->next; | |
858 } | |
859 | |
860 *presult = result; | |
861 return 0; | |
862 } |