expr.c revision 1.5 1 /*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Ozan Yigit at York University.
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 8.1 (Berkeley) 6/6/93";
39 #endif /* not lint */
40
41 #include <sys/cdefs.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 static int query __P((void));
104 static int lor __P((void));
105 static int land __P((void));
106 static int bor __P((void));
107 static int bxor __P((void));
108 static int band __P((void));
109 static int eql __P((void));
110 static int relat __P((void));
111 static int shift __P((void));
112 static int primary __P((void));
113 static int term __P((void));
114 static int unary __P((void));
115 static int factor __P((void));
116 static int constant __P((void));
117 static int num __P((void));
118 static int geteql __P((void));
119 static int getrel __P((void));
120 static int skipws __P((void));
121 static void experr __P((char *));
122
123 /*
124 * For longjmp
125 */
126 #include <setjmp.h>
127 static jmp_buf expjump;
128
129 /*
130 * macros:
131 * ungetch - Put back the last character examined.
132 * getch - return the next character from expr string.
133 */
134 #define ungetch() nxtch--
135 #define getch() *nxtch++
136
137 int
138 expr(expbuf)
139 char *expbuf;
140 {
141 register int rval;
142
143 nxtch = expbuf;
144 if (setjmp(expjump) != 0)
145 return FALSE;
146
147 rval = query();
148 if (skipws() == EOS)
149 return rval;
150
151 printf("m4: ill-formed expression.\n");
152 return FALSE;
153 }
154
155 /*
156 * query : lor | lor '?' query ':' query
157 */
158 static int
159 query()
160 {
161 register int bool, true_val, false_val;
162
163 bool = lor();
164 if (skipws() != '?') {
165 ungetch();
166 return bool;
167 }
168
169 true_val = query();
170 if (skipws() != ':')
171 experr("bad query");
172
173 false_val = query();
174 return bool ? true_val : false_val;
175 }
176
177 /*
178 * lor : land { '||' land }
179 */
180 static int
181 lor()
182 {
183 register int c, vl, vr;
184
185 vl = land();
186 while ((c = skipws()) == '|' && getch() == '|') {
187 vr = land();
188 vl = vl || vr;
189 }
190
191 if (c == '|')
192 ungetch();
193 ungetch();
194 return vl;
195 }
196
197 /*
198 * land : bor { '&&' bor }
199 */
200 static int
201 land()
202 {
203 register int c, vl, vr;
204
205 vl = bor();
206 while ((c = skipws()) == '&' && getch() == '&') {
207 vr = bor();
208 vl = vl && vr;
209 }
210
211 if (c == '&')
212 ungetch();
213 ungetch();
214 return vl;
215 }
216
217 /*
218 * bor : bxor { '|' bxor }
219 */
220 static int
221 bor()
222 {
223 register int vl, vr, c;
224
225 vl = bxor();
226 while ((c = skipws()) == '|' && getch() != '|') {
227 ungetch();
228 vr = bxor();
229 vl |= vr;
230 }
231
232 if (c == '|')
233 ungetch();
234 ungetch();
235 return vl;
236 }
237
238 /*
239 * bxor : band { '^' band }
240 */
241 static int
242 bxor()
243 {
244 register int vl, vr;
245
246 vl = band();
247 while (skipws() == '^') {
248 vr = band();
249 vl ^= vr;
250 }
251
252 ungetch();
253 return vl;
254 }
255
256 /*
257 * band : eql { '&' eql }
258 */
259 static int
260 band()
261 {
262 register int vl, vr, c;
263
264 vl = eql();
265 while ((c = skipws()) == '&' && getch() != '&') {
266 ungetch();
267 vr = eql();
268 vl &= vr;
269 }
270
271 if (c == '&')
272 ungetch();
273 ungetch();
274 return vl;
275 }
276
277 /*
278 * eql : relat { eqrel relat }
279 */
280 static int
281 eql()
282 {
283 register int vl, vr, rel;
284
285 vl = relat();
286 while ((rel = geteql()) != -1) {
287 vr = relat();
288
289 switch (rel) {
290
291 case EQL:
292 vl = (vl == vr);
293 break;
294 case NEQ:
295 vl = (vl != vr);
296 break;
297 }
298 }
299 return vl;
300 }
301
302 /*
303 * relat : shift { rel shift }
304 */
305 static int
306 relat()
307 {
308 register int vl, vr, rel;
309
310 vl = shift();
311 while ((rel = getrel()) != -1) {
312
313 vr = shift();
314 switch (rel) {
315
316 case LEQ:
317 vl = (vl <= vr);
318 break;
319 case LSS:
320 vl = (vl < vr);
321 break;
322 case GTR:
323 vl = (vl > vr);
324 break;
325 case GEQ:
326 vl = (vl >= vr);
327 break;
328 }
329 }
330 return vl;
331 }
332
333 /*
334 * shift : primary { shop primary }
335 */
336 static int
337 shift()
338 {
339 register int vl, vr, c;
340
341 vl = primary();
342 while (((c = skipws()) == '<' || c == '>') && c == getch()) {
343 vr = primary();
344
345 if (c == '<')
346 vl <<= vr;
347 else
348 vl >>= vr;
349 }
350
351 if (c == '<' || c == '>')
352 ungetch();
353 ungetch();
354 return vl;
355 }
356
357 /*
358 * primary : term { addop term }
359 */
360 static int
361 primary()
362 {
363 register int c, vl, vr;
364
365 vl = term();
366 while ((c = skipws()) == '+' || c == '-') {
367 vr = term();
368 if (c == '+')
369 vl += vr;
370 else
371 vl -= vr;
372 }
373
374 ungetch();
375 return vl;
376 }
377
378 /*
379 * <term> := <unary> { <mulop> <unary> }
380 */
381 static int
382 term()
383 {
384 register int c, vl, vr;
385
386 vl = unary();
387 while ((c = skipws()) == '*' || c == '/' || c == '%') {
388 vr = unary();
389
390 switch (c) {
391 case '*':
392 vl *= vr;
393 break;
394 case '/':
395 vl /= vr;
396 break;
397 case '%':
398 vl %= vr;
399 break;
400 }
401 }
402 ungetch();
403 return vl;
404 }
405
406 /*
407 * unary : factor | unop unary
408 */
409 static int
410 unary()
411 {
412 register int val, c;
413
414 if ((c = skipws()) == '!' || c == '~' || c == '-') {
415 val = unary();
416
417 switch (c) {
418 case '!':
419 return !val;
420 case '~':
421 return ~val;
422 case '-':
423 return -val;
424 }
425 }
426
427 ungetch();
428 return factor();
429 }
430
431 /*
432 * factor : constant | '(' query ')'
433 */
434 static int
435 factor()
436 {
437 register int val;
438
439 if (skipws() == '(') {
440 val = query();
441 if (skipws() != ')')
442 experr("bad factor");
443 return val;
444 }
445
446 ungetch();
447 return constant();
448 }
449
450 /*
451 * constant: num | 'char'
452 * Note: constant() handles multi-byte constants
453 */
454 static int
455 constant()
456 {
457 register int i;
458 register int value;
459 register char c;
460 int v[sizeof(int)];
461
462 if (skipws() != '\'') {
463 ungetch();
464 return num();
465 }
466 for (i = 0; i < sizeof(int); i++) {
467 if ((c = getch()) == '\'') {
468 ungetch();
469 break;
470 }
471 if (c == '\\') {
472 switch (c = getch()) {
473 case '0':
474 case '1':
475 case '2':
476 case '3':
477 case '4':
478 case '5':
479 case '6':
480 case '7':
481 ungetch();
482 c = num();
483 break;
484 case 'n':
485 c = 012;
486 break;
487 case 'r':
488 c = 015;
489 break;
490 case 't':
491 c = 011;
492 break;
493 case 'b':
494 c = 010;
495 break;
496 case 'f':
497 c = 014;
498 break;
499 }
500 }
501 v[i] = c;
502 }
503 if (i == 0 || getch() != '\'')
504 experr("illegal character constant");
505 for (value = 0; --i >= 0;) {
506 value <<= 8;
507 value += v[i];
508 }
509 return value;
510 }
511
512 /*
513 * num : digit | num digit
514 */
515 static int
516 num()
517 {
518 register int rval, c, base;
519 int ndig;
520
521 base = ((c = skipws()) == '0') ? OCTAL : DECIMAL;
522 rval = 0;
523 ndig = 0;
524 while (c >= '0' && c <= (base == OCTAL ? '7' : '9')) {
525 rval *= base;
526 rval += (c - '0');
527 c = getch();
528 ndig++;
529 }
530 ungetch();
531
532 if (ndig == 0)
533 experr("bad constant");
534
535 return rval;
536
537 }
538
539 /*
540 * eqlrel : '=' | '==' | '!='
541 */
542 static int
543 geteql()
544 {
545 register int c1, c2;
546
547 c1 = skipws();
548 c2 = getch();
549
550 switch (c1) {
551
552 case '=':
553 if (c2 != '=')
554 ungetch();
555 return EQL;
556
557 case '!':
558 if (c2 == '=')
559 return NEQ;
560 ungetch();
561 ungetch();
562 return -1;
563
564 default:
565 ungetch();
566 ungetch();
567 return -1;
568 }
569 }
570
571 /*
572 * rel : '<' | '>' | '<=' | '>='
573 */
574 static int
575 getrel()
576 {
577 register int c1, c2;
578
579 c1 = skipws();
580 c2 = getch();
581
582 switch (c1) {
583
584 case '<':
585 if (c2 == '=')
586 return LEQ;
587 ungetch();
588 return LSS;
589
590 case '>':
591 if (c2 == '=')
592 return GEQ;
593 ungetch();
594 return GTR;
595
596 default:
597 ungetch();
598 ungetch();
599 return -1;
600 }
601 }
602
603 /*
604 * Skip over any white space and return terminating char.
605 */
606 static int
607 skipws()
608 {
609 register char c;
610
611 while ((c = getch()) <= ' ' && c > EOS)
612 ;
613 return c;
614 }
615
616 /*
617 * resets environment to eval(), prints an error
618 * and forces eval to return FALSE.
619 */
620 static void
621 experr(msg)
622 char *msg;
623 {
624 printf("m4: %s in expr.\n", msg);
625 longjmp(expjump, -1);
626 }
627