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