Home | History | Annotate | Line # | Download | only in m4
expr.c revision 1.2
      1 /*  File   : expr.c
      2     Authors: Mike Lutz & Bob Harper
      3     Editors: Ozan Yigit & Richard A. O'Keefe
      4     Updated: %G%
      5     Purpose: arithmetic expression evaluator.
      6 
      7     expr() performs a standard recursive descent parse to evaluate any
      8     expression permitted byf the following grammar:
      9 
     10       expr    :       query EOS
     11       query   :       lor
     12               |       lor "?" query ":" query
     13       lor     :       land { "||" land }	or OR,  for Pascal
     14       land    :       bor { "&&" bor }		or AND, for Pascal
     15       bor     :       bxor { "|" bxor }
     16       bxor    :       band { "^" band }
     17       band    :       eql { "&" eql }
     18       eql     :       relat { eqrel relat }
     19       relat   :       shift { rel shift }
     20       shift   :       primary { shop primary }
     21       primary :       term { addop term }
     22       term    :       unary { mulop unary }
     23       unary   :       factor
     24               |       unop unary
     25       factor  :       constant
     26               |       "(" query ")"
     27       constant:       num
     28               |       "'" CHAR "'"		or '"' CHAR '"'
     29       num     :       DIGIT			full ANSI C syntax
     30               |       DIGIT num
     31       shop    :       "<<"
     32               |       ">>"
     33       eqlrel  :       "="
     34               |       "=="
     35               |       "!="
     36       rel     :       "<"			or <>, Pascal not-equal
     37               |       ">"
     38               |       "<="			or =<, for Prolog users.
     39               |       ">="
     40 
     41     This expression evaluator was lifted from a public-domain
     42     C Pre-Processor included with the DECUS C Compiler distribution.
     43     It has been hacked somewhat to be suitable for m4.
     44 
     45     26-Mar-1993		Changed to work in any of EBCDIC, ASCII, DEC MNCS,
     46 			or ISO 8859/n.
     47 
     48     26-Mar-1993		Changed to use "long int" rather than int, so that
     49 			we get the same 32-bit arithmetic on a PC as on a Sun.
     50 			It isn't fully portable, of course, but then on a 64-
     51 			bit machine we _want_ 64-bit arithmetic...
     52 			Shifting rewritten (using LONG_BIT) to give signed
     53 			shifts even when (long) >> (long) is unsigned.
     54 
     55     26-Mar-1993		I finally got sick of the fact that &&, ||, and ?:
     56 			don't do conditional evaluation.  What is the good
     57 			of having eval(0&&(1/0)) crash and dump core?  Now
     58 			every function has a doit? argument.
     59 
     60     26-Mar-1993		charcon() didn't actually accept 'abcd', which it
     61 			should have.  Fixed it.
     62 
     63     20-Apr-1993		eval(1/0) and eval(1%0) dumped core and crashed.
     64 			This is also true of the System V r 3.2 m4, but
     65 			it isn't good enough for ours!  Changed it so that
     66 			x % 0 => x	as per Concrete Mathematics
     67 			x / 0 => error and return 0 from expr().
     68 */
     69 
     70 #define FALSE   0
     71 #define	TRUE	1
     72 
     73 #include <stdio.h>
     74 #include <setjmp.h>
     75 static jmp_buf expjump;		/* Error exit point for expr() */
     76 
     77 static unsigned char *nxtchr;	/* Parser scan pointer */
     78 
     79 #define	deblank0	while ((unsigned)(*nxtchr-1) < ' ') nxtchr++
     80 #define deblank1	while ((unsigned)(*++nxtchr - 1) < ' ')
     81 #define deblank2	nxtchr++; deblank1
     82 
     83 #include "ourlims.h"
     84 static char digval[1+UCHAR_MAX];
     85 
     86 /*  This file should work in any C implementation that doesn't have too
     87     many characters to fit in one table.  We use a table to convert
     88     (unsigned) characters to numeric codes:
     89 	 0 to  9	for '0' to '9'
     90 	10 to 35	for 'a' to 'z'
     91 	10 to 35	for 'A' to 'Z'
     92 	36		for '_'
     93     Instead of asking whether tolower(c) == 'a' we ask whether
     94     digval[c] == DIGIT_A, and so on.  This essentially duplicates the
     95     chtype[] table in main.c; we should use just one table.
     96 */
     97 #define	DIGIT_A 10
     98 #define	DIGIT_B 11
     99 #define	DIGIT_C 12
    100 #define	DIGIT_D 13
    101 #define	DIGIT_E 14
    102 #define	DIGIT_F 15
    103 #define	DIGIT_G 16
    104 #define DIGIT_H 17
    105 #define	DIGIT_I	18
    106 #define	DIGIT_J 19
    107 #define DIGIT_K 20
    108 #define	DIGIT_L	21
    109 #define DIGIT_M 22
    110 #define DIGIT_N 23
    111 #define	DIGIT_O 24
    112 #define	DIGIT_P 25
    113 #define	DIGIT_Q 26
    114 #define	DIGIT_R	27
    115 #define	DIGIT_S 28
    116 #define	DIGIT_T 29
    117 #define	DIGIT_U 30
    118 #define	DIGIT_V 31
    119 #define	DIGIT_W 32
    120 #define	DIGIT_X 33
    121 #define	DIGIT_Y 34
    122 #define	DIGIT_Z 35
    123 
    124 
    125 #ifdef	__STDC__
    126 static long int query(int);
    127 #else
    128 static long int query();
    129 #endif
    130 
    131 
    132 /*  experr(msg)
    133     prints an error message, resets environment to expr(), and
    134     forces expr() to return FALSE.
    135 */
    136 void experr(msg)
    137     char *msg;
    138     {
    139 	(void) fprintf(stderr, "m4: %s\n", msg);
    140 	longjmp(expjump, -1);	/* Force expr() to return FALSE */
    141     }
    142 
    143 
    144 /*  <numcon> ::= '0x' <hex> | '0X' <hex> | '0' <oct> | <dec>
    145     For ANSI C, an integer may be followed by u, l, ul, or lu,
    146     in any mix of cases.  We accept and ignore those letters;
    147     all the numbers are treated as long.
    148 */
    149 static long int numcon(doit)
    150     int doit;
    151     {
    152 	register long int v;	/* current value */
    153 	register int b;		/* base (radix) */
    154 	register int c;		/* character or digit value */
    155 
    156 	if (!doit) {
    157 	    do nxtchr++; while (digval[*nxtchr] <= 36);
    158 	    deblank0;
    159 	    return 0;
    160 	}
    161 
    162 	v = digval[*nxtchr++];	/* We already know it's a digit */
    163 	if (v != 0) {
    164 	    b = 10;		/* decimal number */
    165 	} else
    166 	if (digval[*nxtchr] == DIGIT_X) {
    167 	    nxtchr++;
    168 	    b = 16;		/* hexadecimal number */
    169 	} else {
    170 	    b = 8;		/* octal number */
    171 	}
    172 	do {
    173 	    while (digval[c = *nxtchr++] < b) v = v*b + digval[c];
    174 	} while (c == '_');
    175 	while (digval[c] == DIGIT_L || digval[c] == DIGIT_U) c = *nxtchr++;
    176 	nxtchr--;		/* unread c */
    177 	if ((unsigned)(c-1) < ' ') { deblank1; }
    178 	return v;
    179     }
    180 
    181 
    182 /*  <charcon> ::= <qt> { <char> } <qt>
    183     Note: multibyte constants are accepted.
    184     Note: BEL (\a) and ESC (\e) have the same values in EBCDIC and ASCII.
    185 */
    186 static long int charcon(doit)
    187     int doit;
    188     {
    189 	register int i;
    190 	long int value;
    191 	register int c;
    192 	int q;
    193 	int v[sizeof value];
    194 
    195 	q = *nxtchr++;		/* the quote character */
    196 	for (i = 0; ; i++) {
    197 	    c = *nxtchr++;
    198 	    if (c == q) {	/* end of literal, or doubled quote */
    199 		if (*nxtchr != c) break;
    200 		nxtchr++;	/* doubled quote stands for one quote */
    201 	    }
    202 	    if (i == sizeof value) experr("Unterminated character constant");
    203 	    if (c == '\\') {
    204 		switch (c = *nxtchr++) {
    205 		    case '0': case '1': case '2': case '3':
    206 		    case '4': case '5': case '6': case '7':
    207 			c -= '0';
    208 			if ((unsigned)(*nxtchr - '0') < 8)
    209 			    c = (c << 3) | (*nxtchr++ - '0');
    210 			if ((unsigned)(*nxtchr - '0') < 8)
    211 			    c = (c << 3) | (*nxtchr++ - '0');
    212 			break;
    213 		    case 'n': case 'N': c = '\n'; break;
    214 		    case 'r': case 'R': c = '\r'; break;
    215 		    case 't': case 'T': c = '\t'; break;
    216 		    case 'b': case 'B': c = '\b'; break;
    217 		    case 'f': case 'F': c = '\f'; break;
    218 		    case 'a': case 'A': c = 007;  break;
    219 		    case 'e': case 'E': c = 033;  break;
    220 #if	' ' == 64
    221 		    case 'd': case 'D': c = 045;  break; /*EBCDIC DEL */
    222 #else
    223 		    case 'd': case 'D': c = 127;  break; /* ASCII DEL */
    224 #endif
    225 		    default :			  break;
    226 		}
    227 	    }
    228 	    v[i] = c;
    229 	}
    230 	deblank0;
    231 	if (!doit) return 0;
    232 	for (value = 0; --i >= 0; ) value = (value << CHAR_BIT) | v[i];
    233 	return value;
    234     }
    235 
    236 
    237 /*  <unary> ::= <unop> <unary> | <factor>
    238     <unop> ::= '!' || '~' | '-'
    239     <factor> ::= '(' <query> ')' | <'> <char> <'> | <"> <char> <"> | <num>
    240 */
    241 static long int unary(doit)
    242     int doit;
    243     {
    244 	long int v;
    245 
    246 	switch (nxtchr[0]) {
    247 	    case 'n': case 'N':
    248 			if (digval[nxtchr[1]] != DIGIT_O
    249 			||  digval[nxtchr[2]] != DIGIT_T)
    250 			    experr("Bad 'not'");
    251 			nxtchr += 2;
    252 	    case '!':	deblank1; return !unary(doit);
    253 	    case '~':	deblank1; return ~unary(doit);
    254 	    case '-':	deblank1; return -unary(doit);
    255 	    case '+':	deblank1; return  unary(doit);
    256 	    case '(':	deblank1; v = query(doit);
    257 			if (nxtchr[0] != ')') experr("Bad factor");
    258 			deblank1; return v;
    259 	    case '\'':
    260 	    case '\"':	return charcon(doit);
    261 	    case '0': case '1': case '2':
    262 	    case '3': case '4': case '5':
    263 	    case '6': case '7': case '8':
    264 	    case '9':	return numcon(doit);
    265 	    default :   experr("Bad constant");
    266 	}
    267 	return 0;	/*NOTREACHED*/
    268     }
    269 
    270 
    271 /*  <term> ::= <unary> { <mulop> <unary> }
    272     <mulop> ::= '*' | '/' || '%'
    273 */
    274 static long int term(doit)
    275     int doit;
    276     {
    277 	register long int vl, vr;
    278 
    279 	vl = unary(doit);
    280 	for (;;)
    281 	    switch (nxtchr[0]) {
    282 		case '*':
    283 		    deblank1;
    284 		    vr = unary(doit);
    285 		    if (doit) vl *= vr;
    286 		    break;
    287 		case 'd': case 'D':
    288 		    if (digval[nxtchr[1]] != DIGIT_I
    289 		    ||  digval[nxtchr[2]] != DIGIT_V)
    290 			experr("Bad 'div'");
    291 		    nxtchr += 2;
    292 		    /*FALLTHROUGH*/
    293 		case '/':
    294 		    deblank1;
    295 		    vr = unary(doit);
    296 		    if (doit) {
    297 			if (vr == 0) experr("Division by 0");
    298 			vl /= vr;
    299 		    }
    300 		    break;
    301 		case 'm': case 'M':
    302 		    if (digval[nxtchr[1]] != DIGIT_O
    303 		    ||  digval[nxtchr[2]] != DIGIT_D)
    304 			experr("Bad 'mod'");
    305 		    nxtchr += 2;
    306 		    /*FALLTHROUGH*/
    307 		case '%':
    308 		    deblank1;
    309 		    vr = unary(doit);
    310 		    if (doit) {
    311 			if (vr != 0) vl %= vr;
    312 		    }
    313 		    break;
    314 		default:
    315 		    return vl;
    316 	    }
    317 	/*NOTREACHED*/
    318     }
    319 
    320 /*  <primary> ::= <term> { <addop> <term> }
    321     <addop> ::= '+' | '-'
    322 */
    323 static long int primary(doit)
    324     int doit;
    325     {
    326 	register long int vl;
    327 
    328 	vl = term(doit);
    329 	for (;;)
    330 	    if (nxtchr[0] == '+') {
    331 		deblank1;
    332 		if (doit) vl += term(doit); else (void)term(doit);
    333 	    } else
    334 	    if (nxtchr[0] == '-') {
    335 		deblank1;
    336 		if (doit) vl -= term(doit); else (void)term(doit);
    337 	    } else
    338 		return vl;
    339 	/*NOTREACHED*/
    340     }
    341 
    342 
    343 /*  <shift> ::= <primary> { <shop> <primary> }
    344     <shop> ::= '<<' | '>>'
    345 */
    346 static long int shift(doit)
    347     int doit;
    348     {
    349 	register long int vl, vr;
    350 
    351 	vl = primary(doit);
    352 	for (;;) {
    353 	    if (nxtchr[0] == '<' && nxtchr[1] == '<') {
    354 		deblank2;
    355 		vr = primary(doit);
    356 	    } else
    357 	    if (nxtchr[0] == '>' && nxtchr[1] == '>') {
    358 		deblank2;
    359 		vr = -primary(doit);
    360 	    } else {
    361 		return vl;
    362 	    }
    363 	    /* The following code implements shifts portably */
    364 	    /* Shifts are signed shifts, and the shift count */
    365 	    /* acts like repeated one-bit shifts, not modulo anything */
    366 	    if (doit) {
    367 		if (vr >= LONG_BIT) {
    368 		    vl = 0;
    369 		} else
    370 		if (vr <= -LONG_BIT) {
    371 		    vl = -(vl < 0);
    372 		} else
    373 		if (vr > 0) {
    374 		    vl <<= vr;
    375 		} else
    376 		if (vr < 0) {
    377 		    vl = (vl >> -vr) | (-(vl < 0) << (LONG_BIT + vr));
    378 		}
    379 	    }
    380 	}
    381 	/*NOTREACHED*/
    382     }
    383 
    384 
    385 /*  <relat> ::= <shift> { <rel> <shift> }
    386     <rel> ::= '<=' | '>=' | '=<' | '=>' | '<' | '>'
    387     Here I rely on the fact that '<<' and '>>' are swallowed by <shift>
    388 */
    389 static long int relat(doit)
    390     int doit;
    391     {
    392 	register long int vl;
    393 
    394 	vl = shift(doit);
    395 	for (;;)
    396 	    switch (nxtchr[0]) {
    397 		case '=':
    398 		    switch (nxtchr[1]) {
    399 			case '<':			/* =<, take as <= */
    400 			    deblank2;
    401 			    vl = vl <= shift(doit);
    402 			    break;
    403 			case '>':			/* =>, take as >= */
    404 			    deblank2;
    405 			    vl = vl >= shift(doit);
    406 			    break;
    407 			default:			/* == or =; OOPS */
    408 			    return vl;
    409 		    }
    410 		    break;
    411 		case '<':
    412 		    if (nxtchr[1] == '=') {		/* <= */
    413 			deblank2;
    414 			vl = vl <= shift(doit);
    415 		    } else
    416 		    if (nxtchr[1] == '>') {		/* <> (Pascal) */
    417 			deblank2;
    418 			vl = vl != shift(doit);
    419 		    } else {				/* < */
    420 			deblank1;
    421 			vl = vl < shift(doit);
    422 		    }
    423 		    break;
    424 		case '>':
    425 		    if (nxtchr[1] == '=') {		/* >= */
    426 			deblank2;
    427 			vl = vl >= shift(doit);
    428 		    } else {				/* > */
    429 			deblank1;
    430 			vl = vl > shift(doit);
    431 		    }
    432 		    break;
    433 		default:
    434 		    return vl;
    435 	}
    436 	/*NOTREACHED*/
    437     }
    438 
    439 
    440 /*  <eql> ::= <relat> { <eqrel> <relat> }
    441     <eqlrel> ::= '!=' | '==' | '='
    442 */
    443 static long int eql(doit)
    444     int doit;
    445     {
    446 	register long int vl;
    447 
    448 	vl = relat(doit);
    449 	for (;;)
    450 	    if (nxtchr[0] == '!' && nxtchr[1] == '=') {
    451 		deblank2;
    452 		vl = vl != relat(doit);
    453 	    } else
    454 	    if (nxtchr[0] == '=' && nxtchr[1] == '=') {
    455 		deblank2;
    456 		vl = vl == relat(doit);
    457 	    } else
    458 	    if (nxtchr[0] == '=') {
    459 		deblank1;
    460 		vl = vl == relat(doit);
    461 	    } else
    462 		return vl;
    463 	/*NOTREACHED*/
    464     }
    465 
    466 
    467 /*  <band> ::= <eql> { '&' <eql> }
    468 */
    469 static long int band(doit)
    470     int doit;
    471     {
    472 	register long int vl;
    473 
    474 	vl = eql(doit);
    475 	while (nxtchr[0] == '&' && nxtchr[1] != '&') {
    476 	    deblank1;
    477 	    if (doit) vl &= eql(doit); else (void)eql(doit);
    478 	}
    479 	return vl;
    480     }
    481 
    482 
    483 /*  <bxor> ::= <band> { '^' <band> }
    484 */
    485 static long int bxor(doit)
    486     int doit;
    487     {
    488 	register long int vl;
    489 
    490 	vl = band(doit);
    491 	while (nxtchr[0] == '^') {
    492 	    deblank1;
    493 	    if (doit) vl ^= band(doit); else (void)band(doit);
    494 	}
    495 	return vl;
    496     }
    497 
    498 
    499 /*  <bor> ::= <bxor> { '|' <bxor> }
    500 */
    501 static long int bor(doit)
    502     int doit;
    503     {
    504 	register long int vl;
    505 
    506 	vl = bxor(doit);
    507 	while (nxtchr[0] == '|' && nxtchr[1] != '|') {
    508 	    deblank1;
    509 	    if (doit) vl |= bxor(doit); else (void)bxor(doit);
    510 	}
    511 	return vl;
    512     }
    513 
    514 
    515 /*  <land> ::= <bor> { '&&' <bor> }
    516 */
    517 static long int land(doit)
    518     int doit;
    519     {
    520 	register long int vl;
    521 
    522 	vl = bor(doit);
    523 	for (;;) {
    524 	    if (nxtchr[0] == '&') {
    525 		if (nxtchr[1] != '&') break;
    526 		deblank2;
    527 	    } else
    528 	    if (digval[nxtchr[0]] == DIGIT_A) {
    529 		if (digval[nxtchr[1]] != DIGIT_N) break;
    530 		if (digval[nxtchr[2]] != DIGIT_D) break;
    531 		nxtchr += 2; deblank1;
    532 	    } else {
    533 		/* neither && nor and */
    534 		break;
    535 	    }
    536 	    vl = bor(doit && vl) != 0;
    537 	}
    538 	return vl;
    539     }
    540 
    541 
    542 /*  <lor> ::= <land> { '||' <land> }
    543 */
    544 static long int lor(doit)
    545     int doit;
    546     {
    547 	register long int vl;
    548 
    549 	vl = land(doit);
    550 	for (;;) {
    551 	    if (nxtchr[0] == '|') {
    552 		if (nxtchr[1] != '|') break;
    553 	    } else
    554 	    if (digval[nxtchr[0]] == DIGIT_O) {
    555 		if (digval[nxtchr[1]] != DIGIT_R) break;
    556 	    } else {
    557 		/* neither || nor or */
    558 		break;
    559 	    }
    560 	    deblank2;
    561 	    vl = land(doit && !vl) != 0;
    562 	}
    563 	return vl;
    564     }
    565 
    566 
    567 /*  <query> ::= <lor> [ '?' <query> ':' <query> ]
    568 */
    569 static long int query(doit)
    570     int doit;
    571     {
    572 	register long int bool, true_val, false_val;
    573 
    574 	bool = lor(doit);
    575 	if (*nxtchr != '?') return bool;
    576 	deblank1;
    577 	true_val = query(doit && bool);
    578 	if (*nxtchr != ':') experr("Bad query");
    579 	deblank1;
    580 	false_val = query(doit && !bool);
    581 	return bool ? true_val : false_val;
    582     }
    583 
    584 
    585 static void initialise_digval()
    586     {
    587 	register unsigned char *s;
    588 	register int c;
    589 
    590 	for (c = 0; c <= UCHAR_MAX; c++) digval[c] = 99;
    591 	for (c =  0, s = (unsigned char *)"0123456789";
    592 	/*while*/ *s;
    593 	/*doing*/ digval[*s++] = c++) /* skip */;
    594 	for (c = 10, s = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    595 	/*while*/ *s;
    596 	/*doing*/ digval[*s++] = c++) /* skip */;
    597 	for (c = 10, s = (unsigned char *)"abcdefghijklmnopqrstuvwxyz";
    598 	/*while*/ *s;
    599 	/*doing*/ digval[*s++] = c++) /* skip */;
    600 	digval['_'] = 36;
    601     }
    602 
    603 
    604 long int expr(expbuf)
    605     char *expbuf;
    606     {
    607 	register int rval;
    608 
    609 	if (digval['1'] == 0) initialise_digval();
    610 	nxtchr = (unsigned char *)expbuf;
    611 	deblank0;
    612 	if (setjmp(expjump) != 0) return FALSE;
    613 	rval = query(TRUE);
    614 	if (*nxtchr) experr("Ill-formed expression");
    615 	return rval;
    616     }
    617 
    618