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 $ */
5 * Copyright (c) 1989, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Ozan Yigit at York University.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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
42 static char sccsid[] = "@(#)expr.c 8.2 (Berkeley) 4/29/95";
45 static char rcsid[] = "$OpenBSD: expr.c,v 1.14 2002/04/26 16:15:16 espie Exp $";
50 #include <sys/cdefs.h>
51 __FBSDID("$FreeBSD$");
53 #include <sys/types.h>
62 * expression evaluator: performs a standard recursive
63 * descent parse to evaluate any expression permissible
64 * within the following grammar:
68 * | lor "?" query ":" query
69 * lor : land { "||" land }
70 * land : bor { "&&" bor }
71 * bor : xor { "|" xor }
72 * xor : band { "^" eqrel }
73 * band : eqrel { "&" eqrel }
74 * eqrel : nerel { ("==" | "!=") nerel }
75 * nerel : shift { ("<" | ">" | "<=" | ">=") shift }
76 * shift : primary { ("<<" | ">>") primary }
77 * primary : term { ("+" | "-") term }
78 * term : exp { ("*" | "/" | "%") exp }
79 * exp : unary { "**" unary }
81 * | ("+" | "-" | "~" | "!") unary
90 * This expression evaluator is lifted from a public-domain
91 * C Pre-Processor included with the DECUS C Compiler distribution.
92 * It is hacked somewhat to be suitable for m4.
94 * Originally by: Mike Lutz
108 static const char *nxtch; /* Parser scan pointer */
109 static const char *where;
111 static int query(int mayeval);
112 static int lor(int mayeval);
113 static int land(int mayeval);
114 static int bor(int mayeval);
115 static int xor(int mayeval);
116 static int band(int mayeval);
117 static int eqrel(int mayeval);
118 static int nerel(int mayeval);
119 static int shift(int mayeval);
120 static int primary(int mayeval);
121 static int term(int mayeval);
122 static int exp(int mayeval);
123 static int unary(int mayeval);
124 static int factor(int mayeval);
125 static int constant(int mayeval);
126 static int num(int mayeval);
127 static int geteqrel(int mayeval);
128 static int skipws(void);
129 static void experr(const char *);
135 static jmp_buf expjump;
139 * ungetch - Put back the last character examined.
140 * getch - return the next character from expr string.
142 #define ungetch() nxtch--
143 #define getch() *nxtch++
146 expr(const char *expbuf)
152 if (setjmp(expjump) != 0)
159 printf("m4: ill-formed expression.\n");
164 * query : lor | lor '?' query ':' query
169 int result, true_val, false_val;
171 result = lor(mayeval);
172 if (skipws() != '?') {
177 true_val = query(result);
179 experr("bad query: missing \":\"");
181 false_val = query(!result);
182 return result ? true_val : false_val;
186 * lor : land { '||' land }
194 while ((c = skipws()) == '|') {
195 if (getch() != '|') {
210 * land : not { '&&' not }
218 while ((c = skipws()) == '&') {
219 if (getch() != '&') {
234 * bor : xor { "|" xor }
242 while ((c = skipws()) == '|') {
255 * xor : band { "^" band }
263 while ((c = skipws()) == '^') {
272 * band : eqrel { "&" eqrel }
280 while ((c = skipws()) == '&') {
293 * eqrel : nerel { ("==" | "!=" ) nerel }
301 while ((c = skipws()) == '!' || c == '=') {
302 if ((cr = getch()) != '=') {
321 * nerel : shift { ("<=" | ">=" | "<" | ">") shift }
329 while ((c = skipws()) == '<' || c == '>') {
330 if ((cr = getch()) != '=') {
337 vl = (cr == '\0') ? (vl < vr) : (vl <= vr);
340 vl = (cr == '\0') ? (vl > vr) : (vl >= vr);
349 * shift : primary { ("<<" | ">>") primary }
356 vl = primary(mayeval);
357 while (((c = skipws()) == '<' || c == '>') && getch() == c) {
358 vr = primary(mayeval);
366 if (c == '<' || c == '>')
373 * primary : term { ("+" | "-") term }
381 while ((c = skipws()) == '+' || c == '-') {
395 * term : exp { ("*" | "/" | "%") exp }
403 while ((c = skipws()) == '*' || c == '/' || c == '%') {
414 errx(1, "division by zero in eval.");
422 errx(1, "modulo zero in eval.");
433 * exp : unary { "**" exp }
441 while ((c = skipws()) == '*') {
442 if (getch() != '*') {
458 * unary : factor | ("+" | "-" | "~" | "!") unary
465 if ((c = skipws()) == '+' || c == '-' || c == '~' || c == '!') {
466 val = unary(mayeval);
481 return factor(mayeval);
485 * factor : constant | '(' query ')'
492 if (skipws() == '(') {
493 val = query(mayeval);
495 experr("bad factor: missing \")\"");
500 return constant(mayeval);
504 * constant: num | 'char'
505 * Note: constant() handles multi-byte constants
508 constant(int mayeval)
515 if (skipws() != '\'') {
519 for (i = 0; i < (ssize_t)sizeof(int); i++) {
520 if ((c = getch()) == '\'') {
525 switch (c = getch()) {
556 if (i == 0 || getch() != '\'')
557 experr("illegal character constant");
558 for (value = 0; --i >= 0;) {
566 * num : digit | num digit
579 if (c == 'x' || c == 'X') {
594 case '0': case '1': case '2': case '3':
595 case '4': case '5': case '6': case '7':
599 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
601 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
604 rval += c - 'a' + 10;
618 experr("bad constant");
624 * Skip over any white space and return terminating char.
631 while ((c = getch()) <= ' ' && c > EOS)
637 * resets environment to eval(), prints an error
638 * and forces eval to return FALSE.
641 experr(const char *msg)
643 printf("m4: %s in expr %s.\n", msg, where);
644 longjmp(expjump, -1);