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