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