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