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