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