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: src/usr.bin/m4/expr.c,v 1.3.12.1 2002/07/15 02:06:15 jmallett Exp $");
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 : not { "&&" not }
73 * eqrel : shift { eqrelop shift }
74 * shift : primary { shop primary }
75 * primary : term { addop term }
76 * term : exp { mulop exp }
77 * exp : unary { expop unary }
97 * This expression evaluator is lifted from a public-domain
98 * C Pre-Processor included with the DECUS C Compiler distribution.
99 * It is hacked somewhat to be suitable for m4.
101 * Originally by: Mike Lutz
115 static const char *nxtch; /* Parser scan pointer */
116 static const char *where;
118 static int query(void);
119 static int lor(void);
120 static int land(void);
121 static int not(void);
122 static int eqrel(void);
123 static int shift(void);
124 static int primary(void);
125 static int term(void);
126 static int exp(void);
127 static int unary(void);
128 static int factor(void);
129 static int constant(void);
130 static int num(void);
131 static int geteqrel(void);
132 static int skipws(void);
133 static void experr(const char *);
139 static jmp_buf expjump;
143 * ungetch - Put back the last character examined.
144 * getch - return the next character from expr string.
146 #define ungetch() nxtch--
147 #define getch() *nxtch++
150 expr(const char *expbuf)
156 if (setjmp(expjump) != 0)
163 printf("m4: ill-formed expression.\n");
168 * query : lor | lor '?' query ':' query
173 int result, true_val, false_val;
176 if (skipws() != '?') {
186 return result ? true_val : false_val;
190 * lor : land { '||' land }
198 while ((c = skipws()) == '|') {
210 * land : not { '&&' not }
218 while ((c = skipws()) == '&') {
230 * not : eqrel | '!' not
237 if ((c = skipws()) == '!' && getch() != '=') {
250 * eqrel : shift { eqrelop shift }
258 while ((op = geteqrel()) != -1) {
288 * shift : primary { shop primary }
296 while (((c = skipws()) == '<' || c == '>') && getch() == c) {
305 if (c == '<' || c == '>')
312 * primary : term { addop term }
320 while ((c = skipws()) == '+' || c == '-') {
334 * <term> := <exp> { <mulop> <exp> }
342 while ((c = skipws()) == '*' || c == '/' || c == '%') {
351 errx(1, "division by zero in eval.");
357 errx(1, "modulo zero in eval.");
368 * <term> := <unary> { <expop> <unary> }
376 switch (c = skipws()) {
379 if (getch() != '*') {
397 * unary : factor | unop unary
404 if ((c = skipws()) == '+' || c == '-' || c == '~') {
422 * factor : constant | '(' query ')'
429 if (skipws() == '(') {
432 experr("bad factor");
441 * constant: num | 'char'
442 * Note: constant() handles multi-byte constants
452 if (skipws() != '\'') {
456 for (i = 0; i < (int)sizeof(int); i++) {
457 if ((c = getch()) == '\'') {
462 switch (c = getch()) {
493 if (i == 0 || getch() != '\'')
494 experr("illegal character constant");
495 for (value = 0; --i >= 0;) {
503 * num : digit | num digit
516 if (c == 'x' || c == 'X') {
531 case '0': case '1': case '2': case '3':
532 case '4': case '5': case '6': case '7':
536 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
538 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
541 rval += c - 'a' + 10;
555 experr("bad constant");
561 * eqrel : '=' | '==' | '!=' | '<' | '>' | '<=' | '>='
605 * Skip over any white space and return terminating char.
612 while ((c = getch()) <= ' ' && c > EOS)
618 * resets environment to eval(), prints an error
619 * and forces eval to return FALSE.
622 experr(const char *msg)
624 printf("m4: %s in expr %s.\n", msg, where);
625 longjmp(expjump, -1);