--- ray/src/common/calexpr.c 1991/04/23 15:26:26 1.9 +++ ray/src/common/calexpr.c 2005/05/17 17:51:51 2.30 @@ -1,9 +1,6 @@ -/* Copyright (c) 1986 Regents of the University of California */ - #ifndef lint -static char SCCSid[] = "$SunId$ LBL"; +static const char RCSid[] = "$Id: calexpr.c,v 2.30 2005/05/17 17:51:51 greg Exp $"; #endif - /* * Compute data values using expression parser * @@ -16,60 +13,53 @@ static char SCCSid[] = "$SunId$ LBL"; * 1/29/87 Made variables conditional (VARIABLE) * * 5/19/88 Added constant subexpression elimination (RCONST) + * + * 2/19/03 Eliminated conditional compiles in favor of esupport extern. */ -#include +#include "copyright.h" +#include +#include #include - #include +#include +#include +#include "rtmisc.h" +#include "rtio.h" +#include "rterror.h" #include "calcomp.h" -#define MAXLINE 256 /* maximum line length */ -#define MAXWORD 64 /* maximum word length */ +#define MAXLINE 256 /* maximum line length */ -#define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE)) +#define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE)) -#define isid(c) (isalnum(c) || (c) == '_' || (c) == '.') +#define isdecimal(c) (isdigit(c) || (c) == '.') -#define isdecimal(c) (isdigit(c) || (c) == '.') +static double euminus(EPNODE *), eargument(EPNODE *), enumber(EPNODE *); +static double echannel(EPNODE *); +static double eadd(EPNODE *), esubtr(EPNODE *), + emult(EPNODE *), edivi(EPNODE *), + epow(EPNODE *); +static double ebotch(EPNODE *); -extern double atof(), pow(); -extern char *fgets(), *savestr(); -extern char *emalloc(), *ecalloc(); -extern EPNODE *curfunc; -extern double efunc(), evariable(); -static double euminus(), echannel(), eargument(), enumber(); -static double eadd(), esubtr(), emult(), edivi(), epow(); -static double ebotch(); -extern int errno; +unsigned int esupport = /* what to support */ + E_VARIABLE | E_FUNCTION ; +int eofc = 0; /* optional end-of-file character */ int nextc; /* lookahead character */ -double (*eoper[])() = { /* expression operations */ +double (*eoper[])(EPNODE *) = { /* expression operations */ ebotch, -#ifdef VARIABLE evariable, -#else - ebotch, -#endif enumber, euminus, -#ifdef INCHAN echannel, -#else - ebotch, -#endif -#ifdef FUNCTION efunc, eargument, -#else ebotch, ebotch, -#endif - ebotch, - ebotch, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, emult, @@ -95,15 +85,14 @@ static int linepos; /* position in buffer */ EPNODE * -eparse(expr) /* parse an expression string */ -char *expr; +eparse( /* parse an expression string */ + char *expr +) { EPNODE *ep; initstr(expr, NULL, 0); -#if defined(VARIABLE) && defined(FUNCTION) curfunc = NULL; -#endif ep = getE1(); if (nextc != EOF) syntax("unexpected character"); @@ -112,8 +101,9 @@ char *expr; double -eval(expr) /* evaluate an expression string */ -char *expr; +eval( /* evaluate an expression string */ + char *expr +) { register EPNODE *ep; double rval; @@ -125,18 +115,68 @@ char *expr; } -epfree(epar) /* free a parse tree */ -register EPNODE *epar; +int +epcmp( /* compare two expressions for equivalence */ + register EPNODE *ep1, + register EPNODE *ep2 +) { + double d; + + if (ep1->type != ep2->type) + return(1); + + switch (ep1->type) { + + case VAR: + return(ep1->v.ln != ep2->v.ln); + + case NUM: + if (ep2->v.num == 0) + return(ep1->v.num != 0); + d = ep1->v.num / ep2->v.num; + return((d > 1.000000000001) | (d < 0.999999999999)); + + case CHAN: + case ARG: + return(ep1->v.chan != ep2->v.chan); + + case '=': + case ':': + return(epcmp(ep1->v.kid->sibling, ep2->v.kid->sibling)); + + case TICK: + case SYM: /* should never get this one */ + return(0); + + default: + ep1 = ep1->v.kid; + ep2 = ep2->v.kid; + while (ep1 != NULL) { + if (ep2 == NULL) + return(1); + if (epcmp(ep1, ep2)) + return(1); + ep1 = ep1->sibling; + ep2 = ep2->sibling; + } + return(ep2 != NULL); + } +} + + +void +epfree( /* free a parse tree */ + register EPNODE *epar +) +{ register EPNODE *ep; switch (epar->type) { -#if defined(VARIABLE) || defined(FUNCTION) case VAR: varfree(epar->v.ln); break; -#endif case SYM: freestr(epar->v.name); @@ -149,8 +189,10 @@ register EPNODE *epar; break; default: - for (ep = epar->v.kid; ep != NULL; ep = ep->sibling) + while ((ep = epar->v.kid) != NULL) { + epar->v.kid = ep->sibling; epfree(ep); + } break; } @@ -159,43 +201,44 @@ register EPNODE *epar; } /* the following used to be a switch */ -#ifdef FUNCTION static double -eargument(ep) -EPNODE *ep; +eargument( + EPNODE *ep +) { return(argument(ep->v.chan)); } -#endif static double -enumber(ep) -EPNODE *ep; +enumber( + EPNODE *ep +) { return(ep->v.num); } static double -euminus(ep) -EPNODE *ep; +euminus( + EPNODE *ep +) { register EPNODE *ep1 = ep->v.kid; return(-evalue(ep1)); } -#ifdef INCHAN static double -echannel(ep) -EPNODE *ep; +echannel( + EPNODE *ep +) { return(chanvalue(ep->v.chan)); } -#endif static double -eadd(ep) -EPNODE *ep; +eadd( + EPNODE *ep +) { register EPNODE *ep1 = ep->v.kid; @@ -203,8 +246,9 @@ EPNODE *ep; } static double -esubtr(ep) -EPNODE *ep; +esubtr( + EPNODE *ep +) { register EPNODE *ep1 = ep->v.kid; @@ -212,8 +256,9 @@ EPNODE *ep; } static double -emult(ep) -EPNODE *ep; +emult( + EPNODE *ep +) { register EPNODE *ep1 = ep->v.kid; @@ -221,8 +266,9 @@ EPNODE *ep; } static double -edivi(ep) -EPNODE *ep; +edivi( + EPNODE *ep +) { register EPNODE *ep1 = ep->v.kid; double d; @@ -237,21 +283,22 @@ EPNODE *ep; } static double -epow(ep) -EPNODE *ep; +epow( + EPNODE *ep +) { register EPNODE *ep1 = ep->v.kid; double d; - int lasterrno; + int lasterrno; lasterrno = errno; errno = 0; d = pow(evalue(ep1), evalue(ep1->sibling)); -#ifdef IEEE +#ifdef IEEE if (!finite(d)) errno = EDOM; #endif - if (errno) { + if (errno == EDOM || errno == ERANGE) { wputs("Illegal power\n"); return(0.0); } @@ -260,18 +307,21 @@ EPNODE *ep; } static double -ebotch(ep) -EPNODE *ep; +ebotch( + EPNODE *ep +) { eputs("Bad expression!\n"); quit(1); + return 0.0; /* pro forma return */ } EPNODE * -ekid(ep, n) /* return pointer to a node's nth kid */ -register EPNODE *ep; -register int n; +ekid( /* return pointer to a node's nth kid */ + register EPNODE *ep, + register int n +) { for (ep = ep->v.kid; ep != NULL; ep = ep->sibling) @@ -283,8 +333,9 @@ register int n; int -nekids(ep) /* return # of kids for node ep */ -register EPNODE *ep; +nekids( /* return # of kids for node ep */ + register EPNODE *ep +) { register int n = 0; @@ -295,12 +346,14 @@ register EPNODE *ep; } -initfile(fp, fn, ln) /* prepare input file */ -FILE *fp; -char *fn; -int ln; +void +initfile( /* prepare input file */ + FILE *fp, + char *fn, + int ln +) { - static char inpbuf[MAXLINE]; + static char inpbuf[MAXLINE]; infp = fp; linbuf = inpbuf; @@ -312,10 +365,12 @@ int ln; } -initstr(s, fn, ln) /* prepare input string */ -char *s; -char *fn; -int ln; +void +initstr( /* prepare input string */ + char *s, + char *fn, + int ln +) { infp = NULL; infile = fn; @@ -326,8 +381,26 @@ int ln; } -scan() /* scan next character */ +void +getscanpos( /* return current scan position */ + char **fnp, + int *lnp, + char **spp, + FILE **fpp +) { + if (fnp != NULL) *fnp = infile; + if (lnp != NULL) *lnp = lineno; + if (spp != NULL) *spp = linbuf+linepos; + if (fpp != NULL) *fpp = infp; +} + + +int +scan(void) /* scan next character, return literal next */ +{ + register int lnext = 0; + do { if (linbuf[linepos] == '\0') if (infp == NULL || fgets(linbuf, MAXLINE, infp) == NULL) @@ -339,6 +412,12 @@ scan() /* scan next character */ } else nextc = linbuf[linepos++]; + if (!lnext) + lnext = nextc; + if (nextc == eofc) { + nextc = EOF; + break; + } if (nextc == '{') { scan(); while (nextc != '}') @@ -349,16 +428,18 @@ scan() /* scan next character */ scan(); } } while (isspace(nextc)); + return(lnext); } char * -ltoa(l) /* convert long to ascii */ -long l; +long2ascii( /* convert long to ascii */ + long l +) { - static char buf[16]; + static char buf[16]; register char *cp; - int neg = 0; + int neg = 0; if (l == 0) return("0"); @@ -378,8 +459,10 @@ long l; } -syntax(err) /* report syntax error and quit */ -char *err; +void +syntax( /* report syntax error and quit */ + char *err +) { register int i; @@ -387,9 +470,9 @@ char *err; if (infile != NULL) eputs(infile); if (lineno != 0) { eputs(infile != NULL ? ", line " : "line "); - eputs(ltoa((long)lineno)); + eputs(long2ascii((long)lineno)); } - eputs(": syntax error:\n"); + eputs(":\n"); } eputs(linbuf); if (linbuf[strlen(linbuf)-1] != '\n') @@ -403,9 +486,11 @@ char *err; } -addekid(ep, ekid) /* add a child to ep */ -register EPNODE *ep; -EPNODE *ekid; +void +addekid( /* add a child to ep */ + register EPNODE *ep, + EPNODE *ekid +) { if (ep->v.kid == NULL) ep->v.kid = ekid; @@ -419,62 +504,71 @@ EPNODE *ekid; char * -getname() /* scan an identifier */ +getname(void) /* scan an identifier */ { - static char str[MAXWORD+1]; - register int i; + static char str[RMAXWORD+1]; + register int i, lnext; - for (i = 0; i < MAXWORD && isid(nextc); i++, scan()) - str[i] = nextc; + lnext = nextc; + for (i = 0; i < RMAXWORD && isid(lnext); i++, lnext = scan()) + str[i] = lnext; str[i] = '\0'; + while (isid(lnext)) /* skip rest of name */ + lnext = scan(); return(str); } int -getinum() /* scan a positive integer */ +getinum(void) /* scan a positive integer */ { - register int n; + register int n, lnext; n = 0; - while (isdigit(nextc)) { - n = n * 10 + nextc - '0'; - scan(); + lnext = nextc; + while (isdigit(lnext)) { + n = n * 10 + lnext - '0'; + lnext = scan(); } return(n); } double -getnum() /* scan a positive float */ +getnum(void) /* scan a positive float */ { - register int i; - char str[MAXWORD+1]; + register int i, lnext; + char str[RMAXWORD+1]; i = 0; - while (isdigit(nextc) && i < MAXWORD) { - str[i++] = nextc; - scan(); + lnext = nextc; + while (isdigit(lnext) && i < RMAXWORD) { + str[i++] = lnext; + lnext = scan(); } - if (nextc == '.' && i < MAXWORD) { - str[i++] = nextc; - scan(); - while (isdigit(nextc) && i < MAXWORD) { - str[i++] = nextc; - scan(); + if (lnext == '.' && i < RMAXWORD) { + str[i++] = lnext; + lnext = scan(); + if (i == 1 && !isdigit(lnext)) + syntax("badly formed number"); + while (isdigit(lnext) && i < RMAXWORD) { + str[i++] = lnext; + lnext = scan(); } } - if ((nextc == 'e' || nextc == 'E') && i < MAXWORD) { - str[i++] = nextc; - scan(); - if ((nextc == '-' || nextc == '+') && i < MAXWORD) { - str[i++] = nextc; - scan(); + if ((lnext == 'e') | (lnext == 'E') && i < RMAXWORD) { + str[i++] = lnext; + lnext = scan(); + if ((lnext == '-') | (lnext == '+') && i < RMAXWORD) { + str[i++] = lnext; + lnext = scan(); } - while (isdigit(nextc) && i < MAXWORD) { - str[i++] = nextc; - scan(); + if (!isdigit(lnext)) + syntax("missing exponent"); + while (isdigit(lnext) && i < RMAXWORD) { + str[i++] = lnext; + lnext = scan(); } } str[i] = '\0'; @@ -484,8 +578,8 @@ getnum() /* scan a positive float */ EPNODE * -getE1() /* E1 -> E1 ADDOP E2 */ - /* E2 */ +getE1(void) /* E1 -> E1 ADDOP E2 */ + /* E2 */ { register EPNODE *ep1, *ep2; @@ -496,10 +590,9 @@ getE1() /* E1 -> E1 ADDOP E2 */ scan(); addekid(ep2, ep1); addekid(ep2, getE2()); -#ifdef RCONST - if (ep1->type == NUM && ep1->sibling->type == NUM) + if (esupport&E_RCONST && + ep1->type == NUM && ep1->sibling->type == NUM) ep2 = rconst(ep2); -#endif ep1 = ep2; } return(ep1); @@ -507,8 +600,8 @@ getE1() /* E1 -> E1 ADDOP E2 */ EPNODE * -getE2() /* E2 -> E2 MULOP E3 */ - /* E3 */ +getE2(void) /* E2 -> E2 MULOP E3 */ + /* E3 */ { register EPNODE *ep1, *ep2; @@ -519,10 +612,9 @@ getE2() /* E2 -> E2 MULOP E3 */ scan(); addekid(ep2, ep1); addekid(ep2, getE3()); -#ifdef RCONST - if (ep1->type == NUM && ep1->sibling->type == NUM) + if (esupport&E_RCONST && + ep1->type == NUM && ep1->sibling->type == NUM) ep2 = rconst(ep2); -#endif ep1 = ep2; } return(ep1); @@ -530,8 +622,8 @@ getE2() /* E2 -> E2 MULOP E3 */ EPNODE * -getE3() /* E3 -> E4 ^ E3 */ - /* E4 */ +getE3(void) /* E3 -> E4 ^ E3 */ + /* E4 */ { register EPNODE *ep1, *ep2; @@ -542,10 +634,9 @@ getE3() /* E3 -> E4 ^ E3 */ scan(); addekid(ep2, ep1); addekid(ep2, getE3()); -#ifdef RCONST - if (ep1->type == NUM && ep1->sibling->type == NUM) + if (esupport&E_RCONST && + ep1->type == NUM && ep1->sibling->type == NUM) ep2 = rconst(ep2); -#endif return(ep2); } return(ep1); @@ -553,8 +644,8 @@ getE3() /* E3 -> E4 ^ E3 */ EPNODE * -getE4() /* E4 -> ADDOP E5 */ - /* E5 */ +getE4(void) /* E4 -> ADDOP E5 */ + /* E5 */ { register EPNODE *ep1, *ep2; @@ -565,6 +656,10 @@ getE4() /* E4 -> ADDOP E5 */ ep2->v.num = -ep2->v.num; return(ep2); } + if (ep2->type == UMINUS) { /* don't generate -(-E5) */ + efree((char *)ep2); + return(ep2->v.kid); + } ep1 = newnode(); ep1->type = UMINUS; addekid(ep1, ep2); @@ -577,94 +672,87 @@ getE4() /* E4 -> ADDOP E5 */ EPNODE * -getE5() /* E5 -> (E1) */ - /* VAR */ - /* NUM */ - /* $N */ - /* FUNC(E1,..) */ - /* ARG */ +getE5(void) /* E5 -> (E1) */ + /* VAR */ + /* NUM */ + /* $N */ + /* FUNC(E1,..) */ + /* ARG */ { - int i; - register EPNODE *ep1, *ep2; + int i; + char *nam; + register EPNODE *ep1, *ep2; - if (nextc == '(') { - scan(); - ep1 = getE1(); - if (nextc != ')') - syntax("')' expected"); - scan(); - return(ep1); - } + if (nextc == '(') { + scan(); + ep1 = getE1(); + if (nextc != ')') + syntax("')' expected"); + scan(); + return(ep1); + } -#ifdef INCHAN - if (nextc == '$') { - scan(); - ep1 = newnode(); - ep1->type = CHAN; - ep1->v.chan = getinum(); - return(ep1); - } -#endif + if (esupport&E_INCHAN && nextc == '$') { + scan(); + ep1 = newnode(); + ep1->type = CHAN; + ep1->v.chan = getinum(); + return(ep1); + } -#if defined(VARIABLE) || defined(FUNCTION) - if (isalpha(nextc)) { - ep1 = newnode(); - ep1->type = VAR; - ep1->v.ln = varinsert(getname()); - -#if defined(VARIABLE) && defined(FUNCTION) - if (curfunc != NULL) - for (i = 1, ep2 = curfunc->v.kid->sibling; - ep2 != NULL; i++, ep2 = ep2->sibling) - if (!strcmp(ep2->v.name, ep1->v.ln->name)) { - epfree(ep1); - ep1 = newnode(); - ep1->type = ARG; - ep1->v.chan = i; - break; + if (esupport&(E_VARIABLE|E_FUNCTION) && + (isalpha(nextc) || nextc == CNTXMARK)) { + nam = getname(); + ep1 = NULL; + if ((esupport&(E_VARIABLE|E_FUNCTION)) == (E_VARIABLE|E_FUNCTION) + && curfunc != NULL) + for (i = 1, ep2 = curfunc->v.kid->sibling; + ep2 != NULL; i++, ep2 = ep2->sibling) + if (!strcmp(ep2->v.name, nam)) { + ep1 = newnode(); + ep1->type = ARG; + ep1->v.chan = i; + break; + } + if (ep1 == NULL) { + ep1 = newnode(); + ep1->type = VAR; + ep1->v.ln = varinsert(nam); } -#endif -#ifdef FUNCTION - if (nextc == '(') { - ep2 = newnode(); - ep2->type = FUNC; - addekid(ep2, ep1); - ep1 = ep2; - do { - scan(); - addekid(ep1, getE1()); - } while (nextc == ','); - if (nextc != ')') - syntax("')' expected"); - scan(); + if (esupport&E_FUNCTION && nextc == '(') { + ep2 = newnode(); + ep2->type = FUNC; + addekid(ep2, ep1); + ep1 = ep2; + do { + scan(); + addekid(ep1, getE1()); + } while (nextc == ','); + if (nextc != ')') + syntax("')' expected"); + scan(); + } else if (!(esupport&E_VARIABLE)) + syntax("'(' expected"); + if (esupport&E_RCONST && isconstvar(ep1)) + ep1 = rconst(ep1); + return(ep1); } -#ifndef VARIABLE - else - syntax("'(' expected"); -#endif -#endif -#ifdef RCONST - if (isconstvar(ep1)) - ep1 = rconst(ep1); -#endif - return(ep1); - } -#endif - if (isdecimal(nextc)) { - ep1 = newnode(); - ep1->type = NUM; - ep1->v.num = getnum(); - return(ep1); - } - syntax("unexpected character"); + if (isdecimal(nextc)) { + ep1 = newnode(); + ep1->type = NUM; + ep1->v.num = getnum(); + return(ep1); + } + syntax("unexpected character"); + return NULL; /* pro forma return */ } -#ifdef RCONST EPNODE * -rconst(epar) /* reduce a constant expression */ -register EPNODE *epar; +rconst( /* reduce a constant expression */ + register EPNODE *epar +) { register EPNODE *ep; @@ -672,48 +760,57 @@ register EPNODE *epar; ep->type = NUM; errno = 0; ep->v.num = evalue(epar); - if (errno) - syntax("bad constant expression"); + if (errno == EDOM || errno == ERANGE) + syntax("bad constant expression"); epfree(epar); return(ep); } -isconstvar(ep) /* is ep linked to a constant? */ -register EPNODE *ep; +int +isconstvar( /* is ep linked to a constant expression? */ + register EPNODE *ep +) { -#ifdef VARIABLE register EPNODE *ep1; - -#ifdef FUNCTION - if (ep->type == FUNC) { - if (ep->v.kid->type != VAR) - return(0); - ep1 = ep->v.kid->v.ln->def; - if (ep1 != NULL && ep1->type != ':') - return(0); - if ((ep1 == NULL || ep1->v.kid->type != FUNC) - && liblookup(ep->v.kid->v.ln->name) == NULL) - return(0); + + if (esupport&E_FUNCTION && ep->type == FUNC) { + if (!isconstfun(ep->v.kid)) + return(0); for (ep1 = ep->v.kid->sibling; ep1 != NULL; ep1 = ep1->sibling) - if (ep1->type != NUM) + if (ep1->type != NUM && !isconstfun(ep1)) return(0); return(1); } -#endif if (ep->type != VAR) return(0); ep1 = ep->v.ln->def; if (ep1 == NULL || ep1->type != ':') return(0); -#ifdef FUNCTION - if (ep1->v.kid->type != SYM) + if (esupport&E_FUNCTION && ep1->v.kid->type != SYM) return(0); -#endif return(1); -#else - return(ep->type == FUNC); -#endif } -#endif + + +int +isconstfun( /* is ep linked to a constant function? */ + register EPNODE *ep +) +{ + register EPNODE *dp; + register LIBR *lp; + + if (ep->type != VAR) + return(0); + if ((dp = ep->v.ln->def) != NULL) { + if (dp->v.kid->type == FUNC) + return(dp->type == ':'); + else + return(0); /* don't identify masked library functions */ + } + if ((lp = ep->v.ln->lib) != NULL) + return(lp->atyp == ':'); + return(0); +}