Mercurial > hg-old > index.cgi
annotate lwlib/lw_expr.c @ 371:9c24d9d485b9
Much bugfixing
author | lost@starbug |
---|---|
date | Wed, 21 Apr 2010 23:29:18 -0600 |
parents | 6b33faa21a0a |
children | 90de73ba0cac |
rev | line source |
---|---|
334 | 1 /* |
2 lwexpr.c | |
3 | |
4 Copyright © 2010 William Astle | |
5 | |
6 This file is part of LWTOOLS. | |
7 | |
8 LWTOOLS is free software: you can redistribute it and/or modify it under the | |
9 terms of the GNU General Public License as published by the Free Software | |
10 Foundation, either version 3 of the License, or (at your option) any later | |
11 version. | |
12 | |
13 This program is distributed in the hope that it will be useful, but WITHOUT | |
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
16 more details. | |
17 | |
18 You should have received a copy of the GNU General Public License along with | |
19 this program. If not, see <http://www.gnu.org/licenses/>. | |
20 */ | |
21 | |
22 #include <config.h> | |
23 | |
24 #include <stdarg.h> | |
25 #include <stdio.h> | |
26 #include <string.h> | |
27 | |
28 #define ___lw_expr_c_seen___ | |
29 #include "lw_alloc.h" | |
30 #include "lw_expr.h" | |
31 #include "lw_error.h" | |
32 #include "lw_string.h" | |
33 | |
342 | 34 static lw_expr_fn_t *evaluate_special = NULL; |
35 static lw_expr_fn2_t *evaluate_var = NULL; | |
346
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
36 static lw_expr_fn3_t *parse_term = NULL; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
37 |
347 | 38 int lw_expr_istype(lw_expr_t e, int t) |
39 { | |
40 if (e -> type == t) | |
41 return 1; | |
42 return 0; | |
43 } | |
44 | |
45 int lw_expr_intval(lw_expr_t e) | |
46 { | |
47 if (e -> type == lw_expr_type_int) | |
48 return e -> value; | |
49 return -1; | |
50 } | |
51 | |
367 | 52 int lw_expr_specint(lw_expr_t e) |
53 { | |
54 if (e -> type == lw_expr_type_special) | |
55 return e -> value; | |
56 return -1; | |
57 } | |
58 | |
346
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
59 void lw_expr_set_term_parser(lw_expr_fn3_t *fn) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
60 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
61 parse_term = fn; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
62 } |
337 | 63 |
342 | 64 void lw_expr_set_special_handler(lw_expr_fn_t *fn) |
337 | 65 { |
66 evaluate_special = fn; | |
67 } | |
68 | |
342 | 69 void lw_expr_set_var_handler(lw_expr_fn2_t *fn) |
337 | 70 { |
71 evaluate_var = fn; | |
72 } | |
73 | |
334 | 74 lw_expr_t lw_expr_create(void) |
75 { | |
76 lw_expr_t r; | |
77 | |
78 r = lw_alloc(sizeof(struct lw_expr_priv)); | |
79 r -> operands = NULL; | |
80 | |
81 return r; | |
82 } | |
83 | |
84 void lw_expr_destroy(lw_expr_t E) | |
85 { | |
337 | 86 struct lw_expr_opers *o; |
87 for (o = E -> operands; o; o = o -> next) | |
88 lw_expr_destroy(o -> p); | |
89 if (E -> type == lw_expr_type_var) | |
90 lw_free(E -> value2); | |
91 lw_free(E); | |
334 | 92 } |
93 | |
337 | 94 /* actually duplicates the entire expression */ |
95 void lw_expr_add_operand(lw_expr_t E, lw_expr_t O); | |
334 | 96 lw_expr_t lw_expr_copy(lw_expr_t E) |
97 { | |
337 | 98 lw_expr_t r, t; |
99 struct lw_expr_opers *o; | |
100 | |
101 r = lw_alloc(sizeof(struct lw_expr_priv)); | |
102 *r = *E; | |
103 r -> operands = NULL; | |
104 | |
105 if (E -> type == lw_expr_type_var) | |
106 r -> value2 = lw_strdup(E -> value2); | |
107 for (o = E -> operands; o; o = o -> next) | |
108 { | |
109 lw_expr_add_operand(r, lw_expr_copy(o -> p)); | |
110 } | |
111 | |
112 return r; | |
334 | 113 } |
114 | |
115 void lw_expr_add_operand(lw_expr_t E, lw_expr_t O) | |
116 { | |
117 struct lw_expr_opers *o, *t; | |
118 | |
119 o = lw_alloc(sizeof(struct lw_expr_opers)); | |
120 o -> p = lw_expr_copy(O); | |
121 o -> next = NULL; | |
122 for (t = E -> operands; t && t -> next; t = t -> next) | |
123 /* do nothing */ ; | |
124 | |
125 if (t) | |
126 t -> next = o; | |
127 else | |
128 E -> operands = o; | |
129 } | |
130 | |
335 | 131 lw_expr_t lw_expr_build_aux(int exprtype, va_list args) |
334 | 132 { |
133 lw_expr_t r; | |
134 int t; | |
135 void *p; | |
136 | |
137 lw_expr_t te1, te2; | |
138 | |
139 r = lw_expr_create(); | |
140 | |
141 switch (exprtype) | |
142 { | |
143 case lw_expr_type_int: | |
144 t = va_arg(args, int); | |
145 r -> type = lw_expr_type_int; | |
146 r -> value = t; | |
147 break; | |
148 | |
149 case lw_expr_type_var: | |
150 p = va_arg(args, char *); | |
151 r -> type = lw_expr_type_var; | |
152 r -> value2 = lw_strdup(p); | |
153 break; | |
154 | |
155 case lw_expr_type_special: | |
156 t = va_arg(args, int); | |
157 p = va_arg(args, char *); | |
158 r -> type = lw_expr_type_special; | |
337 | 159 r -> value = t; |
334 | 160 r -> value2 = p; |
161 break; | |
162 | |
163 case lw_expr_type_oper: | |
164 t = va_arg(args, int); | |
165 te1 = va_arg(args, lw_expr_t); | |
166 if (t != lw_expr_oper_com && t != lw_expr_oper_neg) | |
167 te2 = va_arg(args, lw_expr_t); | |
168 else | |
169 te2 = NULL; | |
170 | |
171 r -> type = lw_expr_type_oper; | |
172 r -> value = t; | |
173 lw_expr_add_operand(r, te1); | |
371 | 174 if (te2) |
175 lw_expr_add_operand(r, te2); | |
334 | 176 break; |
177 | |
178 default: | |
179 lw_error("Invalid expression type specified to lw_expr_build"); | |
180 } | |
181 | |
335 | 182 return r; |
183 } | |
184 | |
185 lw_expr_t lw_expr_build(int exprtype, ...) | |
186 { | |
187 va_list args; | |
188 lw_expr_t r; | |
189 | |
190 va_start(args, exprtype); | |
191 r = lw_expr_build_aux(exprtype, args); | |
192 va_end(args); | |
193 return r; | |
194 } | |
195 | |
370 | 196 void lw_expr_print(lw_expr_t E, FILE *fp) |
334 | 197 { |
198 struct lw_expr_opers *o; | |
335 | 199 int c = 0; |
200 | |
334 | 201 for (o = E -> operands; o; o = o -> next) |
202 { | |
335 | 203 c++; |
370 | 204 lw_expr_print(o -> p, fp); |
334 | 205 } |
206 | |
207 switch (E -> type) | |
208 { | |
209 case lw_expr_type_int: | |
371 | 210 if (E -> value < 0) |
211 fprintf(fp, "-%#x ", -(E -> value)); | |
212 else | |
213 fprintf(fp, "%#x ", E -> value); | |
334 | 214 break; |
335 | 215 |
216 case lw_expr_type_var: | |
370 | 217 fprintf(fp, "V(%s) ", (char *)(E -> value2)); |
335 | 218 break; |
219 | |
220 case lw_expr_type_special: | |
370 | 221 fprintf(fp, "S(%d,%p) ", E -> value, E -> value2); |
335 | 222 break; |
223 | |
334 | 224 case lw_expr_type_oper: |
370 | 225 fprintf(fp, "[%d]", c); |
334 | 226 switch (E -> value) |
227 { | |
228 case lw_expr_oper_plus: | |
370 | 229 fprintf(fp, "+ "); |
334 | 230 break; |
231 | |
232 case lw_expr_oper_minus: | |
370 | 233 fprintf(fp, "- "); |
334 | 234 break; |
235 | |
236 case lw_expr_oper_times: | |
370 | 237 fprintf(fp, "* "); |
334 | 238 break; |
239 | |
240 case lw_expr_oper_divide: | |
370 | 241 fprintf(fp, "/ "); |
334 | 242 break; |
243 | |
244 case lw_expr_oper_mod: | |
370 | 245 fprintf(fp, "%% "); |
334 | 246 break; |
247 | |
248 case lw_expr_oper_intdiv: | |
370 | 249 fprintf(fp, "\\ "); |
334 | 250 break; |
251 | |
252 case lw_expr_oper_bwand: | |
370 | 253 fprintf(fp, "BWAND "); |
334 | 254 break; |
255 | |
256 case lw_expr_oper_bwor: | |
370 | 257 fprintf(fp, "BWOR "); |
334 | 258 break; |
259 | |
260 case lw_expr_oper_bwxor: | |
370 | 261 fprintf(fp, "BWXOR "); |
334 | 262 break; |
263 | |
264 case lw_expr_oper_and: | |
370 | 265 fprintf(fp, "AND "); |
334 | 266 break; |
267 | |
268 case lw_expr_oper_or: | |
370 | 269 fprintf(fp, "OR "); |
334 | 270 break; |
271 | |
272 case lw_expr_oper_neg: | |
370 | 273 fprintf(fp, "NEG "); |
334 | 274 break; |
275 | |
276 case lw_expr_oper_com: | |
370 | 277 fprintf(fp, "COM "); |
334 | 278 break; |
279 | |
280 default: | |
370 | 281 fprintf(fp, "OPER "); |
334 | 282 break; |
283 } | |
284 break; | |
285 default: | |
370 | 286 fprintf(fp, "ERR "); |
334 | 287 break; |
288 } | |
289 } | |
290 | |
291 /* | |
292 Return: | |
293 nonzero if expressions are the same (identical pointers or matching values) | |
294 zero if expressions are not the same | |
295 | |
296 */ | |
297 int lw_expr_compare(lw_expr_t E1, lw_expr_t E2) | |
298 { | |
299 struct lw_expr_opers *o1, *o2; | |
300 | |
301 if (E1 == E2) | |
302 return 1; | |
303 | |
304 if (!(E1 -> type == E2 -> type && E1 -> value == E2 -> value)) | |
305 return 0; | |
306 | |
307 if (E1 -> type == lw_expr_type_var) | |
308 { | |
309 if (!strcmp(E1 -> value2, E2 -> value2)) | |
310 return 1; | |
311 else | |
312 return 0; | |
313 } | |
314 | |
315 if (E1 -> type == lw_expr_type_special) | |
316 { | |
317 if (E1 -> value2 == E2 -> value2) | |
318 return 1; | |
319 else | |
320 return 0; | |
321 } | |
322 | |
323 for (o1 = E1 -> operands, o2 = E2 -> operands; o1 && o2; o1 = o1 -> next, o2 = o2 -> next) | |
324 if (lw_expr_compare(o1 -> p, o2 -> p) == 0) | |
325 return 0; | |
326 if (o1 || o2) | |
327 return 0; | |
328 | |
329 return 1; | |
330 } | |
331 | |
332 /* return true if E is an operator of type oper */ | |
333 int lw_expr_isoper(lw_expr_t E, int oper) | |
334 { | |
335 if (E -> type == lw_expr_type_oper && E -> value == oper) | |
336 return 1; | |
337 return 0; | |
338 } | |
335 | 339 |
340 | |
341 void lw_expr_simplify_sortconstfirst(lw_expr_t E) | |
342 { | |
343 struct lw_expr_opers *o; | |
371 | 344 |
345 if (E -> type != lw_expr_type_oper) | |
346 return; | |
347 if (E -> value != lw_expr_oper_times && E -> value != lw_expr_oper_plus) | |
348 return; | |
349 | |
335 | 350 for (o = E -> operands; o; o = o -> next) |
371 | 351 { |
352 if (o -> p -> type == lw_expr_type_oper && (o -> p -> value == lw_expr_oper_times || o -> p -> value == lw_expr_oper_plus)) | |
353 lw_expr_simplify_sortconstfirst(o -> p); | |
354 } | |
335 | 355 |
356 for (o = E -> operands; o; o = o -> next) | |
357 { | |
358 if (o -> p -> type == lw_expr_type_int && o != E -> operands) | |
359 { | |
360 struct lw_expr_opers *o2; | |
361 for (o2 = E -> operands; o2 -> next != o; o2 = o2 -> next) | |
362 /* do nothing */ ; | |
363 o2 -> next = o -> next; | |
364 o -> next = E -> operands; | |
365 E -> operands = o; | |
366 o = o2; | |
367 } | |
368 } | |
369 } | |
370 | |
336 | 371 void lw_expr_sortoperandlist(struct lw_expr_opers **o) |
372 { | |
373 fprintf(stderr, "lw_expr_sortoperandlist() not yet implemented\n"); | |
374 } | |
375 | |
335 | 376 // return 1 if the operand lists match, 0 if not |
377 // may re-order the argument lists | |
378 int lw_expr_simplify_compareoperandlist(struct lw_expr_opers **ol1, struct lw_expr_opers **ol2) | |
379 { | |
380 struct lw_expr_opers *o1, *o2; | |
381 | |
382 lw_expr_sortoperandlist(ol1); | |
383 lw_expr_sortoperandlist(ol2); | |
384 | |
385 for (o1 = *ol1, o2 = *ol2; o1 && o2; o1 = o1 -> next, o2 = o2 -> next) | |
386 { | |
387 if (!lw_expr_compare(o1 -> p, o2 -> p)) | |
388 return 0; | |
389 } | |
390 if (o1 || o2) | |
391 return 0; | |
392 return 1; | |
393 } | |
394 | |
371 | 395 int lw_expr_simplify_isliketerm(lw_expr_t e1, lw_expr_t e2) |
396 { | |
397 fprintf(stderr, "isliketerm in: "); | |
398 lw_expr_print(e1, stderr); | |
399 fprintf(stderr, "; "); | |
400 lw_expr_print(e2, stderr); | |
401 fprintf(stderr, "\n"); | |
402 | |
403 // first term is a "times" | |
404 if (e1 -> type == lw_expr_type_oper && e1 -> value == lw_expr_oper_times) | |
405 { | |
406 // second term is a "times" | |
407 if (e2 -> type == lw_expr_type_oper && e2 -> value == lw_expr_oper_times) | |
408 { | |
409 // both times - easy check | |
410 struct lw_expr_opers *o1, *o2; | |
411 for (o1 = e1 -> operands; o1; o1 = o1 -> next) | |
412 if (o1 -> p -> type != lw_expr_type_int) | |
413 break; | |
414 | |
415 for (o2 = e2 -> operands; o2; o2 = o2 -> next) | |
416 if (o2 -> p -> type != lw_expr_type_int) | |
417 break; | |
418 | |
419 if (lw_expr_simplify_compareoperandlist(&o1, &o2)) | |
420 return 1; | |
421 return 0; | |
422 } | |
423 | |
424 // not a times - have to assume it's the operand list | |
425 // with a "1 *" in front if it | |
426 if (e1 -> operands -> next -> next) | |
427 return 0; | |
428 if (!lw_expr_compare(e1 -> operands -> next -> p, e2)) | |
429 return 0; | |
430 return 1; | |
431 } | |
432 | |
433 // e1 is not a times | |
434 if (e2 -> type == lw_expr_type_oper && e2 -> value == lw_expr_oper_times) | |
435 { | |
436 // e2 is a times | |
437 if (e2 -> operands -> next -> next) | |
438 return 0; | |
439 if (!lw_expr_compare(e1, e2 -> operands -> next -> p)) | |
440 return 0; | |
441 return 1; | |
442 } | |
443 | |
444 // neither are times | |
445 if (!lw_expr_compare(e1, e2)) | |
446 return 0; | |
447 return 1; | |
448 } | |
449 | |
346
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
450 void lw_expr_simplify(lw_expr_t E, void *priv) |
335 | 451 { |
452 struct lw_expr_opers *o; | |
453 | |
371 | 454 // replace subtraction with O1 + -1(O2)... |
455 // needed for like term collection | |
456 if (E -> type == lw_expr_type_oper && E -> value == lw_expr_oper_minus) | |
457 { | |
458 for (o = E -> operands -> next; o; o = o -> next) | |
459 { | |
460 lw_expr_t e1, e2; | |
461 | |
462 e2 = lw_expr_build(lw_expr_type_int, -1); | |
463 e1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_times, e2, o -> p); | |
464 lw_expr_destroy(o -> p); | |
465 lw_expr_destroy(e2); | |
466 o -> p = e1; | |
467 } | |
468 E -> value = lw_expr_oper_plus; | |
469 } | |
470 | |
471 // turn "NEG" into -1(O) - needed for like term collection | |
472 if (E -> type == lw_expr_type_oper && E -> value == lw_expr_oper_neg) | |
473 { | |
474 lw_expr_t e1; | |
475 | |
476 E -> value = lw_expr_oper_times; | |
477 e1 = lw_expr_build(lw_expr_type_int, -1); | |
478 lw_expr_add_operand(E, e1); | |
479 lw_expr_destroy(e1); | |
480 } | |
481 | |
337 | 482 again: |
483 // try to resolve non-constant terms to constants here | |
484 if (E -> type == lw_expr_type_special && evaluate_special) | |
485 { | |
486 lw_expr_t te; | |
487 | |
346
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
488 te = evaluate_special(E -> value, E -> value2, priv); |
337 | 489 if (te) |
490 { | |
491 for (o = E -> operands; o; o = o -> next) | |
492 lw_expr_destroy(o -> p); | |
493 if (E -> type == lw_expr_type_var) | |
494 lw_free(E -> value2); | |
495 *E = *te; | |
496 E -> operands = NULL; | |
497 | |
498 if (te -> type == lw_expr_type_var) | |
499 E -> value2 = lw_strdup(te -> value2); | |
500 for (o = te -> operands; o; o = o -> next) | |
501 { | |
502 lw_expr_add_operand(E, lw_expr_copy(o -> p)); | |
503 } | |
504 lw_expr_destroy(te); | |
505 goto again; | |
506 } | |
507 return; | |
508 } | |
509 | |
510 if (E -> type == lw_expr_type_var && evaluate_var) | |
511 { | |
512 lw_expr_t te; | |
513 | |
346
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
514 te = evaluate_var(E -> value2, priv); |
337 | 515 if (te) |
516 { | |
517 for (o = E -> operands; o; o = o -> next) | |
518 lw_expr_destroy(o -> p); | |
519 if (E -> type == lw_expr_type_var) | |
520 lw_free(E -> value2); | |
521 *E = *te; | |
522 E -> operands = NULL; | |
523 | |
524 if (te -> type == lw_expr_type_var) | |
525 E -> value2 = lw_strdup(te -> value2); | |
526 for (o = te -> operands; o; o = o -> next) | |
527 { | |
528 lw_expr_add_operand(E, lw_expr_copy(o -> p)); | |
529 } | |
530 lw_expr_destroy(te); | |
531 goto again; | |
532 } | |
533 return; | |
534 } | |
535 | |
536 // non-operators have no simplification to do! | |
537 if (E -> type != lw_expr_type_oper) | |
538 return; | |
539 | |
371 | 540 // merge plus operations |
541 if (E -> value == lw_expr_oper_plus) | |
542 { | |
543 lw_expr_t e2; | |
544 | |
545 tryagainplus: | |
546 for (o = E -> operands; o; o = o -> next) | |
547 { | |
548 if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_plus) | |
549 { | |
550 struct lw_expr_opers *o2, *o3; | |
551 // we have a + operation - bring operands up | |
552 | |
553 for (o2 = E -> operands; o2 && o2 -> next != o; o2 = o2 -> next) | |
554 /* do nothing */ ; | |
555 if (o2) | |
556 o2 -> next = o -> p -> operands; | |
557 else | |
558 E -> operands = o -> p -> operands; | |
559 for (o2 = o -> p -> operands; o2 -> next; o2 = o2 -> next) | |
560 /* do nothing */ ; | |
561 o2 -> next = o -> next; | |
562 o -> p -> operands = NULL; | |
563 lw_expr_destroy(o -> p); | |
564 lw_free(o); | |
565 goto tryagainplus; | |
566 } | |
567 } | |
568 } | |
569 | |
570 // merge times operations | |
571 if (E -> value == lw_expr_oper_times) | |
572 { | |
573 lw_expr_t e2; | |
574 | |
575 tryagaintimes: | |
576 for (o = E -> operands; o; o = o -> next) | |
577 { | |
578 if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_times) | |
579 { | |
580 struct lw_expr_opers *o2, *o3; | |
581 // we have a + operation - bring operands up | |
582 | |
583 for (o2 = E -> operands; o2 && o2 -> next != o; o2 = o2 -> next) | |
584 /* do nothing */ ; | |
585 if (o2) | |
586 o2 -> next = o -> p -> operands; | |
587 else | |
588 E -> operands = o -> p -> operands; | |
589 for (o2 = o -> p -> operands; o2 -> next; o2 = o2 -> next) | |
590 /* do nothing */ ; | |
591 o2 -> next = o -> next; | |
592 o -> p -> operands = NULL; | |
593 lw_expr_destroy(o -> p); | |
594 lw_free(o); | |
595 goto tryagaintimes; | |
596 } | |
597 } | |
598 } | |
335 | 599 |
337 | 600 // simplify operands |
601 for (o = E -> operands; o; o = o -> next) | |
346
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
602 lw_expr_simplify(o -> p, priv); |
337 | 603 |
604 for (o = E -> operands; o; o = o -> next) | |
605 { | |
606 if (o -> p -> type != lw_expr_type_int) | |
607 break; | |
608 } | |
609 | |
610 if (!o) | |
611 { | |
612 // we can do the operation here! | |
613 int tr = -42424242; | |
614 | |
615 switch (E -> value) | |
616 { | |
617 case lw_expr_oper_neg: | |
618 tr = -(E -> operands -> p -> value); | |
619 break; | |
620 | |
621 case lw_expr_oper_com: | |
622 tr = ~(E -> operands -> p -> value); | |
623 break; | |
624 | |
625 case lw_expr_oper_plus: | |
626 tr = E -> operands -> p -> value; | |
627 for (o = E -> operands -> next; o; o = o -> next) | |
628 tr += o -> p -> value; | |
629 break; | |
630 | |
631 case lw_expr_oper_minus: | |
632 tr = E -> operands -> p -> value; | |
633 for (o = E -> operands -> next; o; o = o -> next) | |
634 tr -= o -> p -> value; | |
635 break; | |
636 | |
637 case lw_expr_oper_times: | |
638 tr = E -> operands -> p -> value; | |
639 for (o = E -> operands -> next; o; o = o -> next) | |
640 tr *= o -> p -> value; | |
641 break; | |
642 | |
643 case lw_expr_oper_divide: | |
644 tr = E -> operands -> p -> value / E -> operands -> next -> p -> value; | |
645 break; | |
646 | |
647 case lw_expr_oper_mod: | |
648 tr = E -> operands -> p -> value % E -> operands -> next -> p -> value; | |
649 break; | |
650 | |
651 case lw_expr_oper_intdiv: | |
652 tr = E -> operands -> p -> value / E -> operands -> next -> p -> value; | |
653 break; | |
654 | |
655 case lw_expr_oper_bwand: | |
656 tr = E -> operands -> p -> value & E -> operands -> next -> p -> value; | |
657 break; | |
658 | |
659 case lw_expr_oper_bwor: | |
660 tr = E -> operands -> p -> value | E -> operands -> next -> p -> value; | |
661 break; | |
662 | |
663 case lw_expr_oper_bwxor: | |
664 tr = E -> operands -> p -> value ^ E -> operands -> next -> p -> value; | |
665 break; | |
666 | |
667 case lw_expr_oper_and: | |
668 tr = E -> operands -> p -> value && E -> operands -> next -> p -> value; | |
669 break; | |
670 | |
671 case lw_expr_oper_or: | |
672 tr = E -> operands -> p -> value || E -> operands -> next -> p -> value; | |
673 break; | |
674 | |
675 } | |
676 | |
677 while (E -> operands) | |
678 { | |
679 o = E -> operands; | |
680 E -> operands = o -> next; | |
681 lw_expr_destroy(o -> p); | |
682 lw_free(o); | |
683 } | |
684 E -> type = lw_expr_type_int; | |
685 E -> value = tr; | |
335 | 686 return; |
337 | 687 } |
335 | 688 |
371 | 689 if (E -> value == lw_expr_oper_plus) |
690 { | |
691 lw_expr_t e1; | |
692 int cval = 0; | |
693 | |
694 e1 = lw_expr_create(); | |
695 e1 -> operands = E -> operands; | |
696 E -> operands = 0; | |
697 | |
698 for (o = e1 -> operands; o; o = o -> next) | |
699 { | |
700 if (o -> p -> type == lw_expr_type_int) | |
701 cval += o -> p -> value; | |
702 else | |
703 lw_expr_add_operand(E, o -> p); | |
704 } | |
705 lw_expr_destroy(e1); | |
706 if (cval) | |
707 { | |
708 e1 = lw_expr_build(lw_expr_type_int, cval); | |
709 lw_expr_add_operand(E, e1); | |
710 lw_expr_destroy(e1); | |
711 } | |
712 } | |
713 | |
714 if (E -> value == lw_expr_oper_times) | |
715 { | |
716 lw_expr_t e1; | |
717 int cval = 1; | |
718 | |
719 e1 = lw_expr_create(); | |
720 e1 -> operands = E -> operands; | |
721 E -> operands = 0; | |
722 | |
723 for (o = e1 -> operands; o; o = o -> next) | |
724 { | |
725 if (o -> p -> type == lw_expr_type_int) | |
726 cval *= o -> p -> value; | |
727 else | |
728 lw_expr_add_operand(E, o -> p); | |
729 } | |
730 lw_expr_destroy(e1); | |
731 if (cval != 1) | |
732 { | |
733 e1 = lw_expr_build(lw_expr_type_int, cval); | |
734 lw_expr_add_operand(E, e1); | |
735 lw_expr_destroy(e1); | |
736 } | |
737 } | |
738 | |
335 | 739 if (E -> value == lw_expr_oper_times) |
740 { | |
741 for (o = E -> operands; o; o = o -> next) | |
742 { | |
743 if (o -> p -> type == lw_expr_type_int && o -> p -> value == 0) | |
744 { | |
745 // one operand of times is 0, replace operation with 0 | |
746 while (E -> operands) | |
747 { | |
748 o = E -> operands; | |
749 E -> operands = o -> next; | |
750 lw_expr_destroy(o -> p); | |
751 lw_free(o); | |
752 } | |
753 E -> type = lw_expr_type_int; | |
754 E -> value = 0; | |
755 return; | |
756 } | |
757 } | |
758 } | |
759 | |
371 | 760 // sort "constants" to the start of each operand list for + and * |
761 if (E -> value == lw_expr_oper_plus || E -> value == lw_expr_oper_times) | |
762 lw_expr_simplify_sortconstfirst(E); | |
763 | |
335 | 764 // look for like terms and collect them together |
765 if (E -> value == lw_expr_oper_plus) | |
766 { | |
371 | 767 struct lw_expr_opers *o2; |
335 | 768 for (o = E -> operands; o; o = o -> next) |
769 { | |
371 | 770 // skip constants |
771 if (o -> p -> type == lw_expr_type_int) | |
772 continue; | |
773 | |
774 // we have a term to match | |
775 // (o -> p) is first term | |
776 for (o2 = o -> next; o2; o2 = o2 -> next) | |
335 | 777 { |
371 | 778 lw_expr_t e1, e2; |
335 | 779 |
371 | 780 if (o2 -> p -> type == lw_expr_type_int) |
781 continue; | |
782 | |
783 if (lw_expr_simplify_isliketerm(o -> p, o2 -> p)) | |
335 | 784 { |
371 | 785 int coef, coef2; |
786 | |
787 // we have a like term here | |
788 // do something about it | |
789 if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_times) | |
790 { | |
791 if (o -> p -> operands -> p -> type == lw_expr_type_int) | |
792 coef = o -> p -> operands -> p -> value; | |
793 else | |
794 coef = 1; | |
795 } | |
796 else | |
797 coef = 1; | |
335 | 798 if (o2 -> p -> type == lw_expr_type_oper && o2 -> p -> value == lw_expr_oper_times) |
799 { | |
371 | 800 if (o2 -> p -> operands -> p -> type == lw_expr_type_int) |
801 coef2 = o2 -> p -> operands -> p -> value; | |
802 else | |
803 coef2 = 1; | |
335 | 804 } |
371 | 805 else |
806 coef2 = 1; | |
807 coef += coef2; | |
808 e1 = lw_expr_create(); | |
809 e1 -> type = lw_expr_type_oper; | |
810 e1 -> value = lw_expr_oper_times; | |
811 if (coef != 1) | |
812 { | |
813 e2 = lw_expr_build(lw_expr_type_int, coef); | |
814 lw_expr_add_operand(e1, e2); | |
815 lw_expr_destroy(e2); | |
816 } | |
817 lw_expr_destroy(o -> p); | |
818 o -> p = e1; | |
819 for (o = o2 -> p -> operands; o; o = o -> next) | |
820 { | |
821 if (o -> p -> type == lw_expr_type_int) | |
822 continue; | |
823 lw_expr_add_operand(e1, o -> p); | |
824 } | |
825 lw_expr_destroy(o2 -> p); | |
826 o2 -> p = lw_expr_build(lw_expr_type_int, 0); | |
827 goto again; | |
335 | 828 } |
829 } | |
830 } | |
831 } | |
832 | |
833 | |
834 if (E -> value == lw_expr_oper_plus) | |
835 { | |
836 int c = 0, t = 0; | |
837 for (o = E -> operands; o; o = o -> next) | |
838 { | |
839 t++; | |
840 if (!(o -> p -> type == lw_expr_type_int && o -> p -> value == 0)) | |
841 { | |
842 c++; | |
843 } | |
844 } | |
845 if (c == 1) | |
846 { | |
847 lw_expr_t r; | |
848 // find the value and "move it up" | |
849 while (E -> operands) | |
850 { | |
851 o = E -> operands; | |
852 if (o -> p -> type != lw_expr_type_int || o -> p -> value != 0) | |
853 { | |
337 | 854 r = lw_expr_copy(o -> p); |
335 | 855 } |
856 E -> operands = o -> next; | |
857 lw_expr_destroy(o -> p); | |
858 lw_free(o); | |
859 } | |
860 *E = *r; | |
861 return; | |
862 } | |
863 else if (c == 0) | |
864 { | |
865 // replace with 0 | |
866 while (E -> operands) | |
867 { | |
868 o = E -> operands; | |
869 E -> operands = o -> next; | |
870 lw_expr_destroy(o -> p); | |
871 lw_free(o); | |
872 } | |
873 E -> type = lw_expr_type_int; | |
874 E -> value = 0; | |
875 return; | |
876 } | |
877 else if (c != t) | |
878 { | |
879 // collapse out zero terms | |
880 struct lw_expr_opers *o2; | |
881 | |
882 for (o = E -> operands; o; o = o -> next) | |
883 { | |
884 if (o -> p -> type == lw_expr_type_int && o -> p -> value == 0) | |
885 { | |
886 if (o == E -> operands) | |
887 { | |
888 E -> operands = o -> next; | |
889 lw_expr_destroy(o -> p); | |
890 lw_free(o); | |
891 o = E -> operands; | |
892 } | |
893 else | |
894 { | |
895 for (o2 = E -> operands; o2 -> next == o; o2 = o2 -> next) | |
896 /* do nothing */ ; | |
897 o2 -> next = o -> next; | |
898 lw_expr_destroy(o -> p); | |
899 lw_free(o); | |
900 o = o2; | |
901 } | |
902 } | |
903 } | |
904 } | |
905 return; | |
906 } | |
907 } | |
346
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
908 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
909 /* |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
910 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
911 The following two functions are co-routines which evaluate an infix |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
912 expression. lw_expr_parse_term checks for unary prefix operators then, if |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
913 none found, passes the string off the the defined helper function to |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
914 determine what the term really is. It also handles parentheses. |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
915 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
916 lw_expr_parse_expr evaluates actual expressions with infix operators. It |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
917 respects the order of operations. |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
918 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
919 The end of an expression is determined by the presence of any of the |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
920 following conditions: |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
921 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
922 1. a NUL character |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
923 2. a whitespace character |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
924 3. a ) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
925 4. a , |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
926 5. any character that is not recognized as a term |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
927 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
928 lw_expr_parse_term returns NULL if there is no term (end of expr, etc.) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
929 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
930 lw_expr_parse_expr returns NULL if there is no expression or on a syntax |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
931 error. |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
932 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
933 */ |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
934 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
935 lw_expr_t lw_expr_parse_expr(char **p, void *priv, int prec); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
936 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
937 lw_expr_t lw_expr_parse_term(char **p, void *priv) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
938 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
939 lw_expr_t term, term2; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
940 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
941 eval_next: |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
942 if (!**p || isspace(**p) || **p == ')' || **p == ']') |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
943 return NULL; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
944 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
945 // parentheses |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
946 if (**p == '(') |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
947 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
948 (*p)++; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
949 term = lw_expr_parse_expr(p, priv, 0); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
950 if (**p != ')') |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
951 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
952 lw_expr_destroy(term); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
953 return NULL; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
954 } |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
955 (*p)++; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
956 return term; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
957 } |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
958 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
959 // unary + |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
960 if (**p == '+') |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
961 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
962 (*p)++; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
963 goto eval_next; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
964 } |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
965 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
966 // unary - (prec 200) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
967 if (**p == '-') |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
968 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
969 (*p)++; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
970 term = lw_expr_parse_expr(p, priv, 200); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
971 if (!term) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
972 return NULL; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
973 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
974 term2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_neg, term); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
975 lw_expr_destroy(term); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
976 return term2; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
977 } |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
978 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
979 // unary ^ or ~ (complement, prec 200) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
980 if (**p == '^' || **p == '~') |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
981 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
982 (*p)++; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
983 term = lw_expr_parse_expr(p, priv, 200); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
984 if (!term) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
985 return NULL; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
986 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
987 term2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_com, term); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
988 lw_expr_destroy(term); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
989 return term2; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
990 } |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
991 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
992 // non-operator - pass to caller |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
993 return parse_term(p, priv); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
994 } |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
995 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
996 lw_expr_t lw_expr_parse_expr(char **p, void *priv, int prec) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
997 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
998 static const struct operinfo |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
999 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1000 int opernum; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1001 char *operstr; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1002 int operprec; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1003 } operators[] = |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1004 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1005 { lw_expr_oper_plus, "+", 100 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1006 { lw_expr_oper_minus, "-", 100 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1007 { lw_expr_oper_times, "*", 100 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1008 { lw_expr_oper_divide, "/", 150 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1009 { lw_expr_oper_mod, "%", 150 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1010 { lw_expr_oper_intdiv, "\\", 150 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1011 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1012 { lw_expr_oper_and, "&&", 25 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1013 { lw_expr_oper_or, "||", 25 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1014 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1015 { lw_expr_oper_bwand, "&", 50 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1016 { lw_expr_oper_bwor, "|", 50 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1017 { lw_expr_oper_bwxor, "^", 50 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1018 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1019 { lw_expr_oper_none, "", 0 } |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1020 }; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1021 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1022 int opern, i; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1023 lw_expr_t term1, term2, term3; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1024 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1025 if (!**p || isspace(**p) || **p == ')' || **p == ',' || **p == ']') |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1026 return NULL; |
370 | 1027 |
346
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1028 term1 = lw_expr_parse_term(p, priv); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1029 if (!term1) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1030 return NULL; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1031 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1032 eval_next: |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1033 if (!**p || isspace(**p) || **p == ')' || **p == ',' || **p == ']') |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1034 return term1; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1035 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1036 // expecting an operator here |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1037 for (opern = 0; operators[opern].opernum != lw_expr_oper_none; opern++) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1038 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1039 for (i = 0; (*p)[i] && operators[opern].operstr[i] && ((*p)[i] == operators[opern].operstr[i]); i++) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1040 /* do nothing */; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1041 if (operators[opern].operstr[i] == '\0') |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1042 break; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1043 } |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1044 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1045 if (operators[opern].opernum == lw_expr_oper_none) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1046 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1047 // unrecognized operator |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1048 lw_expr_destroy(term1); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1049 return NULL; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1050 } |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1051 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1052 // operator number is in opern, length of oper in i |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1053 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1054 // logic: |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1055 // if the precedence of this operation is <= to the "prec" flag, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1056 // we simply return without advancing the input pointer; the operator |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1057 // will be evaluated again in the enclosing function call |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1058 if (operators[opern].operprec <= prec) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1059 return term1; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1060 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1061 // logic: |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1062 // we have a higher precedence operator here so we will advance the |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1063 // input pointer to the next term and let the expression evaluator |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1064 // loose on it after which time we will push our operator onto the |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1065 // stack and then go on with the expression evaluation |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1066 (*p) += i; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1067 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1068 // evaluate next expression(s) of higher precedence |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1069 term2 = lw_expr_parse_expr(p, priv, operators[opern].operprec); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1070 if (!term2) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1071 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1072 lw_expr_destroy(term1); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1073 return NULL; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1074 } |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1075 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1076 // now create operator |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1077 term3 = lw_expr_build(lw_expr_type_oper, operators[opern].opernum, term1, term2); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1078 lw_expr_destroy(term1); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1079 lw_expr_destroy(term2); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1080 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1081 // the new "expression" is the next "left operand" |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1082 term1 = term3; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1083 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1084 // continue evaluating |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1085 goto eval_next; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1086 } |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1087 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1088 lw_expr_t lw_expr_parse(char **p, void *priv) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1089 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1090 return lw_expr_parse_expr(p, priv, 0); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1091 } |
367 | 1092 |
1093 int lw_expr_testterms(lw_expr_t e, lw_expr_testfn_t *fn, void *priv) | |
1094 { | |
1095 struct lw_expr_opers *o; | |
1096 int r; | |
1097 | |
1098 for (o = e -> operands; o; o = o -> next) | |
1099 { | |
1100 r = lw_expr_testterms(o -> p, fn, priv); | |
1101 if (r) | |
1102 return r; | |
1103 } | |
1104 return (fn)(e, priv); | |
1105 } |