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.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 $
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 : 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 }
73 * | ("+" | "-" | "~" | "!") unary
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.
86 * Originally by: Mike Lutz
100 static const char *nxtch
; /* Parser scan pointer */
101 static const char *where
;
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 geteqrel(int mayeval
);
120 static int skipws(void);
121 static void experr(const char *);
127 static jmp_buf expjump
;
131 * ungetch - Put back the last character examined.
132 * getch - return the next character from expr string.
134 #define ungetch() nxtch--
135 #define getch() *nxtch++
138 expr(const char *expbuf
)
144 if (setjmp(expjump
) != 0)
151 printf("m4: ill-formed expression.\n");
156 * query : lor | lor '?' query ':' query
161 int result
, true_val
, false_val
;
163 result
= lor(mayeval
);
164 if (skipws() != '?') {
169 true_val
= query(result
);
171 experr("bad query: missing \":\"");
173 false_val
= query(!result
);
174 return result
? true_val
: false_val
;
178 * lor : land { '||' land }
186 while ((c
= skipws()) == '|') {
187 if (getch() != '|') {
202 * land : not { '&&' not }
210 while ((c
= skipws()) == '&') {
211 if (getch() != '&') {
226 * bor : xor { "|" xor }
234 while ((c
= skipws()) == '|') {
247 * xor : band { "^" band }
255 while ((c
= skipws()) == '^') {
264 * band : eqrel { "&" eqrel }
272 while ((c
= skipws()) == '&') {
285 * eqrel : nerel { ("==" | "!=" ) nerel }
293 while ((c
= skipws()) == '!' || c
== '=') {
294 if ((cr
= getch()) != '=') {
313 * nerel : shift { ("<=" | ">=" | "<" | ">") shift }
321 while ((c
= skipws()) == '<' || c
== '>') {
322 if ((cr
= getch()) != '=') {
329 vl
= (cr
== '\0') ? (vl
< vr
) : (vl
<= vr
);
332 vl
= (cr
== '\0') ? (vl
> vr
) : (vl
>= vr
);
341 * shift : primary { ("<<" | ">>") primary }
348 vl
= primary(mayeval
);
349 while (((c
= skipws()) == '<' || c
== '>') && getch() == c
) {
350 vr
= primary(mayeval
);
358 if (c
== '<' || c
== '>')
365 * primary : term { ("+" | "-") term }
373 while ((c
= skipws()) == '+' || c
== '-') {
387 * term : exp { ("*" | "/" | "%") exp }
395 while ((c
= skipws()) == '*' || c
== '/' || c
== '%') {
406 errx(1, "division by zero in eval.");
414 errx(1, "modulo zero in eval.");
425 * exp : unary { "**" exp }
433 while ((c
= skipws()) == '*') {
434 if (getch() != '*') {
450 * unary : factor | ("+" | "-" | "~" | "!") unary
457 if ((c
= skipws()) == '+' || c
== '-' || c
== '~' || c
== '!') {
458 val
= unary(mayeval
);
473 return factor(mayeval
);
477 * factor : constant | '(' query ')'
484 if (skipws() == '(') {
485 val
= query(mayeval
);
487 experr("bad factor: missing \")\"");
492 return constant(mayeval
);
496 * constant: num | 'char'
497 * Note: constant() handles multi-byte constants
500 constant(int mayeval
)
507 if (skipws() != '\'') {
511 for (i
= 0; i
< (ssize_t
)sizeof(int); i
++) {
512 if ((c
= getch()) == '\'') {
517 switch (c
= getch()) {
548 if (i
== 0 || getch() != '\'')
549 experr("illegal character constant");
550 for (value
= 0; --i
>= 0;) {
558 * num : digit | num digit
571 if (c
== 'x' || c
== 'X') {
586 case '0': case '1': case '2': case '3':
587 case '4': case '5': case '6': case '7':
591 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
593 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
596 rval
+= c
- 'a' + 10;
610 experr("bad constant");
616 * Skip over any white space and return terminating char.
623 while ((c
= getch()) <= ' ' && c
> EOS
)
629 * resets environment to eval(), prints an error
630 * and forces eval to return FALSE.
633 experr(const char *msg
)
635 printf("m4: %s in expr %s.\n", msg
, where
);
636 longjmp(expjump
, -1);