Mercurial > hg-old > index.cgi
annotate lwlib/lw_expr.c @ 382:eacdae8a1575
Various bugfixes
author | lost@starbug |
---|---|
date | Sat, 15 May 2010 13:39:21 -0600 |
parents | 91c0fe026940 |
children | a741d2e4869f |
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 | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
196 void lw_expr_print_aux(lw_expr_t E, char **obuf, int *buflen, int *bufloc) |
334 | 197 { |
198 struct lw_expr_opers *o; | |
335 | 199 int c = 0; |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
200 char buf[256]; |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
201 |
334 | 202 for (o = E -> operands; o; o = o -> next) |
203 { | |
335 | 204 c++; |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
205 lw_expr_print_aux(o -> p, obuf, buflen, bufloc); |
334 | 206 } |
207 | |
208 switch (E -> type) | |
209 { | |
210 case lw_expr_type_int: | |
371 | 211 if (E -> value < 0) |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
212 snprintf(buf, 256, "-%#x ", -(E -> value)); |
371 | 213 else |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
214 snprintf(buf, 256, "%#x ", E -> value); |
334 | 215 break; |
335 | 216 |
217 case lw_expr_type_var: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
218 snprintf(buf, 256, "V(%s) ", (char *)(E -> value2)); |
335 | 219 break; |
220 | |
221 case lw_expr_type_special: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
222 snprintf(buf, 256, "S(%d,%p) ", E -> value, E -> value2); |
335 | 223 break; |
224 | |
334 | 225 case lw_expr_type_oper: |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
226 snprintf(buf, 256, "[%d]", c); |
334 | 227 switch (E -> value) |
228 { | |
229 case lw_expr_oper_plus: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
230 strcat(buf, "+ "); |
334 | 231 break; |
232 | |
233 case lw_expr_oper_minus: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
234 strcat(buf, "- "); |
334 | 235 break; |
236 | |
237 case lw_expr_oper_times: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
238 strcat(buf, "* "); |
334 | 239 break; |
240 | |
241 case lw_expr_oper_divide: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
242 strcat(buf, "/ "); |
334 | 243 break; |
244 | |
245 case lw_expr_oper_mod: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
246 strcat(buf, "% "); |
334 | 247 break; |
248 | |
249 case lw_expr_oper_intdiv: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
250 strcat(buf, "\\ "); |
334 | 251 break; |
252 | |
253 case lw_expr_oper_bwand: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
254 strcat(buf, "BWAND "); |
334 | 255 break; |
256 | |
257 case lw_expr_oper_bwor: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
258 strcat(buf, "BWOR "); |
334 | 259 break; |
260 | |
261 case lw_expr_oper_bwxor: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
262 strcat(buf, "BWXOR "); |
334 | 263 break; |
264 | |
265 case lw_expr_oper_and: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
266 strcat(buf, "AND "); |
334 | 267 break; |
268 | |
269 case lw_expr_oper_or: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
270 strcat(buf, "OR "); |
334 | 271 break; |
272 | |
273 case lw_expr_oper_neg: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
274 strcat(buf, "NEG "); |
334 | 275 break; |
276 | |
277 case lw_expr_oper_com: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
278 strcat(buf, "COM "); |
334 | 279 break; |
280 | |
281 default: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
282 strcat(buf, "OPER "); |
334 | 283 break; |
284 } | |
285 break; | |
286 default: | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
287 snprintf(buf, 256, "ERR "); |
334 | 288 break; |
289 } | |
372
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
290 |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
291 c = strlen(buf); |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
292 if (*bufloc + c >= *buflen) |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
293 { |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
294 *buflen += 128; |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
295 *obuf = lw_realloc(*obuf, *buflen); |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
296 } |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
297 strcpy(*obuf + *bufloc, buf); |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
298 *bufloc += c; |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
299 } |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
300 |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
301 char *lw_expr_print(lw_expr_t E) |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
302 { |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
303 static char *obuf = NULL; |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
304 static int obufsize = 0; |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
305 |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
306 int obufloc = 0; |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
307 |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
308 lw_expr_print_aux(E, &obuf, &obufsize, &obufloc); |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
309 |
90de73ba0cac
Created a useful debug framework and adjusted lw_expr_print() to return a "static" dynamic string
lost@starbug
parents:
371
diff
changeset
|
310 return obuf; |
334 | 311 } |
312 | |
313 /* | |
314 Return: | |
315 nonzero if expressions are the same (identical pointers or matching values) | |
316 zero if expressions are not the same | |
317 | |
318 */ | |
319 int lw_expr_compare(lw_expr_t E1, lw_expr_t E2) | |
320 { | |
321 struct lw_expr_opers *o1, *o2; | |
322 | |
323 if (E1 == E2) | |
324 return 1; | |
325 | |
326 if (!(E1 -> type == E2 -> type && E1 -> value == E2 -> value)) | |
327 return 0; | |
328 | |
329 if (E1 -> type == lw_expr_type_var) | |
330 { | |
331 if (!strcmp(E1 -> value2, E2 -> value2)) | |
332 return 1; | |
333 else | |
334 return 0; | |
335 } | |
336 | |
337 if (E1 -> type == lw_expr_type_special) | |
338 { | |
339 if (E1 -> value2 == E2 -> value2) | |
340 return 1; | |
341 else | |
342 return 0; | |
343 } | |
344 | |
345 for (o1 = E1 -> operands, o2 = E2 -> operands; o1 && o2; o1 = o1 -> next, o2 = o2 -> next) | |
346 if (lw_expr_compare(o1 -> p, o2 -> p) == 0) | |
347 return 0; | |
348 if (o1 || o2) | |
349 return 0; | |
350 | |
351 return 1; | |
352 } | |
353 | |
354 /* return true if E is an operator of type oper */ | |
355 int lw_expr_isoper(lw_expr_t E, int oper) | |
356 { | |
357 if (E -> type == lw_expr_type_oper && E -> value == oper) | |
358 return 1; | |
359 return 0; | |
360 } | |
335 | 361 |
362 | |
363 void lw_expr_simplify_sortconstfirst(lw_expr_t E) | |
364 { | |
365 struct lw_expr_opers *o; | |
371 | 366 |
367 if (E -> type != lw_expr_type_oper) | |
368 return; | |
369 if (E -> value != lw_expr_oper_times && E -> value != lw_expr_oper_plus) | |
370 return; | |
371 | |
335 | 372 for (o = E -> operands; o; o = o -> next) |
371 | 373 { |
374 if (o -> p -> type == lw_expr_type_oper && (o -> p -> value == lw_expr_oper_times || o -> p -> value == lw_expr_oper_plus)) | |
375 lw_expr_simplify_sortconstfirst(o -> p); | |
376 } | |
335 | 377 |
378 for (o = E -> operands; o; o = o -> next) | |
379 { | |
380 if (o -> p -> type == lw_expr_type_int && o != E -> operands) | |
381 { | |
382 struct lw_expr_opers *o2; | |
383 for (o2 = E -> operands; o2 -> next != o; o2 = o2 -> next) | |
384 /* do nothing */ ; | |
385 o2 -> next = o -> next; | |
386 o -> next = E -> operands; | |
387 E -> operands = o; | |
388 o = o2; | |
389 } | |
390 } | |
391 } | |
392 | |
336 | 393 void lw_expr_sortoperandlist(struct lw_expr_opers **o) |
394 { | |
382 | 395 // fprintf(stderr, "lw_expr_sortoperandlist() not yet implemented\n"); |
336 | 396 } |
397 | |
335 | 398 // return 1 if the operand lists match, 0 if not |
399 // may re-order the argument lists | |
400 int lw_expr_simplify_compareoperandlist(struct lw_expr_opers **ol1, struct lw_expr_opers **ol2) | |
401 { | |
402 struct lw_expr_opers *o1, *o2; | |
403 | |
404 lw_expr_sortoperandlist(ol1); | |
405 lw_expr_sortoperandlist(ol2); | |
406 | |
407 for (o1 = *ol1, o2 = *ol2; o1 && o2; o1 = o1 -> next, o2 = o2 -> next) | |
408 { | |
409 if (!lw_expr_compare(o1 -> p, o2 -> p)) | |
410 return 0; | |
411 } | |
412 if (o1 || o2) | |
413 return 0; | |
414 return 1; | |
415 } | |
416 | |
371 | 417 int lw_expr_simplify_isliketerm(lw_expr_t e1, lw_expr_t e2) |
418 { | |
419 // first term is a "times" | |
420 if (e1 -> type == lw_expr_type_oper && e1 -> value == lw_expr_oper_times) | |
421 { | |
422 // second term is a "times" | |
423 if (e2 -> type == lw_expr_type_oper && e2 -> value == lw_expr_oper_times) | |
424 { | |
425 // both times - easy check | |
426 struct lw_expr_opers *o1, *o2; | |
427 for (o1 = e1 -> operands; o1; o1 = o1 -> next) | |
428 if (o1 -> p -> type != lw_expr_type_int) | |
429 break; | |
430 | |
431 for (o2 = e2 -> operands; o2; o2 = o2 -> next) | |
432 if (o2 -> p -> type != lw_expr_type_int) | |
433 break; | |
434 | |
435 if (lw_expr_simplify_compareoperandlist(&o1, &o2)) | |
436 return 1; | |
437 return 0; | |
438 } | |
439 | |
440 // not a times - have to assume it's the operand list | |
441 // with a "1 *" in front if it | |
442 if (e1 -> operands -> next -> next) | |
443 return 0; | |
444 if (!lw_expr_compare(e1 -> operands -> next -> p, e2)) | |
445 return 0; | |
446 return 1; | |
447 } | |
448 | |
449 // e1 is not a times | |
450 if (e2 -> type == lw_expr_type_oper && e2 -> value == lw_expr_oper_times) | |
451 { | |
452 // e2 is a times | |
453 if (e2 -> operands -> next -> next) | |
454 return 0; | |
455 if (!lw_expr_compare(e1, e2 -> operands -> next -> p)) | |
456 return 0; | |
457 return 1; | |
458 } | |
459 | |
460 // neither are times | |
461 if (!lw_expr_compare(e1, e2)) | |
462 return 0; | |
463 return 1; | |
464 } | |
465 | |
346
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
466 void lw_expr_simplify(lw_expr_t E, void *priv) |
335 | 467 { |
468 struct lw_expr_opers *o; | |
469 | |
371 | 470 // replace subtraction with O1 + -1(O2)... |
471 // needed for like term collection | |
472 if (E -> type == lw_expr_type_oper && E -> value == lw_expr_oper_minus) | |
473 { | |
474 for (o = E -> operands -> next; o; o = o -> next) | |
475 { | |
476 lw_expr_t e1, e2; | |
477 | |
478 e2 = lw_expr_build(lw_expr_type_int, -1); | |
479 e1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_times, e2, o -> p); | |
480 lw_expr_destroy(o -> p); | |
481 lw_expr_destroy(e2); | |
482 o -> p = e1; | |
483 } | |
484 E -> value = lw_expr_oper_plus; | |
485 } | |
486 | |
487 // turn "NEG" into -1(O) - needed for like term collection | |
488 if (E -> type == lw_expr_type_oper && E -> value == lw_expr_oper_neg) | |
489 { | |
490 lw_expr_t e1; | |
491 | |
492 E -> value = lw_expr_oper_times; | |
493 e1 = lw_expr_build(lw_expr_type_int, -1); | |
494 lw_expr_add_operand(E, e1); | |
495 lw_expr_destroy(e1); | |
496 } | |
497 | |
337 | 498 again: |
499 // try to resolve non-constant terms to constants here | |
500 if (E -> type == lw_expr_type_special && evaluate_special) | |
501 { | |
502 lw_expr_t te; | |
503 | |
346
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
504 te = evaluate_special(E -> value, E -> value2, priv); |
337 | 505 if (te) |
506 { | |
507 for (o = E -> operands; o; o = o -> next) | |
508 lw_expr_destroy(o -> p); | |
509 if (E -> type == lw_expr_type_var) | |
510 lw_free(E -> value2); | |
511 *E = *te; | |
512 E -> operands = NULL; | |
513 | |
514 if (te -> type == lw_expr_type_var) | |
515 E -> value2 = lw_strdup(te -> value2); | |
516 for (o = te -> operands; o; o = o -> next) | |
517 { | |
518 lw_expr_add_operand(E, lw_expr_copy(o -> p)); | |
519 } | |
520 lw_expr_destroy(te); | |
521 goto again; | |
522 } | |
523 return; | |
524 } | |
525 | |
526 if (E -> type == lw_expr_type_var && evaluate_var) | |
527 { | |
528 lw_expr_t te; | |
529 | |
346
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
530 te = evaluate_var(E -> value2, priv); |
337 | 531 if (te) |
532 { | |
533 for (o = E -> operands; o; o = o -> next) | |
534 lw_expr_destroy(o -> p); | |
535 if (E -> type == lw_expr_type_var) | |
536 lw_free(E -> value2); | |
537 *E = *te; | |
538 E -> operands = NULL; | |
539 | |
540 if (te -> type == lw_expr_type_var) | |
541 E -> value2 = lw_strdup(te -> value2); | |
542 for (o = te -> operands; o; o = o -> next) | |
543 { | |
544 lw_expr_add_operand(E, lw_expr_copy(o -> p)); | |
545 } | |
546 lw_expr_destroy(te); | |
547 goto again; | |
548 } | |
549 return; | |
550 } | |
551 | |
552 // non-operators have no simplification to do! | |
553 if (E -> type != lw_expr_type_oper) | |
554 return; | |
555 | |
371 | 556 // merge plus operations |
557 if (E -> value == lw_expr_oper_plus) | |
558 { | |
559 lw_expr_t e2; | |
560 | |
561 tryagainplus: | |
562 for (o = E -> operands; o; o = o -> next) | |
563 { | |
564 if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_plus) | |
565 { | |
566 struct lw_expr_opers *o2, *o3; | |
567 // we have a + operation - bring operands up | |
568 | |
569 for (o2 = E -> operands; o2 && o2 -> next != o; o2 = o2 -> next) | |
570 /* do nothing */ ; | |
571 if (o2) | |
572 o2 -> next = o -> p -> operands; | |
573 else | |
574 E -> operands = o -> p -> operands; | |
575 for (o2 = o -> p -> operands; o2 -> next; o2 = o2 -> next) | |
576 /* do nothing */ ; | |
577 o2 -> next = o -> next; | |
578 o -> p -> operands = NULL; | |
579 lw_expr_destroy(o -> p); | |
580 lw_free(o); | |
581 goto tryagainplus; | |
582 } | |
583 } | |
584 } | |
585 | |
586 // merge times operations | |
587 if (E -> value == lw_expr_oper_times) | |
588 { | |
589 lw_expr_t e2; | |
590 | |
591 tryagaintimes: | |
592 for (o = E -> operands; o; o = o -> next) | |
593 { | |
594 if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_times) | |
595 { | |
596 struct lw_expr_opers *o2, *o3; | |
597 // we have a + operation - bring operands up | |
598 | |
599 for (o2 = E -> operands; o2 && o2 -> next != o; o2 = o2 -> next) | |
600 /* do nothing */ ; | |
601 if (o2) | |
602 o2 -> next = o -> p -> operands; | |
603 else | |
604 E -> operands = o -> p -> operands; | |
605 for (o2 = o -> p -> operands; o2 -> next; o2 = o2 -> next) | |
606 /* do nothing */ ; | |
607 o2 -> next = o -> next; | |
608 o -> p -> operands = NULL; | |
609 lw_expr_destroy(o -> p); | |
610 lw_free(o); | |
611 goto tryagaintimes; | |
612 } | |
613 } | |
614 } | |
335 | 615 |
337 | 616 // simplify operands |
617 for (o = E -> operands; o; o = o -> next) | |
346
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
618 lw_expr_simplify(o -> p, priv); |
337 | 619 |
620 for (o = E -> operands; o; o = o -> next) | |
621 { | |
622 if (o -> p -> type != lw_expr_type_int) | |
623 break; | |
624 } | |
625 | |
626 if (!o) | |
627 { | |
628 // we can do the operation here! | |
629 int tr = -42424242; | |
630 | |
631 switch (E -> value) | |
632 { | |
633 case lw_expr_oper_neg: | |
634 tr = -(E -> operands -> p -> value); | |
635 break; | |
636 | |
637 case lw_expr_oper_com: | |
638 tr = ~(E -> operands -> p -> value); | |
639 break; | |
640 | |
641 case lw_expr_oper_plus: | |
642 tr = E -> operands -> p -> value; | |
643 for (o = E -> operands -> next; o; o = o -> next) | |
644 tr += o -> p -> value; | |
645 break; | |
646 | |
647 case lw_expr_oper_minus: | |
648 tr = E -> operands -> p -> value; | |
649 for (o = E -> operands -> next; o; o = o -> next) | |
650 tr -= o -> p -> value; | |
651 break; | |
652 | |
653 case lw_expr_oper_times: | |
654 tr = E -> operands -> p -> value; | |
655 for (o = E -> operands -> next; o; o = o -> next) | |
656 tr *= o -> p -> value; | |
657 break; | |
658 | |
659 case lw_expr_oper_divide: | |
660 tr = E -> operands -> p -> value / E -> operands -> next -> p -> value; | |
661 break; | |
662 | |
663 case lw_expr_oper_mod: | |
664 tr = E -> operands -> p -> value % E -> operands -> next -> p -> value; | |
665 break; | |
666 | |
667 case lw_expr_oper_intdiv: | |
668 tr = E -> operands -> p -> value / E -> operands -> next -> p -> value; | |
669 break; | |
670 | |
671 case lw_expr_oper_bwand: | |
672 tr = E -> operands -> p -> value & E -> operands -> next -> p -> value; | |
673 break; | |
674 | |
675 case lw_expr_oper_bwor: | |
676 tr = E -> operands -> p -> value | E -> operands -> next -> p -> value; | |
677 break; | |
678 | |
679 case lw_expr_oper_bwxor: | |
680 tr = E -> operands -> p -> value ^ E -> operands -> next -> p -> value; | |
681 break; | |
682 | |
683 case lw_expr_oper_and: | |
684 tr = E -> operands -> p -> value && E -> operands -> next -> p -> value; | |
685 break; | |
686 | |
687 case lw_expr_oper_or: | |
688 tr = E -> operands -> p -> value || E -> operands -> next -> p -> value; | |
689 break; | |
690 | |
691 } | |
692 | |
693 while (E -> operands) | |
694 { | |
695 o = E -> operands; | |
696 E -> operands = o -> next; | |
697 lw_expr_destroy(o -> p); | |
698 lw_free(o); | |
699 } | |
700 E -> type = lw_expr_type_int; | |
701 E -> value = tr; | |
335 | 702 return; |
337 | 703 } |
335 | 704 |
371 | 705 if (E -> value == lw_expr_oper_plus) |
706 { | |
707 lw_expr_t e1; | |
708 int cval = 0; | |
709 | |
710 e1 = lw_expr_create(); | |
711 e1 -> operands = E -> operands; | |
712 E -> operands = 0; | |
713 | |
714 for (o = e1 -> operands; o; o = o -> next) | |
715 { | |
716 if (o -> p -> type == lw_expr_type_int) | |
717 cval += o -> p -> value; | |
718 else | |
719 lw_expr_add_operand(E, o -> p); | |
720 } | |
721 lw_expr_destroy(e1); | |
722 if (cval) | |
723 { | |
724 e1 = lw_expr_build(lw_expr_type_int, cval); | |
725 lw_expr_add_operand(E, e1); | |
726 lw_expr_destroy(e1); | |
727 } | |
728 } | |
729 | |
730 if (E -> value == lw_expr_oper_times) | |
731 { | |
732 lw_expr_t e1; | |
733 int cval = 1; | |
734 | |
735 e1 = lw_expr_create(); | |
736 e1 -> operands = E -> operands; | |
737 E -> operands = 0; | |
738 | |
739 for (o = e1 -> operands; o; o = o -> next) | |
740 { | |
741 if (o -> p -> type == lw_expr_type_int) | |
742 cval *= o -> p -> value; | |
743 else | |
744 lw_expr_add_operand(E, o -> p); | |
745 } | |
746 lw_expr_destroy(e1); | |
747 if (cval != 1) | |
748 { | |
749 e1 = lw_expr_build(lw_expr_type_int, cval); | |
750 lw_expr_add_operand(E, e1); | |
751 lw_expr_destroy(e1); | |
752 } | |
753 } | |
754 | |
335 | 755 if (E -> value == lw_expr_oper_times) |
756 { | |
757 for (o = E -> operands; o; o = o -> next) | |
758 { | |
759 if (o -> p -> type == lw_expr_type_int && o -> p -> value == 0) | |
760 { | |
761 // one operand of times is 0, replace operation with 0 | |
762 while (E -> operands) | |
763 { | |
764 o = E -> operands; | |
765 E -> operands = o -> next; | |
766 lw_expr_destroy(o -> p); | |
767 lw_free(o); | |
768 } | |
769 E -> type = lw_expr_type_int; | |
770 E -> value = 0; | |
771 return; | |
772 } | |
773 } | |
774 } | |
775 | |
371 | 776 // sort "constants" to the start of each operand list for + and * |
777 if (E -> value == lw_expr_oper_plus || E -> value == lw_expr_oper_times) | |
778 lw_expr_simplify_sortconstfirst(E); | |
779 | |
335 | 780 // look for like terms and collect them together |
781 if (E -> value == lw_expr_oper_plus) | |
782 { | |
371 | 783 struct lw_expr_opers *o2; |
335 | 784 for (o = E -> operands; o; o = o -> next) |
785 { | |
371 | 786 // skip constants |
787 if (o -> p -> type == lw_expr_type_int) | |
788 continue; | |
789 | |
790 // we have a term to match | |
791 // (o -> p) is first term | |
792 for (o2 = o -> next; o2; o2 = o2 -> next) | |
335 | 793 { |
371 | 794 lw_expr_t e1, e2; |
335 | 795 |
371 | 796 if (o2 -> p -> type == lw_expr_type_int) |
797 continue; | |
798 | |
799 if (lw_expr_simplify_isliketerm(o -> p, o2 -> p)) | |
335 | 800 { |
371 | 801 int coef, coef2; |
802 | |
803 // we have a like term here | |
804 // do something about it | |
805 if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_times) | |
806 { | |
807 if (o -> p -> operands -> p -> type == lw_expr_type_int) | |
808 coef = o -> p -> operands -> p -> value; | |
809 else | |
810 coef = 1; | |
811 } | |
812 else | |
813 coef = 1; | |
335 | 814 if (o2 -> p -> type == lw_expr_type_oper && o2 -> p -> value == lw_expr_oper_times) |
815 { | |
371 | 816 if (o2 -> p -> operands -> p -> type == lw_expr_type_int) |
817 coef2 = o2 -> p -> operands -> p -> value; | |
818 else | |
819 coef2 = 1; | |
335 | 820 } |
371 | 821 else |
822 coef2 = 1; | |
823 coef += coef2; | |
824 e1 = lw_expr_create(); | |
825 e1 -> type = lw_expr_type_oper; | |
826 e1 -> value = lw_expr_oper_times; | |
827 if (coef != 1) | |
828 { | |
829 e2 = lw_expr_build(lw_expr_type_int, coef); | |
830 lw_expr_add_operand(e1, e2); | |
831 lw_expr_destroy(e2); | |
832 } | |
833 lw_expr_destroy(o -> p); | |
834 o -> p = e1; | |
835 for (o = o2 -> p -> operands; o; o = o -> next) | |
836 { | |
837 if (o -> p -> type == lw_expr_type_int) | |
838 continue; | |
839 lw_expr_add_operand(e1, o -> p); | |
840 } | |
841 lw_expr_destroy(o2 -> p); | |
842 o2 -> p = lw_expr_build(lw_expr_type_int, 0); | |
843 goto again; | |
335 | 844 } |
845 } | |
846 } | |
847 } | |
848 | |
849 | |
850 if (E -> value == lw_expr_oper_plus) | |
851 { | |
852 int c = 0, t = 0; | |
853 for (o = E -> operands; o; o = o -> next) | |
854 { | |
855 t++; | |
856 if (!(o -> p -> type == lw_expr_type_int && o -> p -> value == 0)) | |
857 { | |
858 c++; | |
859 } | |
860 } | |
861 if (c == 1) | |
862 { | |
863 lw_expr_t r; | |
864 // find the value and "move it up" | |
865 while (E -> operands) | |
866 { | |
867 o = E -> operands; | |
868 if (o -> p -> type != lw_expr_type_int || o -> p -> value != 0) | |
869 { | |
337 | 870 r = lw_expr_copy(o -> p); |
335 | 871 } |
872 E -> operands = o -> next; | |
873 lw_expr_destroy(o -> p); | |
874 lw_free(o); | |
875 } | |
876 *E = *r; | |
877 return; | |
878 } | |
879 else if (c == 0) | |
880 { | |
881 // replace with 0 | |
882 while (E -> operands) | |
883 { | |
884 o = E -> operands; | |
885 E -> operands = o -> next; | |
886 lw_expr_destroy(o -> p); | |
887 lw_free(o); | |
888 } | |
889 E -> type = lw_expr_type_int; | |
890 E -> value = 0; | |
891 return; | |
892 } | |
893 else if (c != t) | |
894 { | |
895 // collapse out zero terms | |
896 struct lw_expr_opers *o2; | |
897 | |
898 for (o = E -> operands; o; o = o -> next) | |
899 { | |
900 if (o -> p -> type == lw_expr_type_int && o -> p -> value == 0) | |
901 { | |
902 if (o == E -> operands) | |
903 { | |
904 E -> operands = o -> next; | |
905 lw_expr_destroy(o -> p); | |
906 lw_free(o); | |
907 o = E -> operands; | |
908 } | |
909 else | |
910 { | |
911 for (o2 = E -> operands; o2 -> next == o; o2 = o2 -> next) | |
912 /* do nothing */ ; | |
913 o2 -> next = o -> next; | |
914 lw_expr_destroy(o -> p); | |
915 lw_free(o); | |
916 o = o2; | |
917 } | |
918 } | |
919 } | |
920 } | |
921 return; | |
922 } | |
923 } | |
346
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
924 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
925 /* |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
926 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
927 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
|
928 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
|
929 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
|
930 determine what the term really is. It also handles parentheses. |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
931 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
932 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
|
933 respects the order of operations. |
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 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
|
936 following conditions: |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
937 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
938 1. a NUL character |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
939 2. a whitespace character |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
940 3. a ) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
941 4. a , |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
942 5. any character that is not recognized as a term |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
943 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
944 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
|
945 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
946 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
|
947 error. |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
948 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
949 */ |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
950 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
951 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
|
952 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
953 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
|
954 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
955 lw_expr_t term, term2; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
956 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
957 eval_next: |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
958 if (!**p || isspace(**p) || **p == ')' || **p == ']') |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
959 return NULL; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
960 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
961 // parentheses |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
962 if (**p == '(') |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
963 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
964 (*p)++; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
965 term = lw_expr_parse_expr(p, priv, 0); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
966 if (**p != ')') |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
967 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
968 lw_expr_destroy(term); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
969 return NULL; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
970 } |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
971 (*p)++; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
972 return term; |
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 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
975 // unary + |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
976 if (**p == '+') |
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 (*p)++; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
979 goto eval_next; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
980 } |
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 // unary - (prec 200) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
983 if (**p == '-') |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
984 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
985 (*p)++; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
986 term = lw_expr_parse_expr(p, priv, 200); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
987 if (!term) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
988 return NULL; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
989 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
990 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
|
991 lw_expr_destroy(term); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
992 return term2; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
993 } |
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 // unary ^ or ~ (complement, prec 200) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
996 if (**p == '^' || **p == '~') |
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 (*p)++; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
999 term = lw_expr_parse_expr(p, priv, 200); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1000 if (!term) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1001 return NULL; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1002 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1003 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
|
1004 lw_expr_destroy(term); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1005 return term2; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1006 } |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1007 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1008 // non-operator - pass to caller |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1009 return parse_term(p, priv); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1010 } |
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_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
|
1013 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1014 static const struct operinfo |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1015 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1016 int opernum; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1017 char *operstr; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1018 int operprec; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1019 } operators[] = |
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 { lw_expr_oper_plus, "+", 100 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1022 { lw_expr_oper_minus, "-", 100 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1023 { lw_expr_oper_times, "*", 100 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1024 { lw_expr_oper_divide, "/", 150 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1025 { lw_expr_oper_mod, "%", 150 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1026 { lw_expr_oper_intdiv, "\\", 150 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1027 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1028 { lw_expr_oper_and, "&&", 25 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1029 { lw_expr_oper_or, "||", 25 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1030 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1031 { lw_expr_oper_bwand, "&", 50 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1032 { lw_expr_oper_bwor, "|", 50 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1033 { lw_expr_oper_bwxor, "^", 50 }, |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1034 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1035 { lw_expr_oper_none, "", 0 } |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1036 }; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1037 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1038 int opern, i; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1039 lw_expr_t term1, term2, term3; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1040 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1041 if (!**p || isspace(**p) || **p == ')' || **p == ',' || **p == ']') |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1042 return NULL; |
370 | 1043 |
346
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1044 term1 = lw_expr_parse_term(p, priv); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1045 if (!term1) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1046 return NULL; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1047 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1048 eval_next: |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1049 if (!**p || isspace(**p) || **p == ')' || **p == ',' || **p == ']') |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1050 return term1; |
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 // expecting an operator here |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1053 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
|
1054 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1055 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
|
1056 /* do nothing */; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1057 if (operators[opern].operstr[i] == '\0') |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1058 break; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1059 } |
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 if (operators[opern].opernum == lw_expr_oper_none) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1062 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1063 // unrecognized operator |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1064 lw_expr_destroy(term1); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1065 return NULL; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1066 } |
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 // operator number is in opern, length of oper in i |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1069 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1070 // logic: |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1071 // 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
|
1072 // we simply return without advancing the input pointer; the operator |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1073 // will be evaluated again in the enclosing function call |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1074 if (operators[opern].operprec <= prec) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1075 return term1; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1076 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1077 // logic: |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1078 // 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
|
1079 // 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
|
1080 // 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
|
1081 // stack and then go on with the expression evaluation |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1082 (*p) += i; |
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 // evaluate next expression(s) of higher precedence |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1085 term2 = lw_expr_parse_expr(p, priv, operators[opern].operprec); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1086 if (!term2) |
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_destroy(term1); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1089 return NULL; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1090 } |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1091 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1092 // now create operator |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1093 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
|
1094 lw_expr_destroy(term1); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1095 lw_expr_destroy(term2); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1096 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1097 // the new "expression" is the next "left operand" |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1098 term1 = term3; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1099 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1100 // continue evaluating |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1101 goto eval_next; |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1102 } |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1103 |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1104 lw_expr_t lw_expr_parse(char **p, void *priv) |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1105 { |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1106 return lw_expr_parse_expr(p, priv, 0); |
a82c55070624
Added expression parsing infrastructure and misc fixes
lost@starbug
parents:
342
diff
changeset
|
1107 } |
367 | 1108 |
1109 int lw_expr_testterms(lw_expr_t e, lw_expr_testfn_t *fn, void *priv) | |
1110 { | |
1111 struct lw_expr_opers *o; | |
1112 int r; | |
1113 | |
1114 for (o = e -> operands; o; o = o -> next) | |
1115 { | |
1116 r = lw_expr_testterms(o -> p, fn, priv); | |
1117 if (r) | |
1118 return r; | |
1119 } | |
1120 return (fn)(e, priv); | |
1121 } | |
376 | 1122 |
1123 int lw_expr_type(lw_expr_t e) | |
1124 { | |
1125 return e -> type; | |
1126 } | |
1127 | |
1128 void *lw_expr_specptr(lw_expr_t e) | |
1129 { | |
1130 return e -> value2; | |
1131 } |