forget difference between big and small commands - obsolete with vm.
[minix.git] / commands / m4 / expr.c
blob668bb623a5b5ada74776eb5836f3c621bec0b23d
1 /*
2 * expression evaluator: performs a standard recursive
3 * descent parse to evaluate any expression permissible
4 * within the following grammar:
6 * expr : query EOS
7 * query : lor
8 * | lor "?" query ":" query
9 * lor : land { "||" land }
10 * land : bor { "&&" bor }
11 * bor : bxor { "|" bxor }
12 * bxor : band { "^" band }
13 * band : eql { "&" eql }
14 * eql : relat { eqrel relat }
15 * relat : shift { rel shift }
16 * shift : primary { shop primary }
17 * primary : term { addop term }
18 * term : unary { mulop unary }
19 * unary : factor
20 * | unop unary
21 * factor : constant
22 * | "(" query ")"
23 * constant: num
24 * | "'" CHAR "'"
25 * num : decnum
26 * | "0" octnum
27 * | "0x" hexnum
28 * octnum : OCTDIGIT
29 * | OCTDIGIT octnum
30 * decnum : DECDIGIT
31 * | DECDIGIT decnum
32 * hexnum : HEXDIGIT
33 * | HEXDIGIT hexnum
34 * shop : "<<"
35 * | ">>"
36 * eqlrel : "="
37 * | "=="
38 * | "!="
39 * rel : "<"
40 * | ">"
41 * | "<="
42 * | ">="
45 * This expression evaluator is lifted from a public-domain
46 * C Pre-Processor included with the DECUS C Compiler distribution.
47 * It is hacked somewhat to be suitable for m4.
49 * Originally by: Mike Lutz
50 * Bob Harper
53 #include "mdef.h"
55 #define TRUE 1
56 #define FALSE 0
57 #define EOS (char) 0
58 #define EQL 0
59 #define NEQ 1
60 #define LSS 2
61 #define LEQ 3
62 #define GTR 4
63 #define GEQ 5
65 static char *nxtch; /* Parser scan pointer */
68 * For longjmp
70 #include <setjmp.h>
71 static jmp_buf expjump;
74 * macros:
76 * ungetch - Put back the last character examined.
77 * getch - return the next character from expr string.
79 #define ungetch() nxtch--
80 #define getch() *nxtch++
82 int expr(expbuf)
83 char *expbuf;
85 register int rval;
87 nxtch = expbuf;
88 if (setjmp(expjump) != 0)
89 return (FALSE);
90 rval = query();
91 if (skipws() == EOS)
92 return(rval);
93 experr("Ill-formed expression");
94 /* NOTREACHED */
95 return(0);
99 * query : lor | lor '?' query ':' query
102 int query()
104 register int bool, true_val, false_val;
106 bool = lor();
107 if (skipws() != '?') {
108 ungetch();
109 return(bool);
112 true_val = query();
113 if (skipws() != ':')
114 experr("Bad query");
116 false_val = query();
117 return(bool ? true_val : false_val);
121 * lor : land { '||' land }
124 int lor()
126 register int c, vl, vr;
128 vl = land();
129 while ((c = skipws()) == '|' && getch() == '|') {
130 vr = land();
131 vl = vl || vr;
134 if (c == '|')
135 ungetch();
136 ungetch();
137 return(vl);
141 * land : bor { '&&' bor }
144 int land()
146 register int c, vl, vr;
148 vl = bor();
149 while ((c = skipws()) == '&' && getch() == '&') {
150 vr = bor();
151 vl = vl && vr;
154 if (c == '&')
155 ungetch();
156 ungetch();
157 return(vl);
161 * bor : bxor { '|' bxor }
164 int bor()
166 register int vl, vr, c;
168 vl = bxor();
169 while ((c = skipws()) == '|' && getch() != '|') {
170 ungetch();
171 vr = bxor();
172 vl |= vr;
175 if (c == '|')
176 ungetch();
177 ungetch();
178 return(vl);
182 * bxor : band { '^' band }
185 int bxor()
187 register int vl, vr;
189 vl = band();
190 while (skipws() == '^') {
191 vr = band();
192 vl ^= vr;
195 ungetch();
196 return(vl);
200 * band : eql { '&' eql }
203 int band()
205 register int vl, vr, c;
207 vl = eql();
208 while ((c = skipws()) == '&' && getch() != '&') {
209 ungetch();
210 vr = eql();
211 vl &= vr;
214 if (c == '&')
215 ungetch();
216 ungetch();
217 return(vl);
221 * eql : relat { eqrel relat }
224 int eql()
226 register int vl, vr, rel;
228 vl = relat();
229 while ((rel = geteql()) != -1) {
230 vr = relat();
232 switch (rel) {
234 case EQL:
235 vl = (vl == vr);
236 break;
237 case NEQ:
238 vl = (vl != vr);
239 break;
242 return(vl);
246 * relat : shift { rel shift }
249 int relat()
251 register int vl, vr, rel;
253 vl = shift();
254 while ((rel = getrel()) != -1) {
256 vr = shift();
257 switch (rel) {
259 case LEQ:
260 vl = (vl <= vr);
261 break;
262 case LSS:
263 vl = (vl < vr);
264 break;
265 case GTR:
266 vl = (vl > vr);
267 break;
268 case GEQ:
269 vl = (vl >= vr);
270 break;
273 return(vl);
277 * shift : primary { shop primary }
280 int shift()
282 register int vl, vr, c;
284 vl = primary();
285 while (((c = skipws()) == '<' || c == '>') && c == getch()) {
286 vr = primary();
288 if (c == '<')
289 vl <<= vr;
290 else
291 vl >>= vr;
294 if (c == '<' || c == '>')
295 ungetch();
296 ungetch();
297 return(vl);
301 * primary : term { addop term }
304 int primary()
306 register int c, vl, vr;
308 vl = term();
309 while ((c = skipws()) == '+' || c == '-') {
310 vr = term();
311 if (c == '+')
312 vl += vr;
313 else
314 vl -= vr;
317 ungetch();
318 return(vl);
322 * <term> := <unary> { <mulop> <unary> }
325 int term()
327 register int c, vl, vr;
329 vl = unary();
330 while ((c = skipws()) == '*' || c == '/' || c == '%') {
331 vr = unary();
333 switch (c) {
334 case '*':
335 vl *= vr;
336 break;
337 case '/':
338 vl /= vr;
339 break;
340 case '%':
341 vl %= vr;
342 break;
345 ungetch();
346 return(vl);
350 * unary : factor | unop unary
353 int unary()
355 register int val, c;
357 if ((c = skipws()) == '!' || c == '~' || c == '-') {
358 val = unary();
360 switch (c) {
361 case '!':
362 return(! val);
363 case '~':
364 return(~ val);
365 case '-':
366 return(- val);
370 ungetch();
371 return(factor());
375 * factor : constant | '(' query ')'
378 int factor()
380 register int val;
382 if (skipws() == '(') {
383 val = query();
384 if (skipws() != ')')
385 experr("Bad factor");
386 return(val);
389 ungetch();
390 return(constant());
394 * constant: num | 'char'
397 int constant()
400 * Note: constant() handles multi-byte constants
403 register int i;
404 register int value;
405 register char c;
406 int v[sizeof (int)];
408 if (skipws() != '\'') {
409 ungetch();
410 return(num());
412 for (i = 0; i < sizeof(int); i++) {
413 if ((c = getch()) == '\'') {
414 ungetch();
415 break;
417 if (c == '\\') {
418 switch (c = getch()) {
419 case '0':
420 case '1':
421 case '2':
422 case '3':
423 case '4':
424 case '5':
425 case '6':
426 case '7':
427 ungetch();
428 c = num();
429 break;
430 case 'n':
431 c = 012;
432 break;
433 case 'r':
434 c = 015;
435 break;
436 case 't':
437 c = 011;
438 break;
439 case 'b':
440 c = 010;
441 break;
442 case 'f':
443 c = 014;
444 break;
447 v[i] = c;
449 if (i == 0 || getch() != '\'')
450 experr("Illegal character constant");
451 for (value = 0; --i >= 0;) {
452 value <<= 8;
453 value += v[i];
455 return(value);
459 * num : digit | num digit
462 int num()
464 register int rval, c, base;
465 int ndig;
467 ndig = 0;
468 if ((c = skipws()) == '0') {
469 c = getch ();
470 if (c == 'x' || c == 'X') {
471 base = 16;
472 c = getch ();
473 } else {
474 base = 8;
475 ndig = 1;
477 } else {
478 base = 10;
480 rval = 0;
481 for (;;) {
482 if (isdigit(c)) c -= '0';
483 else if (isupper (c)) c -= ('A' - 10);
484 else if (islower (c)) c -= ('a' - 10);
485 else break;
486 if (c < 0 || c >= base)
487 break;
489 rval *= base;
490 rval += c;
491 c = getch();
492 ndig++;
494 ungetch();
495 if (ndig)
496 return(rval);
497 experr("Bad constant");
498 /* NOTREACHED */
499 return(0);
503 * eqlrel : '=' | '==' | '!='
506 int geteql()
508 register int c1, c2;
510 c1 = skipws();
511 c2 = getch();
513 switch (c1) {
515 case '=':
516 if (c2 != '=')
517 ungetch();
518 return(EQL);
520 case '!':
521 if (c2 == '=')
522 return(NEQ);
523 ungetch();
524 ungetch();
525 return(-1);
527 default:
528 ungetch();
529 ungetch();
530 return(-1);
535 * rel : '<' | '>' | '<=' | '>='
538 int getrel()
540 register int c1, c2;
542 c1 = skipws();
543 c2 = getch();
545 switch (c1) {
547 case '<':
548 if (c2 == '=')
549 return(LEQ);
550 ungetch();
551 return(LSS);
553 case '>':
554 if (c2 == '=')
555 return(GEQ);
556 ungetch();
557 return(GTR);
559 default:
560 ungetch();
561 ungetch();
562 return(-1);
567 * Skip over any white space and return terminating char.
569 int skipws()
571 register char c;
573 while ((c = getch()) <= ' ' && c > EOS)
575 return(c);
579 * Error handler - resets environment to eval(), prints an error,
580 * and returns FALSE.
582 int experr(msg)
583 char *msg;
585 printf("mp: %s\n",msg);
586 longjmp(expjump, -1); /* Force eval() to return FALSE */