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
expr(expbuf)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
query()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
lor()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
land()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
not()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
eqrel()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
shift()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
primary()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
term()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
exp()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
unary()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
factor()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
constant()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
num()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
geteqrel()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
skipws()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
experr(msg)543 experr(msg)
544 char *msg;
545 {
546 printf("m4: %s in expr.\n", msg);
547 longjmp(expjump, -1);
548 }
549