Merge branch 'vendor/LIBPCAP'
[dragonfly.git] / usr.bin / m4 / expr.c
1 /*      $OpenBSD: expr.c,v 1.14 2002/04/26 16:15:16 espie Exp $ */
2 /*      $NetBSD: expr.c,v 1.7 1995/09/28 05:37:31 tls Exp $     */
3
4 /*
5  * Copyright (c) 1989, 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Ozan Yigit at York University.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *      This product includes software developed by the University of
22  *      California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  * @(#)expr.c   8.2 (Berkeley) 4/29/95
40  * $OpenBSD: expr.c,v 1.14 2002/04/26 16:15:16 espie Exp $
41  * $FreeBSD: src/usr.bin/m4/expr.c,v 1.14 2004/05/01 03:59:43 smkelly Exp $
42  * $DragonFly: src/usr.bin/m4/expr.c,v 1.4 2006/12/27 21:29:02 pavalos Exp $
43  */
44
45 #include <sys/types.h>
46 #include <ctype.h>
47 #include <err.h>
48 #include <stddef.h>
49 #include <stdio.h>
50 #include "mdef.h"
51 #include "extern.h"
52
53 /*
54  *      expression evaluator: performs a standard recursive
55  *      descent parse to evaluate any expression permissible
56  *      within the following grammar:
57  *
58  *      expr    :       query EOS
59  *      query   :       lor
60  *              |       lor "?" query ":" query
61  *      lor     :       land { "||" land }
62  *      land    :       bor { "&&" bor }
63  *      bor     :       xor { "|" xor }
64  *      xor     :       band { "^" eqrel }
65  *      band    :       eqrel { "&" eqrel }
66  *      eqrel   :       nerel { ("==" | "!=") nerel }
67  *      nerel   :       shift { ("<" | ">" | "<=" | ">=") shift }
68  *      shift   :       primary { ("<<" | ">>") primary }
69  *      primary :       term { ("+" | "-") term }
70  *      term    :       exp { ("*" | "/" | "%") exp }
71  *      exp     :       unary { "**" unary }
72  *      unary   :       factor
73  *              |       ("+" | "-" | "~" | "!") unary
74  *      factor  :       constant
75  *              |       "(" query ")"
76  *      constant:       num
77  *              |       "'" CHAR "'"
78  *      num     :       DIGIT
79  *              |       DIGIT num
80  *
81  *
82  *      This expression evaluator is lifted from a public-domain
83  *      C Pre-Processor included with the DECUS C Compiler distribution.
84  *      It is hacked somewhat to be suitable for m4.
85  *
86  *      Originally by:  Mike Lutz
87  *                      Bob Harper
88  */
89
90 #define EQL     0
91 #define NEQ     1
92 #define LSS     2
93 #define LEQ     3
94 #define GTR     4
95 #define GEQ     5
96 #define OCTAL   8
97 #define DECIMAL 10
98 #define HEX     16
99
100 static const char *nxtch;                      /* Parser scan pointer */
101 static const char *where;
102
103 static int query(int mayeval);
104 static int lor(int mayeval);
105 static int land(int mayeval);
106 static int bor(int mayeval);
107 static int xor(int mayeval);
108 static int band(int mayeval);
109 static int eqrel(int mayeval);
110 static int nerel(int mayeval);
111 static int shift(int mayeval);
112 static int primary(int mayeval);
113 static int term(int mayeval);
114 static int expx(int mayeval);
115 static int unary(int mayeval);
116 static int factor(int mayeval);
117 static int constant(int mayeval);
118 static int num(int mayeval);
119 static int skipws(void);
120 static void experr(const char *);
121
122 /*
123  * For longjmp
124  */
125 #include <setjmp.h>
126 static jmp_buf expjump;
127
128 /*
129  * macros:
130  *      ungetch - Put back the last character examined.
131  *      getch   - return the next character from expr string.
132  */
133 #define ungetch()       nxtch--
134 #define getch()         *nxtch++
135
136 int
137 expr(const char *expbuf)
138 {
139         int rval;
140
141         nxtch = expbuf;
142         where = expbuf;
143         if (setjmp(expjump) != 0)
144                 return FALSE;
145
146         rval = query(1);
147         if (skipws() == EOS)
148                 return rval;
149
150         printf("m4: ill-formed expression.\n");
151         return FALSE;
152 }
153
154 /*
155  * query : lor | lor '?' query ':' query
156  */
157 static int
158 query(int mayeval)
159 {
160         int result, true_val, false_val;
161
162         result = lor(mayeval);
163         if (skipws() != '?') {
164                 ungetch();
165                 return result;
166         }
167
168         true_val = query(result);
169         if (skipws() != ':')
170                 experr("bad query: missing \":\"");
171
172         false_val = query(!result);
173         return result ? true_val : false_val;
174 }
175
176 /*
177  * lor : land { '||' land }
178  */
179 static int
180 lor(int mayeval)
181 {
182         int c, vl, vr;
183
184         vl = land(mayeval);
185         while ((c = skipws()) == '|') {
186                 if (getch() != '|') {
187                         ungetch();
188                         break;
189                 }
190                 if (vl != 0)
191                         mayeval = 0;
192                 vr = land(mayeval);
193                 vl = vl || vr;
194         }
195
196         ungetch();
197         return vl;
198 }
199
200 /*
201  * land : not { '&&' not }
202  */
203 static int
204 land(int mayeval)
205 {
206         int c, vl, vr;
207
208         vl = bor(mayeval);
209         while ((c = skipws()) == '&') {
210                 if (getch() != '&') {
211                         ungetch();
212                         break;
213                 }
214                 if (vl == 0)
215                         mayeval = 0;
216                 vr = bor(mayeval);
217                 vl = vl && vr;
218         }
219
220         ungetch();
221         return vl;
222 }
223
224 /*
225  * bor : xor { "|" xor }
226  */
227 static int
228 bor(int mayeval)
229 {
230         int vl, vr, c, cr;
231
232         vl = xor(mayeval);
233         while ((c = skipws()) == '|') {
234                 cr = getch();
235                 ungetch();
236                 if (cr == '|')
237                         break;
238                 vr = xor(mayeval);
239                 vl |= vr;
240         }
241         ungetch();
242         return (vl);
243 }
244
245 /*
246  * xor : band { "^" band }
247  */
248 static int
249 xor(int mayeval)
250 {
251         int vl, vr, c;
252
253         vl = band(mayeval);
254         while ((c = skipws()) == '^') {
255                 vr = band(mayeval);
256                 vl ^= vr;
257         }
258         ungetch();
259         return (vl);
260 }
261
262 /*
263  * band : eqrel { "&" eqrel }
264  */
265 static int
266 band(int mayeval)
267 {
268         int c, cr, vl, vr;
269
270         vl = eqrel(mayeval);
271         while ((c = skipws()) == '&') {
272                 cr = getch();
273                 ungetch();
274                 if (cr == '&')
275                         break;
276                 vr = eqrel(mayeval);
277                 vl &= vr;
278         }
279         ungetch();
280         return vl;
281 }
282
283 /*
284  * eqrel : nerel { ("==" | "!=" ) nerel }
285  */
286 static int
287 eqrel(int mayeval)
288 {
289         int vl, vr, c, cr;
290
291         vl = nerel(mayeval);
292         while ((c = skipws()) == '!' || c == '=') {
293                 if ((cr = getch()) != '=') {
294                         ungetch();
295                         break;
296                 }
297                 vr = nerel(mayeval);
298                 switch (c) {
299                 case '=':
300                         vl = (vl == vr);
301                         break;
302                 case '!':
303                         vl = (vl != vr);
304                         break;
305                 }
306         }
307         ungetch();
308         return vl;
309 }
310
311 /*
312  * nerel : shift { ("<=" | ">=" | "<" | ">") shift }
313  */
314 static int
315 nerel(int mayeval)
316 {
317         int vl, vr, c, cr;
318
319         vl = shift(mayeval);
320         while ((c = skipws()) == '<' || c == '>') {
321                 if ((cr = getch()) != '=') {
322                         ungetch();
323                         cr = '\0';
324                 }
325                 vr = shift(mayeval);
326                 switch (c) {
327                 case '<':
328                         vl = (cr == '\0') ? (vl < vr) : (vl <= vr);
329                         break;
330                 case '>':
331                         vl = (cr == '\0') ? (vl > vr) : (vl >= vr);
332                         break;
333                 }
334         }
335         ungetch();
336         return vl;
337 }
338
339 /*
340  * shift : primary { ("<<" | ">>") primary }
341  */
342 static int
343 shift(int mayeval)
344 {
345         int vl, vr, c;
346
347         vl = primary(mayeval);
348         while (((c = skipws()) == '<' || c == '>') && getch() == c) {
349                 vr = primary(mayeval);
350
351                 if (c == '<')
352                         vl <<= vr;
353                 else
354                         vl >>= vr;
355         }
356
357         if (c == '<' || c == '>')
358                 ungetch();
359         ungetch();
360         return vl;
361 }
362
363 /*
364  * primary : term { ("+" | "-") term }
365  */
366 static int
367 primary(int mayeval)
368 {
369         int c, vl, vr;
370
371         vl = term(mayeval);
372         while ((c = skipws()) == '+' || c == '-') {
373                 vr = term(mayeval);
374
375                 if (c == '+')
376                         vl += vr;
377                 else
378                         vl -= vr;
379         }
380
381         ungetch();
382         return vl;
383 }
384
385 /*
386  * term : exp { ("*" | "/" | "%") exp }
387  */
388 static int
389 term(int mayeval)
390 {
391         int c, vl, vr;
392
393         vl = expx(mayeval);
394         while ((c = skipws()) == '*' || c == '/' || c == '%') {
395                 vr = expx(mayeval);
396
397                 switch (c) {
398                 case '*':
399                         vl *= vr;
400                         break;
401                 case '/':
402                         if (!mayeval)
403                                 /* short-circuit */;
404                         else if (vr == 0)
405                                 errx(1, "division by zero in eval.");
406                         else
407                                 vl /= vr;
408                         break;
409                 case '%':
410                         if (!mayeval)
411                                 /* short-circuit */;
412                         else if (vr == 0)
413                                 errx(1, "modulo zero in eval.");
414                         else
415                                 vl %= vr;
416                         break;
417                 }
418         }
419         ungetch();
420         return vl;
421 }
422
423 /*
424  * exp : unary { "**" exp }
425  */
426 static int
427 expx(int mayeval)
428 {
429         int c, vl, vr, n;
430
431         vl = unary(mayeval);
432         while ((c = skipws()) == '*') {
433                 if (getch() != '*') {
434                         ungetch();
435                         break;
436                 }
437                 vr = unary(mayeval);
438                 n = 1;
439                 while (vr-- > 0)
440                         n *= vl;
441                 return n;
442         }
443
444         ungetch();
445         return vl;
446 }
447
448 /*
449  * unary : factor | ("+" | "-" | "~" | "!") unary
450  */
451 static int
452 unary(int mayeval)
453 {
454         int val, c;
455
456         if ((c = skipws()) == '+' || c == '-' || c == '~' || c == '!') {
457                 val = unary(mayeval);
458
459                 switch (c) {
460                 case '+':
461                         return val;
462                 case '-':
463                         return -val;
464                 case '~':
465                         return ~val;
466                 case '!':
467                         return !val;
468                 }
469         }
470
471         ungetch();
472         return factor(mayeval);
473 }
474
475 /*
476  * factor : constant | '(' query ')'
477  */
478 static int
479 factor(int mayeval)
480 {
481         int val;
482
483         if (skipws() == '(') {
484                 val = query(mayeval);
485                 if (skipws() != ')')
486                         experr("bad factor: missing \")\"");
487                 return val;
488         }
489
490         ungetch();
491         return constant(mayeval);
492 }
493
494 /*
495  * constant: num | 'char'
496  * Note: constant() handles multi-byte constants
497  */
498 static int
499 constant(int mayeval)
500 {
501         int i;
502         int value;
503         int c;
504         int v[sizeof(int)];
505
506         if (skipws() != '\'') {
507                 ungetch();
508                 return num(mayeval);
509         }
510         for (i = 0; i < (ssize_t)sizeof(int); i++) {
511                 if ((c = getch()) == '\'') {
512                         ungetch();
513                         break;
514                 }
515                 if (c == '\\') {
516                         switch (c = getch()) {
517                         case '0':
518                         case '1':
519                         case '2':
520                         case '3':
521                         case '4':
522                         case '5':
523                         case '6':
524                         case '7':
525                                 ungetch();
526                                 c = num(mayeval);
527                                 break;
528                         case 'n':
529                                 c = 012;
530                                 break;
531                         case 'r':
532                                 c = 015;
533                                 break;
534                         case 't':
535                                 c = 011;
536                                 break;
537                         case 'b':
538                                 c = 010;
539                                 break;
540                         case 'f':
541                                 c = 014;
542                                 break;
543                         }
544                 }
545                 v[i] = c;
546         }
547         if (i == 0 || getch() != '\'')
548                 experr("illegal character constant");
549         for (value = 0; --i >= 0;) {
550                 value <<= 8;
551                 value += v[i];
552         }
553         return value;
554 }
555
556 /*
557  * num : digit | num digit
558  */
559 static int
560 num(int mayeval __unused)
561 {
562         int rval, c, base;
563         int ndig;
564
565         rval = 0;
566         ndig = 0;
567         c = skipws();
568         if (c == '0') {
569                 c = skipws();
570                 if (c == 'x' || c == 'X') {
571                         base = HEX;
572                         c = skipws();
573                 } else {
574                         base = OCTAL;
575                         ndig++;
576                 }
577         } else
578                 base = DECIMAL;
579         for(;;) {
580                 switch(c) {
581                         case '8': case '9':
582                                 if (base == OCTAL)
583                                         goto bad_digit;
584                                 /*FALLTHRU*/
585                         case '0': case '1': case '2': case '3':
586                         case '4': case '5': case '6': case '7':
587                                 rval *= base;
588                                 rval += c - '0';
589                                 break;
590                         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
591                                 c = tolower(c);
592                         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
593                                 if (base == HEX) {
594                                         rval *= base;
595                                         rval += c - 'a' + 10;
596                                         break;
597                                 }
598                                 /*FALLTHRU*/
599                         default:
600                                 goto bad_digit;
601                 }
602                 c = getch();
603                 ndig++;
604         }
605 bad_digit:
606         ungetch();
607
608         if (ndig == 0)
609                 experr("bad constant");
610
611         return rval;
612 }
613
614 /*
615  * Skip over any white space and return terminating char.
616  */
617 static int
618 skipws(void)
619 {
620         int c;
621
622         while ((c = getch()) <= ' ' && c > EOS)
623                 ;
624         return c;
625 }
626
627 /*
628  * resets environment to eval(), prints an error
629  * and forces eval to return FALSE.
630  */
631 static void
632 experr(const char *msg)
633 {
634         printf("m4: %s in expr %s.\n", msg, where);
635         longjmp(expjump, -1);
636 }