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