Mercurial > hg-old > index.cgi
comparison old-trunk/lwasm/old/expr.c @ 339:eb230fa7d28e
Prepare for migration to hg
author | lost |
---|---|
date | Fri, 19 Mar 2010 02:54:14 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
338:e7885b3ee266 | 339:eb230fa7d28e |
---|---|
1 /* | |
2 expr.c | |
3 Copyright © 2008 William Astle | |
4 | |
5 This file is part of LWASM. | |
6 | |
7 LWASM is free software: you can redistribute it and/or modify it under the | |
8 terms of the GNU General Public License as published by the Free Software | |
9 Foundation, either version 3 of the License, or (at your option) any later | |
10 version. | |
11 | |
12 This program is distributed in the hope that it will be useful, but WITHOUT | |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
15 more details. | |
16 | |
17 You should have received a copy of the GNU General Public License along with | |
18 this program. If not, see <http://www.gnu.org/licenses/>. | |
19 */ | |
20 | |
21 /* | |
22 This file contains the actual expression evaluator | |
23 */ | |
24 | |
25 #define __expr_c_seen__ | |
26 | |
27 #include <config.h> | |
28 | |
29 #include <ctype.h> | |
30 #include <stdlib.h> | |
31 #include <string.h> | |
32 | |
33 #include "expr.h" | |
34 #include "util.h" | |
35 #include "lwasm.h" | |
36 | |
37 lwasm_expr_stack_t *lwasm_expr_stack_create(void) | |
38 { | |
39 lwasm_expr_stack_t *s; | |
40 | |
41 s = lwasm_alloc(sizeof(lwasm_expr_stack_t)); | |
42 s -> head = NULL; | |
43 s -> tail = NULL; | |
44 return s; | |
45 } | |
46 | |
47 void lwasm_expr_stack_free(lwasm_expr_stack_t *s) | |
48 { | |
49 while (s -> head) | |
50 { | |
51 s -> tail = s -> head; | |
52 s -> head = s -> head -> next; | |
53 lwasm_expr_term_free(s -> tail -> term); | |
54 lwasm_free(s -> tail); | |
55 } | |
56 lwasm_free(s); | |
57 } | |
58 | |
59 void lwasm_expr_term_free(lwasm_expr_term_t *t) | |
60 { | |
61 if (t) | |
62 { | |
63 if (t -> term_type == LWASM_TERM_SYM) | |
64 lwasm_free(t -> symbol); | |
65 lwasm_free(t); | |
66 } | |
67 } | |
68 | |
69 lwasm_expr_term_t *lwasm_expr_term_create_oper(int oper) | |
70 { | |
71 lwasm_expr_term_t *t; | |
72 | |
73 debug_message(10, "Creating operator term: %d", oper); | |
74 | |
75 t = lwasm_alloc(sizeof(lwasm_expr_term_t)); | |
76 t -> term_type = LWASM_TERM_OPER; | |
77 t -> value = oper; | |
78 return t; | |
79 } | |
80 | |
81 lwasm_expr_term_t *lwasm_expr_term_create_int(int val) | |
82 { | |
83 lwasm_expr_term_t *t; | |
84 debug_message(10, "Creating integer term: %d", val); | |
85 | |
86 t = lwasm_alloc(sizeof(lwasm_expr_term_t)); | |
87 t -> term_type = LWASM_TERM_INT; | |
88 t -> value = val; | |
89 return t; | |
90 } | |
91 | |
92 lwasm_expr_term_t *lwasm_expr_term_create_secbase(void) | |
93 { | |
94 lwasm_expr_term_t *t; | |
95 debug_message(10, "Creating section base term"); | |
96 | |
97 t = lwasm_alloc(sizeof(lwasm_expr_term_t)); | |
98 t -> term_type = LWASM_TERM_SECBASE; | |
99 return t; | |
100 } | |
101 | |
102 lwasm_expr_term_t *lwasm_expr_term_create_sym(char *sym) | |
103 { | |
104 lwasm_expr_term_t *t; | |
105 | |
106 debug_message(10, "Creating symbol term: %s", sym); | |
107 | |
108 t = lwasm_alloc(sizeof(lwasm_expr_term_t)); | |
109 t -> term_type = LWASM_TERM_SYM; | |
110 t -> symbol = lwasm_strdup(sym); | |
111 return t; | |
112 } | |
113 | |
114 lwasm_expr_term_t *lwasm_expr_term_dup(lwasm_expr_term_t *t) | |
115 { | |
116 switch (t -> term_type) | |
117 { | |
118 case LWASM_TERM_INT: | |
119 return lwasm_expr_term_create_int(t -> value); | |
120 | |
121 case LWASM_TERM_OPER: | |
122 return lwasm_expr_term_create_oper(t -> value); | |
123 | |
124 case LWASM_TERM_SYM: | |
125 return lwasm_expr_term_create_sym(t -> symbol); | |
126 | |
127 case LWASM_TERM_SECBASE: | |
128 return lwasm_expr_term_create_secbase(); | |
129 | |
130 default: | |
131 debug_message(0, "lwasm_expr_term_dup(): invalid term type %d", t -> term_type); | |
132 exit(1); | |
133 } | |
134 // can't get here | |
135 } | |
136 | |
137 void lwasm_expr_stack_push(lwasm_expr_stack_t *s, lwasm_expr_term_t *t) | |
138 { | |
139 lwasm_expr_stack_node_t *n; | |
140 | |
141 if (!s) | |
142 { | |
143 debug_message(0, "lwasm_expr_stack_push(): invalid stack pointer"); | |
144 exit(1); | |
145 } | |
146 | |
147 n = lwasm_alloc(sizeof(lwasm_expr_stack_node_t)); | |
148 n -> next = NULL; | |
149 n -> prev = s -> tail; | |
150 n -> term = lwasm_expr_term_dup(t); | |
151 | |
152 if (s -> head) | |
153 { | |
154 s -> tail -> next = n; | |
155 s -> tail = n; | |
156 } | |
157 else | |
158 { | |
159 s -> head = n; | |
160 s -> tail = n; | |
161 } | |
162 } | |
163 | |
164 lwasm_expr_term_t *lwasm_expr_stack_pop(lwasm_expr_stack_t *s) | |
165 { | |
166 lwasm_expr_term_t *t; | |
167 lwasm_expr_stack_node_t *n; | |
168 | |
169 if (!(s -> tail)) | |
170 return NULL; | |
171 | |
172 n = s -> tail; | |
173 s -> tail = n -> prev; | |
174 if (!(n -> prev)) | |
175 { | |
176 s -> head = NULL; | |
177 } | |
178 | |
179 t = n -> term; | |
180 n -> term = NULL; | |
181 | |
182 lwasm_free(n); | |
183 | |
184 return t; | |
185 } | |
186 | |
187 // the following two functions are co-routines which actually parse | |
188 // an infix expression onto the expression stack, each returns -1 | |
189 // if an error is encountered | |
190 | |
191 /* | |
192 parse a term and push it onto the stack | |
193 | |
194 this function handles unary prefix operators (-, +, .not., .com.) | |
195 as well as () | |
196 */ | |
197 int lwasm_expr_parse_term(lwasm_expr_stack_t *s, const char **p) | |
198 { | |
199 lwasm_expr_term_t *t; | |
200 debug_message(2, "Expression string %s", *p); | |
201 | |
202 eval_next: | |
203 if (!**p || isspace(**p) || **p == ')' || **p == ']') | |
204 return -1; | |
205 if (**p == '(') | |
206 { | |
207 debug_message(3, "Starting paren"); | |
208 (*p)++; | |
209 lwasm_expr_parse_expr(s, p, 0); | |
210 if (**p != ')') | |
211 return -1; | |
212 (*p)++; | |
213 return 0; | |
214 } | |
215 | |
216 if (**p == '+') | |
217 { | |
218 debug_message(3, "Unary +"); | |
219 (*p)++; | |
220 goto eval_next; | |
221 } | |
222 | |
223 if (**p == '-') | |
224 { | |
225 // parse expression following "-" | |
226 (*p)++; | |
227 if (lwasm_expr_parse_expr(s, p, 200) < 0) | |
228 return -1; | |
229 t = lwasm_expr_term_create_oper(LWASM_OPER_NEG); | |
230 lwasm_expr_stack_push(s, t); | |
231 lwasm_expr_term_free(t); | |
232 return 0; | |
233 } | |
234 | |
235 if (**p == '^' || **p == '~') | |
236 { | |
237 // parse expression following "^" | |
238 (*p)++; | |
239 if (lwasm_expr_parse_expr(s, p, 200) < 0) | |
240 return -1; | |
241 t = lwasm_expr_term_create_oper(LWASM_OPER_COM); | |
242 lwasm_expr_stack_push(s, t); | |
243 lwasm_expr_term_free(t); | |
244 return 0; | |
245 } | |
246 | |
247 /* | |
248 we have an actual term here so evaluate it | |
249 | |
250 it could be one of the following: | |
251 | |
252 1. a decimal constant | |
253 2. a hexadecimal constant | |
254 3. an octal constant | |
255 4. a binary constant | |
256 5. a symbol reference | |
257 6. the "current" instruction address (*) | |
258 7. the "current" data address (.) | |
259 8. a "back reference" (<) | |
260 9. a "forward reference" (>) | |
261 | |
262 items 6 through 9 are stored as symbol references | |
263 | |
264 (a . followed by a . or a alpha char or number is a symbol) | |
265 */ | |
266 if (**p == '*' | |
267 || ( | |
268 **p == '.' | |
269 && (*p)[1] != '.' | |
270 && !((*p)[1] >= 'A' && (*p)[1] <= 'Z') | |
271 && !((*p)[1] >= 'a' && (*p)[1] <= 'z') | |
272 && !((*p)[1] >= '0' && (*p)[1] <= '9') | |
273 ) | |
274 || **p == '<' | |
275 || **p == '>') | |
276 { | |
277 char tstr[2]; | |
278 tstr[0] = **p; | |
279 tstr[1] = '\0'; | |
280 t = lwasm_expr_term_create_sym(tstr); | |
281 lwasm_expr_stack_push(s, t); | |
282 lwasm_expr_term_free(t); | |
283 (*p)++; | |
284 return 0; | |
285 } | |
286 | |
287 /* | |
288 - a symbol will be a string of characters introduced by a letter, ".", | |
289 "_" but NOT a number OR it may start with a digit if it contains a $ | |
290 - a decimal constant will consist of only digits, optionally prefixed | |
291 with "&" | |
292 - a binary constant will consist of only 0s and 1s either prefixed with % | |
293 or suffixed with "B" | |
294 - a hex constant will consist of 0-9A-F either prefixed with $ or | |
295 suffixed with "H"; a hex number starting with A-F must be prefixed | |
296 with $ or start with 0 and end with H | |
297 - an octal constant will consist of 0-7 either prefixed with @ or | |
298 suffixed with "O" or "Q" | |
299 - an ascii constant will be a single character prefixed with a ' | |
300 - a double ascii constant will be two characters prefixed with a " | |
301 | |
302 */ | |
303 if (**p == '"') | |
304 { | |
305 // double ascii constant | |
306 int val; | |
307 (*p)++; | |
308 if (!**p) | |
309 return -1; | |
310 if (!*((*p)+1)) | |
311 return -1; | |
312 val = **p << 8 | *((*p) + 1); | |
313 (*p) += 2; | |
314 t = lwasm_expr_term_create_int(val); | |
315 lwasm_expr_stack_push(s, t); | |
316 lwasm_expr_term_free(t); | |
317 return 0; | |
318 } | |
319 else if (**p == '\'') | |
320 { | |
321 // single ascii constant | |
322 int val; | |
323 (*p)++; | |
324 debug_message(3, "Single ascii character constant '%c'", **p); | |
325 if (!**p) | |
326 return -1; | |
327 val = **p; | |
328 (*p)++; | |
329 t = lwasm_expr_term_create_int(val); | |
330 lwasm_expr_stack_push(s, t); | |
331 lwasm_expr_term_free(t); | |
332 return 0; | |
333 } | |
334 else if (**p == '&') | |
335 { | |
336 // decimal constant | |
337 int val = 0; | |
338 | |
339 (*p)++; | |
340 while (**p && strchr("0123456789", **p)) | |
341 { | |
342 val = val * 10 + (**p - '0'); | |
343 (*p)++; | |
344 } | |
345 t = lwasm_expr_term_create_int(val); | |
346 lwasm_expr_stack_push(s, t); | |
347 lwasm_expr_term_free(t); | |
348 return 0; | |
349 } | |
350 else if (**p == '%') | |
351 { | |
352 // binary constant | |
353 int val = 0; | |
354 | |
355 (*p)++; | |
356 while (**p == '0' || **p == '1') | |
357 { | |
358 val = val * 2 + (**p - '0'); | |
359 (*p)++; | |
360 } | |
361 t = lwasm_expr_term_create_int(val); | |
362 lwasm_expr_stack_push(s, t); | |
363 lwasm_expr_term_free(t); | |
364 return 0; | |
365 } | |
366 else if (**p == '$') | |
367 { | |
368 // hexadecimal constant | |
369 int val = 0, val2; | |
370 | |
371 (*p)++; | |
372 debug_message(3, "Found prefix hex constant: %s", *p); | |
373 while (**p && strchr("0123456789ABCDEFabcdef", **p)) | |
374 { | |
375 val2 = toupper(**p) - '0'; | |
376 if (val2 > 9) | |
377 val2 -= 7; | |
378 debug_message(3, "Got char: %c (%d)", **p, val2); | |
379 val = val * 16 + val2; | |
380 (*p)++; | |
381 } | |
382 t = lwasm_expr_term_create_int(val); | |
383 lwasm_expr_stack_push(s, t); | |
384 lwasm_expr_term_free(t); | |
385 return 0; | |
386 } | |
387 else if (**p == '0' && tolower(*(*p + 1)) == 'x') | |
388 { | |
389 // "C" style hexadecimal constant | |
390 int val = 0, val2; | |
391 | |
392 (*p)+=2; | |
393 debug_message(3, "Found \"C\" style prefix hex constant: %s", *p); | |
394 while (**p && strchr("0123456789ABCDEFabcdef", **p)) | |
395 { | |
396 val2 = toupper(**p) - '0'; | |
397 if (val2 > 9) | |
398 val2 -= 7; | |
399 debug_message(3, "Got char: %c (%d)", **p, val2); | |
400 val = val * 16 + val2; | |
401 (*p)++; | |
402 } | |
403 t = lwasm_expr_term_create_int(val); | |
404 lwasm_expr_stack_push(s, t); | |
405 lwasm_expr_term_free(t); | |
406 return 0; | |
407 } | |
408 // an @ followed by a digit is an octal number | |
409 // but if it's followed by anything else, it is a symbol | |
410 else if (**p == '@' && isdigit(*(*p + 1))) | |
411 { | |
412 // octal constant | |
413 int val = 0; | |
414 | |
415 (*p)++; | |
416 while (**p && strchr("01234567", **p)) | |
417 { | |
418 val = val * 8 + (**p - '0'); | |
419 (*p)++; | |
420 } | |
421 t = lwasm_expr_term_create_int(val); | |
422 lwasm_expr_stack_push(s, t); | |
423 lwasm_expr_term_free(t); | |
424 return 0; | |
425 } | |
426 | |
427 // symbol or bare decimal or suffix identified constant here | |
428 | |
429 // find the end of a potential symbol | |
430 do | |
431 { | |
432 int l = 0; | |
433 char *sb; | |
434 int havedol = 0; | |
435 | |
436 // evaluate a symbol here | |
437 static const char *symchars = "_.$@?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; | |
438 while ((*p)[l] && strchr(symchars, (*p)[l])) | |
439 { | |
440 if ((*p)[l] == '$') | |
441 havedol = 1; | |
442 l++; | |
443 } | |
444 if (l == 0) | |
445 return -1; | |
446 | |
447 if (havedol || **p < '0' || **p > '9') | |
448 { | |
449 // have a symbol here | |
450 | |
451 sb = lwasm_alloc(l + 1); | |
452 sb[l] = '\0'; | |
453 memcpy(sb, *p, l); | |
454 t = lwasm_expr_term_create_sym(sb); | |
455 lwasm_expr_stack_push(s, t); | |
456 lwasm_expr_term_free(t); | |
457 (*p) += l; | |
458 debug_message(3, "Symbol: '%s'; (%s)", sb, *p); | |
459 lwasm_free(sb); | |
460 return 0; | |
461 } | |
462 } while (0); | |
463 | |
464 if (!**p) | |
465 return -1; | |
466 | |
467 // evaluate a suffix based constant | |
468 { | |
469 int decval = 0, binval = 0, hexval = 0, octval = 0; | |
470 int valtype = 15; // 1 = bin, 2 = oct, 4 = dec, 8 = hex | |
471 int bindone = 0; | |
472 int val; | |
473 int dval; | |
474 | |
475 while (1) | |
476 { | |
477 if (!**p || !strchr("0123456789ABCDEFabcdefqhoQHO", **p)) | |
478 { | |
479 // we can legally have bin or decimal here | |
480 if (bindone) | |
481 { | |
482 // we just finished a binary value | |
483 val = binval; | |
484 break; | |
485 } | |
486 else if (valtype & 4) | |
487 { | |
488 // otherwise we must be decimal (if we're still allowed one) | |
489 val = decval; | |
490 debug_message(3, "End of decimal value"); | |
491 break; | |
492 } | |
493 else | |
494 { | |
495 // bad value | |
496 return -1; | |
497 } | |
498 } | |
499 | |
500 dval = toupper(**p); | |
501 (*p)++; | |
502 | |
503 if (bindone) | |
504 { | |
505 // any characters past "B" means it is not binary | |
506 bindone = 0; | |
507 valtype &= 14; | |
508 } | |
509 | |
510 switch (dval) | |
511 { | |
512 case 'Q': | |
513 case 'O': | |
514 if (valtype & 2) | |
515 { | |
516 val = octval; | |
517 valtype = -1; | |
518 break; | |
519 } | |
520 else | |
521 { | |
522 // not a valid octal value | |
523 return -1; | |
524 } | |
525 /* can't get here */ | |
526 | |
527 case 'H': | |
528 if (valtype & 8) | |
529 { | |
530 val = hexval; | |
531 valtype = -1; | |
532 break; | |
533 } | |
534 else | |
535 { | |
536 // not a valid hex number | |
537 return -1; | |
538 } | |
539 /* can't get here */ | |
540 | |
541 case 'B': | |
542 // this is a bit of a sticky one since B is a legit hex | |
543 // digit so this may or may not be the end of the number | |
544 // so we fall through to the digit case | |
545 | |
546 if (valtype & 1) | |
547 { | |
548 // could still be binary | |
549 bindone = 1; | |
550 valtype = 9; // hex and binary | |
551 } | |
552 /* fall through intentional */ | |
553 | |
554 default: | |
555 // digit | |
556 dval -= '0'; | |
557 if (dval > 9) | |
558 dval -= 7; | |
559 debug_message(3, "Got digit: %d", dval); | |
560 // if (dval > 1) | |
561 // valtype &= 14; | |
562 // if (dval > 7) | |
563 // valtype &= 12; | |
564 // if (dval > 9) | |
565 // valtype &= 8; | |
566 | |
567 if (valtype & 8) | |
568 { | |
569 hexval = hexval * 16 + dval; | |
570 } | |
571 if (valtype & 4) | |
572 { | |
573 if (dval > 9) | |
574 valtype &= 11; | |
575 else | |
576 decval = decval * 10 + dval; | |
577 } | |
578 if (valtype & 2) | |
579 { | |
580 if (dval > 7) | |
581 valtype &= 13; | |
582 else | |
583 octval = octval * 8 + dval; | |
584 } | |
585 if (valtype & 1) | |
586 { | |
587 if (dval > 1) | |
588 valtype &= 14; | |
589 else | |
590 binval = binval * 2 + dval; | |
591 } | |
592 } | |
593 // break out if we have a return value | |
594 if (valtype == -1) | |
595 break; | |
596 // return if no more valid possibilities! | |
597 if (valtype == 0) | |
598 return -1; | |
599 val = decval; // in case we fall through | |
600 } | |
601 | |
602 // we get here when we have a value to return | |
603 t = lwasm_expr_term_create_int(val); | |
604 lwasm_expr_stack_push(s, t); | |
605 lwasm_expr_term_free(t); | |
606 return 0; | |
607 } | |
608 /* can't get here */ | |
609 } | |
610 | |
611 // parse an expression and push the result onto the stack | |
612 // if an operator of lower precedence than the value of "prec" is found, | |
613 int lwasm_expr_parse_expr(lwasm_expr_stack_t *s, const char **p, int prec) | |
614 { | |
615 static const struct operinfo | |
616 { | |
617 int opernum; | |
618 char *operstr; | |
619 int operprec; | |
620 } operators[] = | |
621 { | |
622 { LWASM_OPER_PLUS, "+", 100 }, | |
623 { LWASM_OPER_MINUS, "-", 100 }, | |
624 { LWASM_OPER_TIMES, "*", 150 }, | |
625 { LWASM_OPER_DIVIDE, "/", 150 }, | |
626 { LWASM_OPER_MOD, "%", 150 }, | |
627 { LWASM_OPER_INTDIV, "\\", 150 }, | |
628 | |
629 // boolean AND/OR | |
630 { LWASM_OPER_AND, "&&", 25 }, | |
631 { LWASM_OPER_OR, "||", 25 }, | |
632 | |
633 // bitwise ops | |
634 { LWASM_OPER_BWAND, "&", 50 }, | |
635 { LWASM_OPER_BWOR, "|", 50 }, | |
636 | |
637 // this collides with the unary complement but shouldn't cause | |
638 // any trouble because of operator precedence | |
639 { LWASM_OPER_BWXOR, "^", 50 }, | |
640 | |
641 { LWASM_OPER_NONE, "", 0 } | |
642 }; | |
643 int opern, i; | |
644 lwasm_expr_term_t *operterm; | |
645 | |
646 // return if we are at the end of the expression or a subexpression | |
647 if (!**p || isspace(**p) || **p == ')' || **p == ',' || **p == ']') | |
648 return 0; | |
649 | |
650 if (lwasm_expr_parse_term(s, p) < 0) | |
651 return -1; | |
652 | |
653 eval_next: | |
654 if (!**p || isspace(**p) || **p == ')' || **p == ',' || **p == ']') | |
655 return 0; | |
656 | |
657 // expecting an operator here | |
658 for (opern = 0; operators[opern].opernum != LWASM_OPER_NONE; opern++) | |
659 { | |
660 for (i = 0; (*p)[i] && operators[opern].operstr[i] && ((*p)[i] == operators[opern].operstr[i]); i++) | |
661 /* do nothing */ ; | |
662 if (operators[opern].operstr[i] == '\0') | |
663 break; | |
664 } | |
665 if (operators[opern].opernum == LWASM_OPER_NONE) | |
666 { | |
667 // unrecognized operator | |
668 return -1; | |
669 } | |
670 | |
671 // the operator number in question is in opern; i is the length of the | |
672 // operator string | |
673 | |
674 // logic: | |
675 // if the precedence of this operation is <= to the "prec" flag, | |
676 // we simply return without advancing the input pointer; the operator | |
677 // will be evaluated again in the enclosing function call | |
678 if (operators[opern].operprec <= prec) | |
679 return 0; | |
680 | |
681 // logic: | |
682 // we have a higher precedence operator here so we will advance the | |
683 // input pointer to the next term and let the expression evaluator | |
684 // loose on it after which time we will push our operator onto the | |
685 // stack and then go on with the expression evaluation | |
686 (*p) += i; // advance input pointer | |
687 | |
688 // evaluate next expression(s) of higher precedence | |
689 if (lwasm_expr_parse_expr(s, p, operators[opern].operprec) < 0) | |
690 return -1; | |
691 | |
692 operterm = lwasm_expr_term_create_oper(operators[opern].opernum); | |
693 lwasm_expr_stack_push(s, operterm); | |
694 lwasm_expr_term_free(operterm); | |
695 | |
696 // return if we are at the end of the expression or a subexpression | |
697 if (!**p || isspace(**p) || **p == ')') | |
698 return 0; | |
699 | |
700 // continue evaluating | |
701 goto eval_next; | |
702 } | |
703 | |
704 /* | |
705 actually evaluate an expression | |
706 | |
707 This happens in two stages. The first stage merely parses the expression into | |
708 a lwasm_expr_stack_t * which is then evaluated as much as possible before the | |
709 result is returned. | |
710 | |
711 Returns NULL on a parse error or otherwise invalid expression. *outp will | |
712 contain the pointer to the next character after the expression if and only | |
713 if there is no error. In the case of an error, *outp is undefined. | |
714 */ | |
715 lwasm_expr_stack_t *lwasm_expr_eval(const char *inp, const char **outp, lwasm_expr_stack_t *(*sfunc)(char *sym, void *state), void *state) | |
716 { | |
717 lwasm_expr_stack_t *s; | |
718 const char *p; | |
719 int rval; | |
720 | |
721 // actually parse the expression | |
722 p = inp; | |
723 s = lwasm_expr_stack_create(); | |
724 | |
725 rval = lwasm_expr_parse_expr(s, &p, 0); | |
726 if (rval < 0) | |
727 goto cleanup_error; | |
728 | |
729 // save end of expression | |
730 if (outp) | |
731 (*outp) = p; | |
732 | |
733 // return potentially partial expression | |
734 if (lwasm_expr_reval(s, sfunc, state) < 0) | |
735 goto cleanup_error; | |
736 | |
737 if (lwasm_expr_is_constant(s)) | |
738 debug_message(3, "Constant expression evaluates to: %d", lwasm_expr_get_value(s)); | |
739 | |
740 return s; | |
741 | |
742 cleanup_error: | |
743 lwasm_expr_stack_free(s); | |
744 return NULL; | |
745 } | |
746 | |
747 /* | |
748 take an expression stack s and scan for operations that can be completed | |
749 | |
750 return -1 on error, 0 on no error | |
751 | |
752 possible errors are: division by zero or unknown operator | |
753 | |
754 theory of operation: | |
755 | |
756 scan the stack for an operator which has two constants preceding it (binary) | |
757 or 1 constant preceding it (unary) and if found, perform the calculation | |
758 and replace the operator and its operands with the result | |
759 | |
760 repeat the scan until no futher simplications are found or if there are no | |
761 further operators or only a single term remains | |
762 | |
763 */ | |
764 int lwasm_expr_reval(lwasm_expr_stack_t *s, lwasm_expr_stack_t *(*sfunc)(char *sym, void *state), void *state) | |
765 { | |
766 lwasm_expr_stack_node_t *n, *n2; | |
767 lwasm_expr_stack_t *ss; | |
768 int c; | |
769 | |
770 next_iter_sym: | |
771 // resolve symbols | |
772 // symbols that do not resolve to an expression are left alone | |
773 for (c = 0, n = s -> head; n; n = n -> next) | |
774 { | |
775 if (n -> term -> term_type == LWASM_TERM_SYM) | |
776 { | |
777 ss = sfunc(n -> term -> symbol, state); | |
778 if (ss) | |
779 { | |
780 c++; | |
781 // splice in the result stack | |
782 if (n -> prev) | |
783 { | |
784 n -> prev -> next = ss -> head; | |
785 } | |
786 else | |
787 { | |
788 s -> head = ss -> head; | |
789 } | |
790 ss -> head -> prev = n -> prev; | |
791 ss -> tail -> next = n -> next; | |
792 if (n -> next) | |
793 { | |
794 n -> next -> prev = ss -> tail; | |
795 } | |
796 else | |
797 { | |
798 s -> tail = ss -> tail; | |
799 } | |
800 lwasm_expr_term_free(n -> term); | |
801 lwasm_free(n); | |
802 n = ss -> tail; | |
803 | |
804 ss -> head = NULL; | |
805 ss -> tail = NULL; | |
806 lwasm_expr_stack_free(ss); | |
807 } | |
808 } | |
809 } | |
810 if (c) | |
811 goto next_iter_sym; | |
812 | |
813 next_iter: | |
814 // a single term | |
815 if (s -> head == s -> tail) | |
816 return 0; | |
817 | |
818 // search for an operator | |
819 for (n = s -> head; n; n = n -> next) | |
820 { | |
821 if (n -> term -> term_type == LWASM_TERM_OPER) | |
822 { | |
823 if (n -> term -> value == LWASM_OPER_NEG | |
824 || n -> term -> value == LWASM_OPER_COM | |
825 ) | |
826 { | |
827 // unary operator | |
828 if (n -> prev && n -> prev -> term -> term_type == LWASM_TERM_INT) | |
829 { | |
830 // a unary operator we can resolve | |
831 // we do the op then remove the term "n" is pointing at | |
832 if (n -> term -> value == LWASM_OPER_NEG) | |
833 { | |
834 n -> prev -> term -> value = -(n -> prev -> term -> value); | |
835 } | |
836 else if (n -> term -> value == LWASM_OPER_COM) | |
837 { | |
838 n -> prev -> term -> value = ~(n -> prev -> term -> value); | |
839 } | |
840 n -> prev -> next = n -> next; | |
841 if (n -> next) | |
842 n -> next -> prev = n -> prev; | |
843 else | |
844 s -> tail = n -> prev; | |
845 | |
846 lwasm_expr_term_free(n -> term); | |
847 lwasm_free(n); | |
848 break; | |
849 } | |
850 } | |
851 else | |
852 { | |
853 // binary operator | |
854 if (n -> prev && n -> prev -> prev && n -> prev -> term -> term_type == LWASM_TERM_INT && n -> prev -> prev -> term -> term_type == LWASM_TERM_INT) | |
855 { | |
856 // a binary operator we can resolve | |
857 switch (n -> term -> value) | |
858 { | |
859 case LWASM_OPER_PLUS: | |
860 n -> prev -> prev -> term -> value += n -> prev -> term -> value; | |
861 break; | |
862 | |
863 case LWASM_OPER_MINUS: | |
864 n -> prev -> prev -> term -> value -= n -> prev -> term -> value; | |
865 break; | |
866 | |
867 case LWASM_OPER_TIMES: | |
868 n -> prev -> prev -> term -> value *= n -> prev -> term -> value; | |
869 break; | |
870 | |
871 case LWASM_OPER_DIVIDE: | |
872 if (n -> prev -> term -> value == 0) | |
873 return -1; | |
874 n -> prev -> prev -> term -> value /= n -> prev -> term -> value; | |
875 break; | |
876 | |
877 case LWASM_OPER_MOD: | |
878 if (n -> prev -> term -> value == 0) | |
879 return -1; | |
880 n -> prev -> prev -> term -> value %= n -> prev -> term -> value; | |
881 break; | |
882 | |
883 case LWASM_OPER_INTDIV: | |
884 if (n -> prev -> term -> value == 0) | |
885 return -1; | |
886 n -> prev -> prev -> term -> value /= n -> prev -> term -> value; | |
887 break; | |
888 | |
889 case LWASM_OPER_BWAND: | |
890 n -> prev -> prev -> term -> value &= n -> prev -> term -> value; | |
891 break; | |
892 | |
893 case LWASM_OPER_BWOR: | |
894 n -> prev -> prev -> term -> value |= n -> prev -> term -> value; | |
895 break; | |
896 | |
897 case LWASM_OPER_BWXOR: | |
898 n -> prev -> prev -> term -> value ^= n -> prev -> term -> value; | |
899 break; | |
900 | |
901 case LWASM_OPER_AND: | |
902 n -> prev -> prev -> term -> value = (n -> prev -> term -> value && n -> prev -> prev -> term -> value) ? 1 : 0; | |
903 break; | |
904 | |
905 case LWASM_OPER_OR: | |
906 n -> prev -> prev -> term -> value = (n -> prev -> term -> value || n -> prev -> prev -> term -> value) ? 1 : 0; | |
907 break; | |
908 | |
909 default: | |
910 // return error if unknown operator! | |
911 return -1; | |
912 } | |
913 | |
914 // now remove the two unneeded entries from the stack | |
915 n -> prev -> prev -> next = n -> next; | |
916 if (n -> next) | |
917 n -> next -> prev = n -> prev -> prev; | |
918 else | |
919 s -> tail = n -> prev -> prev; | |
920 | |
921 lwasm_expr_term_free(n -> term); | |
922 lwasm_expr_term_free(n -> prev -> term); | |
923 lwasm_free(n -> prev); | |
924 lwasm_free(n); | |
925 break; | |
926 } | |
927 } | |
928 } | |
929 } | |
930 // note for the terminally confused about dynamic memory and pointers: | |
931 // n will not be NULL even after the lwasm_free calls above so | |
932 // this test will still work (n will be a dangling pointer) | |
933 // (n will only be NULL if we didn't find any operators to simplify) | |
934 if (n) | |
935 goto next_iter; | |
936 | |
937 return 0; | |
938 } |