comparison lwlink/expr.c @ 139:106c2fe3c9d9

repo reorg
author lost
date Wed, 28 Jan 2009 05:59:14 +0000
parents lwlink-old/trunk/src/expr.c@050864a47b38
children 299c5d793aca
comparison
equal deleted inserted replaced
138:050864a47b38 139:106c2fe3c9d9
1 /*
2 expr.c
3 Copyright © 2009 William Astle
4
5 This file is part of LWLINK.
6
7 LWLINK is free software: you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation, either version 3 of the License, or (at your option) any later
10 version.
11
12 This program is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 more details.
16
17 You should have received a copy of the GNU General Public License along with
18 this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 /*
22 This file contains the actual expression evaluator
23 */
24
25 #define __expr_c_seen__
26
27 #include <ctype.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "expr.h"
32 #include "util.h"
33
34 lw_expr_stack_t *lw_expr_stack_create(void)
35 {
36 lw_expr_stack_t *s;
37
38 s = lw_malloc(sizeof(lw_expr_stack_t));
39 s -> head = NULL;
40 s -> tail = NULL;
41 return s;
42 }
43
44 void lw_expr_stack_free(lw_expr_stack_t *s)
45 {
46 while (s -> head)
47 {
48 s -> tail = s -> head;
49 s -> head = s -> head -> next;
50 lw_expr_term_free(s -> tail -> term);
51 lw_free(s -> tail);
52 }
53 lw_free(s);
54 }
55
56 void lw_expr_term_free(lw_expr_term_t *t)
57 {
58 if (t)
59 {
60 if (t -> term_type == LW_TERM_SYM)
61 lw_free(t -> symbol);
62 lw_free(t);
63 }
64 }
65
66 lw_expr_term_t *lw_expr_term_create_oper(int oper)
67 {
68 lw_expr_term_t *t;
69
70 t = lw_malloc(sizeof(lw_expr_term_t));
71 t -> term_type = LW_TERM_OPER;
72 t -> value = oper;
73 return t;
74 }
75
76 lw_expr_term_t *lw_expr_term_create_int(int val)
77 {
78 lw_expr_term_t *t;
79
80 t = lw_malloc(sizeof(lw_expr_term_t));
81 t -> term_type = LW_TERM_INT;
82 t -> value = val;
83 return t;
84 }
85
86 lw_expr_term_t *lw_expr_term_create_sym(char *sym, int symtype)
87 {
88 lw_expr_term_t *t;
89
90 t = lw_malloc(sizeof(lw_expr_term_t));
91 t -> term_type = LW_TERM_SYM;
92 t -> symbol = lw_strdup(sym);
93 t -> value = symtype;
94 return t;
95 }
96
97 lw_expr_term_t *lw_expr_term_dup(lw_expr_term_t *t)
98 {
99 switch (t -> term_type)
100 {
101 case LW_TERM_INT:
102 return lw_expr_term_create_int(t -> value);
103
104 case LW_TERM_OPER:
105 return lw_expr_term_create_oper(t -> value);
106
107 case LW_TERM_SYM:
108 return lw_expr_term_create_sym(t -> symbol, t -> value);
109
110 default:
111 exit(1);
112 }
113 // can't get here
114 }
115
116 void lw_expr_stack_push(lw_expr_stack_t *s, lw_expr_term_t *t)
117 {
118 lw_expr_stack_node_t *n;
119
120 if (!s)
121 {
122 exit(1);
123 }
124
125 n = lw_malloc(sizeof(lw_expr_stack_node_t));
126 n -> next = NULL;
127 n -> prev = s -> tail;
128 n -> term = lw_expr_term_dup(t);
129
130 if (s -> head)
131 {
132 s -> tail -> next = n;
133 s -> tail = n;
134 }
135 else
136 {
137 s -> head = n;
138 s -> tail = n;
139 }
140 }
141
142 lw_expr_term_t *lw_expr_stack_pop(lw_expr_stack_t *s)
143 {
144 lw_expr_term_t *t;
145 lw_expr_stack_node_t *n;
146
147 if (!(s -> tail))
148 return NULL;
149
150 n = s -> tail;
151 s -> tail = n -> prev;
152 if (!(n -> prev))
153 {
154 s -> head = NULL;
155 }
156
157 t = n -> term;
158 n -> term = NULL;
159
160 lw_free(n);
161
162 return t;
163 }
164
165 /*
166 take an expression stack s and scan for operations that can be completed
167
168 return -1 on error, 0 on no error
169
170 possible errors are: division by zero or unknown operator
171
172 theory of operation:
173
174 scan the stack for an operator which has two constants preceding it (binary)
175 or 1 constant preceding it (unary) and if found, perform the calculation
176 and replace the operator and its operands with the result
177
178 repeat the scan until no futher simplications are found or if there are no
179 further operators or only a single term remains
180
181 */
182 int lw_expr_reval(lw_expr_stack_t *s, lw_expr_stack_t *(*sfunc)(char *sym, int stype, void *state), void *state)
183 {
184 lw_expr_stack_node_t *n, *n2;
185 lw_expr_stack_t *ss;
186 int c;
187
188 next_iter_sym:
189 // resolve symbols
190 // symbols that do not resolve to an expression are left alone
191 for (c = 0, n = s -> head; n; n = n -> next)
192 {
193 if (n -> term -> term_type == LW_TERM_SYM)
194 {
195 ss = sfunc(n -> term -> symbol, n -> term -> value, state);
196 if (ss)
197 {
198 c++;
199 // splice in the result stack
200 if (n -> prev)
201 {
202 n -> prev -> next = ss -> head;
203 }
204 else
205 {
206 s -> head = ss -> head;
207 }
208 ss -> head -> prev = n -> prev;
209 ss -> tail -> next = n -> next;
210 if (n -> next)
211 {
212 n -> next -> prev = ss -> tail;
213 }
214 else
215 {
216 s -> tail = ss -> tail;
217 }
218 lw_expr_term_free(n -> term);
219 lw_free(n);
220 n = ss -> tail;
221
222 ss -> head = NULL;
223 ss -> tail = NULL;
224 lw_expr_stack_free(ss);
225 }
226 }
227 }
228 if (c)
229 goto next_iter_sym;
230
231 next_iter:
232 // a single term
233 if (s -> head == s -> tail)
234 return 0;
235
236 // search for an operator
237 for (n = s -> head; n; n = n -> next)
238 {
239 if (n -> term -> term_type == LW_TERM_OPER)
240 {
241 if (n -> term -> value == LW_OPER_NEG
242 || n -> term -> value == LW_OPER_COM
243 )
244 {
245 // unary operator
246 if (n -> prev && n -> prev -> term -> term_type == LW_TERM_INT)
247 {
248 // a unary operator we can resolve
249 // we do the op then remove the term "n" is pointing at
250 if (n -> term -> value == LW_OPER_NEG)
251 {
252 n -> prev -> term -> value = -(n -> prev -> term -> value);
253 }
254 else if (n -> term -> value == LW_OPER_COM)
255 {
256 n -> prev -> term -> value = ~(n -> prev -> term -> value);
257 }
258 n -> prev -> next = n -> next;
259 if (n -> next)
260 n -> next -> prev = n -> prev;
261 else
262 s -> tail = n -> prev;
263
264 lw_expr_term_free(n -> term);
265 lw_free(n);
266 break;
267 }
268 }
269 else
270 {
271 // binary operator
272 if (n -> prev && n -> prev -> prev && n -> prev -> term -> term_type == LW_TERM_INT && n -> prev -> prev -> term -> term_type == LW_TERM_INT)
273 {
274 // a binary operator we can resolve
275 switch (n -> term -> value)
276 {
277 case LW_OPER_PLUS:
278 n -> prev -> prev -> term -> value += n -> prev -> term -> value;
279 break;
280
281 case LW_OPER_MINUS:
282 n -> prev -> prev -> term -> value -= n -> prev -> term -> value;
283 break;
284
285 case LW_OPER_TIMES:
286 n -> prev -> prev -> term -> value *= n -> prev -> term -> value;
287 break;
288
289 case LW_OPER_DIVIDE:
290 if (n -> prev -> term -> value == 0)
291 return -1;
292 n -> prev -> prev -> term -> value /= n -> prev -> term -> value;
293 break;
294
295 case LW_OPER_MOD:
296 if (n -> prev -> term -> value == 0)
297 return -1;
298 n -> prev -> prev -> term -> value %= n -> prev -> term -> value;
299 break;
300
301 case LW_OPER_INTDIV:
302 if (n -> prev -> term -> value == 0)
303 return -1;
304 n -> prev -> prev -> term -> value /= n -> prev -> term -> value;
305 break;
306
307 case LW_OPER_BWAND:
308 n -> prev -> prev -> term -> value &= n -> prev -> term -> value;
309 break;
310
311 case LW_OPER_BWOR:
312 n -> prev -> prev -> term -> value |= n -> prev -> term -> value;
313 break;
314
315 case LW_OPER_BWXOR:
316 n -> prev -> prev -> term -> value ^= n -> prev -> term -> value;
317 break;
318
319 case LW_OPER_AND:
320 n -> prev -> prev -> term -> value = (n -> prev -> term -> value && n -> prev -> prev -> term -> value) ? 1 : 0;
321 break;
322
323 case LW_OPER_OR:
324 n -> prev -> prev -> term -> value = (n -> prev -> term -> value || n -> prev -> prev -> term -> value) ? 1 : 0;
325 break;
326
327 default:
328 // return error if unknown operator!
329 return -1;
330 }
331
332 // now remove the two unneeded entries from the stack
333 n -> prev -> prev -> next = n -> next;
334 if (n -> next)
335 n -> next -> prev = n -> prev -> prev;
336 else
337 s -> tail = n -> prev -> prev;
338
339 lw_expr_term_free(n -> term);
340 lw_expr_term_free(n -> prev -> term);
341 lw_free(n -> prev);
342 lw_free(n);
343 break;
344 }
345 }
346 }
347 }
348 // note for the terminally confused about dynamic memory and pointers:
349 // n will not be NULL even after the lw_free calls above so
350 // this test will still work (n will be a dangling pointer)
351 // (n will only be NULL if we didn't find any operators to simplify)
352 if (n)
353 goto next_iter;
354
355 return 0;
356 }