Commit | Line | Data |
---|---|---|
c8b5b797 KB |
1 | /* |
2 | * Copyright (c) 1989 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * Ozan Yigit. | |
7 | * | |
8 | * Redistribution and use in source and binary forms are permitted | |
9 | * provided that the above copyright notice and this paragraph are | |
10 | * duplicated in all such forms and that any documentation, | |
11 | * advertising materials, and other materials related to such | |
12 | * distribution and use acknowledge that the software was developed | |
13 | * by the University of California, Berkeley. The name of the | |
14 | * University may not be used to endorse or promote products derived | |
15 | * from this software without specific prior written permission. | |
16 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
17 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
19 | */ | |
20 | ||
21 | #ifndef lint | |
22 | static char sccsid[] = "@(#)expr.c 5.1 (Berkeley) %G%"; | |
23 | #endif /* not lint */ | |
24 | ||
25 | /* | |
26 | * expression evaluator: performs a standard recursive | |
27 | * descent parse to evaluate any expression permissible | |
28 | * within the following grammar: | |
29 | * | |
30 | * expr : query EOS | |
31 | * query : lor | |
32 | * | lor "?" query ":" query | |
33 | * lor : land { "||" land } | |
34 | * land : bor { "&&" bor } | |
35 | * bor : bxor { "|" bxor } | |
36 | * bxor : band { "^" band } | |
37 | * band : eql { "&" eql } | |
38 | * eql : relat { eqrel relat } | |
39 | * relat : shift { rel shift } | |
40 | * shift : primary { shop primary } | |
41 | * primary : term { addop term } | |
42 | * term : unary { mulop unary } | |
43 | * unary : factor | |
44 | * | unop unary | |
45 | * factor : constant | |
46 | * | "(" query ")" | |
47 | * constant: num | |
48 | * | "'" CHAR "'" | |
49 | * num : DIGIT | |
50 | * | DIGIT num | |
51 | * shop : "<<" | |
52 | * | ">>" | |
53 | * eqlrel : "=" | |
54 | * | "==" | |
55 | * | "!=" | |
56 | * rel : "<" | |
57 | * | ">" | |
58 | * | "<=" | |
59 | * | ">=" | |
60 | * | |
61 | * | |
62 | * This expression evaluator is lifted from a public-domain | |
63 | * C Pre-Processor included with the DECUS C Compiler distribution. | |
64 | * It is hacked somewhat to be suitable for m4. | |
65 | * | |
66 | * Originally by: Mike Lutz | |
67 | * Bob Harper | |
68 | */ | |
69 | ||
70 | #define TRUE 1 | |
71 | #define FALSE 0 | |
72 | #define EOS (char) 0 | |
73 | #define EQL 0 | |
74 | #define NEQ 1 | |
75 | #define LSS 2 | |
76 | #define LEQ 3 | |
77 | #define GTR 4 | |
78 | #define GEQ 5 | |
79 | #define OCTAL 8 | |
80 | #define DECIMAL 10 | |
81 | ||
82 | static char *nxtch; /* Parser scan pointer */ | |
83 | ||
84 | /* | |
85 | * For longjmp | |
86 | */ | |
87 | #include <setjmp.h> | |
88 | static jmp_buf expjump; | |
89 | ||
90 | /* | |
91 | * macros: | |
92 | * | |
93 | * ungetch - Put back the last character examined. | |
94 | * getch - return the next character from expr string. | |
95 | */ | |
96 | #define ungetch() nxtch-- | |
97 | #define getch() *nxtch++ | |
98 | ||
99 | expr(expbuf) | |
100 | char *expbuf; | |
101 | { | |
102 | register int rval; | |
103 | ||
104 | nxtch = expbuf; | |
105 | if (setjmp(expjump) != 0) | |
106 | return (FALSE); | |
107 | rval = query(); | |
108 | if (skipws() == EOS) | |
109 | return(rval); | |
110 | experr("Ill-formed expression"); | |
111 | } | |
112 | ||
113 | /* | |
114 | * query : lor | lor '?' query ':' query | |
115 | * | |
116 | */ | |
117 | query() | |
118 | { | |
119 | register int bool, true_val, false_val; | |
120 | ||
121 | bool = lor(); | |
122 | if (skipws() != '?') { | |
123 | ungetch(); | |
124 | return(bool); | |
125 | } | |
126 | ||
127 | true_val = query(); | |
128 | if (skipws() != ':') | |
129 | experr("Bad query"); | |
130 | ||
131 | false_val = query(); | |
132 | return(bool ? true_val : false_val); | |
133 | } | |
134 | ||
135 | /* | |
136 | * lor : land { '||' land } | |
137 | * | |
138 | */ | |
139 | lor() | |
140 | { | |
141 | register int c, vl, vr; | |
142 | ||
143 | vl = land(); | |
144 | while ((c = skipws()) == '|' && getch() == '|') { | |
145 | vr = land(); | |
146 | vl = vl || vr; | |
147 | } | |
148 | ||
149 | if (c == '|') | |
150 | ungetch(); | |
151 | ungetch(); | |
152 | return(vl); | |
153 | } | |
154 | ||
155 | /* | |
156 | * land : bor { '&&' bor } | |
157 | * | |
158 | */ | |
159 | land() | |
160 | { | |
161 | register int c, vl, vr; | |
162 | ||
163 | vl = bor(); | |
164 | while ((c = skipws()) == '&' && getch() == '&') { | |
165 | vr = bor(); | |
166 | vl = vl && vr; | |
167 | } | |
168 | ||
169 | if (c == '&') | |
170 | ungetch(); | |
171 | ungetch(); | |
172 | return(vl); | |
173 | } | |
174 | ||
175 | /* | |
176 | * bor : bxor { '|' bxor } | |
177 | * | |
178 | */ | |
179 | bor() | |
180 | { | |
181 | register int vl, vr, c; | |
182 | ||
183 | vl = bxor(); | |
184 | while ((c = skipws()) == '|' && getch() != '|') { | |
185 | ungetch(); | |
186 | vr = bxor(); | |
187 | vl |= vr; | |
188 | } | |
189 | ||
190 | if (c == '|') | |
191 | ungetch(); | |
192 | ungetch(); | |
193 | return(vl); | |
194 | } | |
195 | ||
196 | /* | |
197 | * bxor : band { '^' band } | |
198 | * | |
199 | */ | |
200 | bxor() | |
201 | { | |
202 | register int vl, vr; | |
203 | ||
204 | vl = band(); | |
205 | while (skipws() == '^') { | |
206 | vr = band(); | |
207 | vl ^= vr; | |
208 | } | |
209 | ||
210 | ungetch(); | |
211 | return(vl); | |
212 | } | |
213 | ||
214 | /* | |
215 | * band : eql { '&' eql } | |
216 | * | |
217 | */ | |
218 | band() | |
219 | { | |
220 | register int vl, vr, c; | |
221 | ||
222 | vl = eql(); | |
223 | while ((c = skipws()) == '&' && getch() != '&') { | |
224 | ungetch(); | |
225 | vr = eql(); | |
226 | vl &= vr; | |
227 | } | |
228 | ||
229 | if (c == '&') | |
230 | ungetch(); | |
231 | ungetch(); | |
232 | return(vl); | |
233 | } | |
234 | ||
235 | /* | |
236 | * eql : relat { eqrel relat } | |
237 | * | |
238 | */ | |
239 | eql() | |
240 | { | |
241 | register int vl, vr, rel; | |
242 | ||
243 | vl = relat(); | |
244 | while ((rel = geteql()) != -1) { | |
245 | vr = relat(); | |
246 | ||
247 | switch (rel) { | |
248 | ||
249 | case EQL: | |
250 | vl = (vl == vr); | |
251 | break; | |
252 | case NEQ: | |
253 | vl = (vl != vr); | |
254 | break; | |
255 | } | |
256 | } | |
257 | return(vl); | |
258 | } | |
259 | ||
260 | /* | |
261 | * relat : shift { rel shift } | |
262 | * | |
263 | */ | |
264 | relat() | |
265 | { | |
266 | register int vl, vr, rel; | |
267 | ||
268 | vl = shift(); | |
269 | while ((rel = getrel()) != -1) { | |
270 | ||
271 | vr = shift(); | |
272 | switch (rel) { | |
273 | ||
274 | case LEQ: | |
275 | vl = (vl <= vr); | |
276 | break; | |
277 | case LSS: | |
278 | vl = (vl < vr); | |
279 | break; | |
280 | case GTR: | |
281 | vl = (vl > vr); | |
282 | break; | |
283 | case GEQ: | |
284 | vl = (vl >= vr); | |
285 | break; | |
286 | } | |
287 | } | |
288 | return(vl); | |
289 | } | |
290 | ||
291 | /* | |
292 | * shift : primary { shop primary } | |
293 | * | |
294 | */ | |
295 | shift() | |
296 | { | |
297 | register int vl, vr, c; | |
298 | ||
299 | vl = primary(); | |
300 | while (((c = skipws()) == '<' || c == '>') && c == getch()) { | |
301 | vr = primary(); | |
302 | ||
303 | if (c == '<') | |
304 | vl <<= vr; | |
305 | else | |
306 | vl >>= vr; | |
307 | } | |
308 | ||
309 | if (c == '<' || c == '>') | |
310 | ungetch(); | |
311 | ungetch(); | |
312 | return(vl); | |
313 | } | |
314 | ||
315 | /* | |
316 | * primary : term { addop term } | |
317 | * | |
318 | */ | |
319 | primary() | |
320 | { | |
321 | register int c, vl, vr; | |
322 | ||
323 | vl = term(); | |
324 | while ((c = skipws()) == '+' || c == '-') { | |
325 | vr = term(); | |
326 | if (c == '+') | |
327 | vl += vr; | |
328 | else | |
329 | vl -= vr; | |
330 | } | |
331 | ||
332 | ungetch(); | |
333 | return(vl); | |
334 | } | |
335 | ||
336 | /* | |
337 | * <term> := <unary> { <mulop> <unary> } | |
338 | * | |
339 | */ | |
340 | term() | |
341 | { | |
342 | register int c, vl, vr; | |
343 | ||
344 | vl = unary(); | |
345 | while ((c = skipws()) == '*' || c == '/' || c == '%') { | |
346 | vr = unary(); | |
347 | ||
348 | switch (c) { | |
349 | case '*': | |
350 | vl *= vr; | |
351 | break; | |
352 | case '/': | |
353 | vl /= vr; | |
354 | break; | |
355 | case '%': | |
356 | vl %= vr; | |
357 | break; | |
358 | } | |
359 | } | |
360 | ungetch(); | |
361 | return(vl); | |
362 | } | |
363 | ||
364 | /* | |
365 | * unary : factor | unop unary | |
366 | * | |
367 | */ | |
368 | unary() | |
369 | { | |
370 | register int val, c; | |
371 | ||
372 | if ((c = skipws()) == '!' || c == '~' || c == '-') { | |
373 | val = unary(); | |
374 | ||
375 | switch (c) { | |
376 | case '!': | |
377 | return(! val); | |
378 | case '~': | |
379 | return(~ val); | |
380 | case '-': | |
381 | return(- val); | |
382 | } | |
383 | } | |
384 | ||
385 | ungetch(); | |
386 | return(factor()); | |
387 | } | |
388 | ||
389 | /* | |
390 | * factor : constant | '(' query ')' | |
391 | * | |
392 | */ | |
393 | factor() | |
394 | { | |
395 | register int val; | |
396 | ||
397 | if (skipws() == '(') { | |
398 | val = query(); | |
399 | if (skipws() != ')') | |
400 | experr("Bad factor"); | |
401 | return(val); | |
402 | } | |
403 | ||
404 | ungetch(); | |
405 | return(constant()); | |
406 | } | |
407 | ||
408 | /* | |
409 | * constant: num | 'char' | |
410 | * | |
411 | */ | |
412 | constant() | |
413 | { | |
414 | /* | |
415 | * Note: constant() handles multi-byte constants | |
416 | */ | |
417 | ||
418 | register int i; | |
419 | register int value; | |
420 | register char c; | |
421 | int v[sizeof (int)]; | |
422 | ||
423 | if (skipws() != '\'') { | |
424 | ungetch(); | |
425 | return(num()); | |
426 | } | |
427 | for (i = 0; i < sizeof(int); i++) { | |
428 | if ((c = getch()) == '\'') { | |
429 | ungetch(); | |
430 | break; | |
431 | } | |
432 | if (c == '\\') { | |
433 | switch (c = getch()) { | |
434 | case '0': | |
435 | case '1': | |
436 | case '2': | |
437 | case '3': | |
438 | case '4': | |
439 | case '5': | |
440 | case '6': | |
441 | case '7': | |
442 | ungetch(); | |
443 | c = num(); | |
444 | break; | |
445 | case 'n': | |
446 | c = 012; | |
447 | break; | |
448 | case 'r': | |
449 | c = 015; | |
450 | break; | |
451 | case 't': | |
452 | c = 011; | |
453 | break; | |
454 | case 'b': | |
455 | c = 010; | |
456 | break; | |
457 | case 'f': | |
458 | c = 014; | |
459 | break; | |
460 | } | |
461 | } | |
462 | v[i] = c; | |
463 | } | |
464 | if (i == 0 || getch() != '\'') | |
465 | experr("Illegal character constant"); | |
466 | for (value = 0; --i >= 0;) { | |
467 | value <<= 8; | |
468 | value += v[i]; | |
469 | } | |
470 | return(value); | |
471 | } | |
472 | ||
473 | /* | |
474 | * num : digit | num digit | |
475 | * | |
476 | */ | |
477 | num() | |
478 | { | |
479 | register int rval, c, base; | |
480 | int ndig; | |
481 | ||
482 | base = ((c = skipws()) == '0') ? OCTAL : DECIMAL; | |
483 | rval = 0; | |
484 | ndig = 0; | |
485 | while (c >= '0' && c <= (base == OCTAL ? '7' : '9')) { | |
486 | rval *= base; | |
487 | rval += (c - '0'); | |
488 | c = getch(); | |
489 | ndig++; | |
490 | } | |
491 | ungetch(); | |
492 | if (ndig) | |
493 | return(rval); | |
494 | experr("Bad constant"); | |
495 | } | |
496 | ||
497 | /* | |
498 | * eqlrel : '=' | '==' | '!=' | |
499 | * | |
500 | */ | |
501 | geteql() | |
502 | { | |
503 | register int c1, c2; | |
504 | ||
505 | c1 = skipws(); | |
506 | c2 = getch(); | |
507 | ||
508 | switch (c1) { | |
509 | ||
510 | case '=': | |
511 | if (c2 != '=') | |
512 | ungetch(); | |
513 | return(EQL); | |
514 | ||
515 | case '!': | |
516 | if (c2 == '=') | |
517 | return(NEQ); | |
518 | ungetch(); | |
519 | ungetch(); | |
520 | return(-1); | |
521 | ||
522 | default: | |
523 | ungetch(); | |
524 | ungetch(); | |
525 | return(-1); | |
526 | } | |
527 | } | |
528 | ||
529 | /* | |
530 | * rel : '<' | '>' | '<=' | '>=' | |
531 | * | |
532 | */ | |
533 | getrel() | |
534 | { | |
535 | register int c1, c2; | |
536 | ||
537 | c1 = skipws(); | |
538 | c2 = getch(); | |
539 | ||
540 | switch (c1) { | |
541 | ||
542 | case '<': | |
543 | if (c2 == '=') | |
544 | return(LEQ); | |
545 | ungetch(); | |
546 | return(LSS); | |
547 | ||
548 | case '>': | |
549 | if (c2 == '=') | |
550 | return(GEQ); | |
551 | ungetch(); | |
552 | return(GTR); | |
553 | ||
554 | default: | |
555 | ungetch(); | |
556 | ungetch(); | |
557 | return(-1); | |
558 | } | |
559 | } | |
560 | ||
561 | /* | |
562 | * Skip over any white space and return terminating char. | |
563 | */ | |
564 | skipws() | |
565 | { | |
566 | register char c; | |
567 | ||
568 | while ((c = getch()) <= ' ' && c > EOS) | |
569 | ; | |
570 | return(c); | |
571 | } | |
572 | ||
573 | /* | |
574 | * Error handler - resets environment to eval(), prints an error, | |
575 | * and returns FALSE. | |
576 | */ | |
577 | experr(msg) | |
578 | char *msg; | |
579 | { | |
580 | printf("mp: %s\n",msg); | |
581 | longjmp(expjump, -1); /* Force eval() to return FALSE */ | |
582 | } |