/* * Constant expression evaluator -- performs a standard recursive * descent parse to evaluate any legal C constant expression. All * operators without side-effects are implemented (thus ++, --, and all * assignment operators are omitted). * * The macro expansion routine is called to process the expression * before it is evaluated. All macros used in the expression must * ultimately evaluate to legal C constants. This code was originally * written by Mike Lutz and was modified by Bob Harper to fit into this * program and to conform to C language standards. */ /* * Include global constant defintions. */ #include "mpdefs.h" /* * Variables global to expr */ static char *nxtch = EOS; /* Parser scan pointer */ static char expbuf[EXPBUFSZ]; /* Buffer for expansion routine */ /* * For longjmp */ #include static jmp_buf exp_jump; expr(exptr) char *exptr; { char *dst; setjmp(exp_jump); dst = expbuf; if (setjmp(exp_jump) != 0) return (FALSE); if (expand(exptr, &dst, expbuf+EXPBUFSZ-2, 0) == ERROR) return(FALSE); *dst = EOS; nxtch = expbuf; if (setjmp(exp_jump) != 0) return (FALSE); return(eval()); } /* ::= */ eval() { register int rval; rval = query() ; if ( skipws() == EOS ) return( rval ) ; experr( "Ill-formed expression" ) ; } /* ::= | '?' ':' */ query() { register int bool, true_val, false_val ; bool = lor() ; if ( skipws() != '?' ) { ungetch() ; return( bool ) ; } true_val = query() ; if ( skipws() != ':' ) experr( "Bad query" ) ; false_val = query() ; return( bool ? true_val : false_val ) ; } /* ::= { '||' } */ lor() { register int c, vl, vr ; vl = land() ; while ( (c = skipws()) == '|' && getch() == '|' ) { vr = land() ; vl = vl || vr ; } if ( c == '|' ) ungetch() ; ungetch() ; return( vl ) ; } /* ::= { '&&' } */ land() { register int c, vl, vr ; vl = bor() ; while ( (c = skipws()) == '&' && getch() == '&' ) { vr = bor() ; vl = vl && vr ; } if ( c == '&' ) ungetch() ; ungetch() ; return( vl ) ; } /* ::= { '|' } */ bor() { register int vl, vr, c ; vl = bxor() ; while ( (c = skipws()) == '|' && getch() != '|' ) { ungetch() ; vr = bxor() ; vl |= vr ; } if ( c == '|' ) ungetch() ; ungetch() ; return( vl ) ; } /* ::= { '^' } */ bxor() { register int vl, vr ; vl = band() ; while ( skipws() == '^' ) { vr = band() ; vl ^= vr ; } ungetch() ; return( vl ) ; } /* ::= { '&' } */ band() { register int vl, vr, c ; vl = eql() ; while ( (c = skipws()) == '&' && getch() != '&' ) { ungetch() ; vr = eql() ; vl &= vr ; } if ( c == '&' ) ungetch() ; ungetch() ; return( vl ) ; } /* ::= { } */ eql() { register int vl, vr, rel ; vl = relat() ; while ( (rel = geteql()) != -1 ) { vr = relat() ; switch ( rel ) { case EQL: vl = (vl == vr) ; break ; case NEQ: vl = (vl != vr) ; break ; } } return( vl ) ; } /* ::= { } */ relat() { register int vl, vr, rel ; vl = shift() ; while ( (rel = getrel()) != -1 ) { vr = shift() ; switch ( rel ) { case LEQ: vl = (vl <= vr) ; break ; case LSS: vl = (vl < vr) ; break ; case GTR: vl = (vl > vr) ; break ; case GEQ: vl = (vl >= vr) ; break ; } } return( vl ) ; } /* ::= { } */ shift() { register int vl, vr, c ; vl = primary() ; while ( ( (c = skipws()) == '<' || c == '>' ) && c == getch() ) { vr = primary() ; if ( c == '<' ) vl <<= vr ; else vl >>= vr ; } if ( c == '<' || c == '>' ) ungetch() ; ungetch() ; return( vl ) ; } /* ::= { } */ primary() { register int c, vl, vr ; vl = term() ; while ( (c = skipws()) == '+' || c == '-' ) { vr = term() ; if ( c == '+' ) vl += vr ; else vl -= vr ; } ungetch() ; return( vl ) ; } /* := { } */ term() { register int c, vl, vr ; vl = unary() ; while ( (c = skipws()) == '*' || c == '/' || c == '%' ) { vr = unary() ; switch ( c ) { case '*': vl *= vr ; break ; case '/': vl /= vr ; break ; case '%': vl %= vr ; break ; } } ungetch() ; return( vl ) ; } /* ::= | */ unary() { register int val, c ; if ( (c = skipws()) == '!' || c == '~' || c == '-' ) { val = unary() ; switch ( c ) { case '!': return( ! val ) ; case '~': return( ~ val ) ; case '-': return( - val ) ; } } ungetch() ; return( factor() ) ; } /* ::= | '(' ')' */ factor() { register int val ; if ( skipws() == '(' ) { val = query() ; if ( skipws() != ')' ) experr( "Bad factor" ) ; return( val ) ; } ungetch() ; return( const() ) ; } /* ::= | '' */ const() { /* * Note: const() handles multi-byte constants */ register int i; register int value; register char c; int v[sizeof (int)]; if (skipws() != '\'') { ungetch(); return(num(0)); } for (i = 0; i < sizeof(int); i++) { if ((c = getch()) == '\'') { ungetch(); break; } if (c == '\\') { switch ( c = getch() ) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': ungetch(); c = num(1); break; case 'n': c = 012; break; case 'r': c = 015; break; case 't': c = 011; break; case 'b': c = 010; break; case 'f': c = 014; break; } } v[i] = c; } if (i == 0 || getch() != '\'') experr("Illegal character constant"); for (value = 0; --i >= 0;) { value <<= 8; value += v[i]; } return(value); } /* ::= | */ num(flag) int flag; /* if flag is zero, the first byte selects conversion */ { register int rval, c, base; int ndig; c = skipws(); base = (flag || c == '0') ? OCTAL : DECIMAL; rval = 0 ; ndig = 0 ; while ( c >= '0' && c <= (base == OCTAL ? '7' : '9') ) { rval *= base ; rval += (c - '0') ; c = getch() ; ndig++ ; } ungetch() ; if ( ndig ) return( rval ) ; experr( "Bad constant" ) ; } /* ::= '=' | '==' | '!=' */ geteql() { register int c1, c2 ; c1 = skipws() ; c2 = getch() ; switch ( c1 ) { case '=': if ( c2 != '=' ) ungetch() ; return( EQL ) ; case '!': if ( c2 == '=' ) return( NEQ ) ; ungetch() ; ungetch() ; return( -1 ) ; default: ungetch() ; ungetch() ; return( -1 ) ; } } /* ::= '<' | '>' | '<=' | '>=' */ getrel() { register int c1, c2; c1 = skipws(); c2 = getch() ; switch ( c1 ) { case '<': if ( c2 == '=' ) return( LEQ ) ; ungetch() ; return( LSS ) ; case '>': if ( c2 == '=' ) return( GEQ ) ; ungetch() ; return( GTR ) ; default: ungetch() ; ungetch() ; return( -1 ) ; } } /* return next character from the expression string. */ getch() { return(*nxtch++); } /* Put back the last character examined. */ ungetch() { return( *--nxtch ) ; } /* Skip over any white space and return terminating char. */ skipws() { register char c; while ( (c = getch()) <= ' ' && c > EOS ) ; return( c ) ; } /* * Error handler - resets environment to eval(), prints an error, * and returns FALSE */ experr(msg) char *msg; { printerr(msg); longjmp(exp_jump, -1); /* Force eval() to return FALSE */ }