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