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
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.3.12.1 2002/07/15 02:06:15 jmallett Exp $
42 * $DragonFly: src/usr.bin/m4/expr.c,v 1.3 2004/07/27 21:03:51 dillon Exp $
45 #include <sys/types.h>
54 * expression evaluator: performs a standard recursive
55 * descent parse to evaluate any expression permissible
56 * within the following grammar:
60 * | lor "?" query ":" query
61 * lor : land { "||" land }
62 * land : not { "&&" not }
65 * eqrel : shift { eqrelop shift }
66 * shift : primary { shop primary }
67 * primary : term { addop term }
68 * term : exp { mulop exp }
69 * exp : unary { expop unary }
89 * This expression evaluator is lifted from a public-domain
90 * C Pre-Processor included with the DECUS C Compiler distribution.
91 * It is hacked somewhat to be suitable for m4.
93 * Originally by: Mike Lutz
107 static const char *nxtch; /* Parser scan pointer */
108 static const char *where;
110 static int query(void);
111 static int lor(void);
112 static int land(void);
113 static int not(void);
114 static int eqrel(void);
115 static int shift(void);
116 static int primary(void);
117 static int term(void);
118 static int expx(void);
119 static int unary(void);
120 static int factor(void);
121 static int constant(void);
122 static int num(void);
123 static int geteqrel(void);
124 static int skipws(void);
125 static void experr(const char *);
131 static jmp_buf expjump;
135 * ungetch - Put back the last character examined.
136 * getch - return the next character from expr string.
138 #define ungetch() nxtch--
139 #define getch() *nxtch++
142 expr(const char *expbuf)
148 if (setjmp(expjump) != 0)
155 printf("m4: ill-formed expression.\n");
160 * query : lor | lor '?' query ':' query
165 int result, true_val, false_val;
168 if (skipws() != '?') {
178 return result ? true_val : false_val;
182 * lor : land { '||' land }
190 while ((c = skipws()) == '|') {
202 * land : not { '&&' not }
210 while ((c = skipws()) == '&') {
222 * not : eqrel | '!' not
229 if ((c = skipws()) == '!' && getch() != '=') {
242 * eqrel : shift { eqrelop shift }
250 while ((op = geteqrel()) != -1) {
280 * shift : primary { shop primary }
288 while (((c = skipws()) == '<' || c == '>') && getch() == c) {
297 if (c == '<' || c == '>')
304 * primary : term { addop term }
312 while ((c = skipws()) == '+' || c == '-') {
326 * <term> := <exp> { <mulop> <exp> }
334 while ((c = skipws()) == '*' || c == '/' || c == '%') {
343 errx(1, "division by zero in eval.");
349 errx(1, "modulo zero in eval.");
360 * <term> := <unary> { <expop> <unary> }
368 switch (c = skipws()) {
371 if (getch() != '*') {
389 * unary : factor | unop unary
396 if ((c = skipws()) == '+' || c == '-' || c == '~') {
414 * factor : constant | '(' query ')'
421 if (skipws() == '(') {
424 experr("bad factor");
433 * constant: num | 'char'
434 * Note: constant() handles multi-byte constants
444 if (skipws() != '\'') {
448 for (i = 0; i < (int)sizeof(int); i++) {
449 if ((c = getch()) == '\'') {
454 switch (c = getch()) {
485 if (i == 0 || getch() != '\'')
486 experr("illegal character constant");
487 for (value = 0; --i >= 0;) {
495 * num : digit | num digit
508 if (c == 'x' || c == 'X') {
523 case '0': case '1': case '2': case '3':
524 case '4': case '5': case '6': case '7':
528 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
530 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
533 rval += c - 'a' + 10;
547 experr("bad constant");
553 * eqrel : '=' | '==' | '!=' | '<' | '>' | '<=' | '>='
597 * Skip over any white space and return terminating char.
604 while ((c = getch()) <= ' ' && c > EOS)
610 * resets environment to eval(), prints an error
611 * and forces eval to return FALSE.
614 experr(const char *msg)
616 printf("m4: %s in expr %s.\n", msg, where);
617 longjmp(expjump, -1);