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