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