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