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