--- ray/src/common/calexpr.c 1991/11/12 16:55:21 2.1 +++ ray/src/common/calexpr.c 2003/03/05 16:16:52 2.20 @@ -1,9 +1,6 @@ -/* Copyright (c) 1991 Regents of the University of California */ - #ifndef lint -static char SCCSid[] = "$SunId$ LBL"; +static const char RCSid[] = "$Id: calexpr.c,v 2.20 2003/03/05 16:16:52 greg Exp $"; #endif - /* * Compute data values using expression parser * @@ -16,57 +13,50 @@ 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 "copyright.h" + #include #include #include +#include + +#include + #include "calcomp.h" -#define MAXLINE 256 /* maximum line length */ +#define MAXLINE 256 /* maximum line length */ -#define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE)) +#define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE)) -#define isdecimal(c) (isdigit(c) || (c) == '.') +#define isdecimal(c) (isdigit(c) || (c) == '.') -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 euminus(), eargument(), enumber(); +static double echannel(); static double eadd(), esubtr(), emult(), edivi(), epow(); static double ebotch(); -extern int errno; +unsigned int esupport = /* what to support */ + E_VARIABLE | E_FUNCTION | E_REDEFW; + int nextc; /* lookahead character */ -double (*eoper[])() = { /* expression operations */ +double (*eoper[])() = { /* 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, @@ -98,9 +88,7 @@ char *expr; EPNODE *ep; initstr(expr, NULL, 0); -#if defined(VARIABLE) && defined(FUNCTION) curfunc = NULL; -#endif ep = getE1(); if (nextc != EOF) syntax("unexpected character"); @@ -122,18 +110,65 @@ char *expr; } +int +epcmp(ep1, ep2) /* compare two expressions for equivalence */ +register EPNODE *ep1, *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(epar) /* free a parse tree */ -register EPNODE *epar; +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); @@ -146,8 +181,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; } @@ -156,43 +193,39 @@ register EPNODE *epar; } /* the following used to be a switch */ -#ifdef FUNCTION static double eargument(ep) -EPNODE *ep; +EPNODE *ep; { return(argument(ep->v.chan)); } -#endif static double enumber(ep) -EPNODE *ep; +EPNODE *ep; { return(ep->v.num); } static double euminus(ep) -EPNODE *ep; +EPNODE *ep; { register EPNODE *ep1 = ep->v.kid; return(-evalue(ep1)); } -#ifdef INCHAN static double echannel(ep) -EPNODE *ep; +EPNODE *ep; { return(chanvalue(ep->v.chan)); } -#endif static double eadd(ep) -EPNODE *ep; +EPNODE *ep; { register EPNODE *ep1 = ep->v.kid; @@ -201,7 +234,7 @@ EPNODE *ep; static double esubtr(ep) -EPNODE *ep; +EPNODE *ep; { register EPNODE *ep1 = ep->v.kid; @@ -210,7 +243,7 @@ EPNODE *ep; static double emult(ep) -EPNODE *ep; +EPNODE *ep; { register EPNODE *ep1 = ep->v.kid; @@ -219,7 +252,7 @@ EPNODE *ep; static double edivi(ep) -EPNODE *ep; +EPNODE *ep; { register EPNODE *ep1 = ep->v.kid; double d; @@ -235,20 +268,20 @@ EPNODE *ep; static double epow(ep) -EPNODE *ep; +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); } @@ -258,7 +291,7 @@ EPNODE *ep; static double ebotch(ep) -EPNODE *ep; +EPNODE *ep; { eputs("Bad expression!\n"); quit(1); @@ -267,7 +300,7 @@ EPNODE *ep; EPNODE * ekid(ep, n) /* return pointer to a node's nth kid */ -register EPNODE *ep; +register EPNODE *ep; register int n; { @@ -281,7 +314,7 @@ register int n; int nekids(ep) /* return # of kids for node ep */ -register EPNODE *ep; +register EPNODE *ep; { register int n = 0; @@ -292,12 +325,13 @@ register EPNODE *ep; } +void initfile(fp, fn, ln) /* prepare input file */ FILE *fp; char *fn; int ln; { - static char inpbuf[MAXLINE]; + static char inpbuf[MAXLINE]; infp = fp; linbuf = inpbuf; @@ -309,6 +343,7 @@ int ln; } +void initstr(s, fn, ln) /* prepare input string */ char *s; char *fn; @@ -323,6 +358,7 @@ int ln; } +void getscanpos(fnp, lnp, spp, fpp) /* return current scan position */ char **fnp; int *lnp; @@ -369,12 +405,12 @@ scan() /* scan next character, return literal next char * -ltoa(l) /* convert long to ascii */ +long2ascii(l) /* 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"); @@ -394,6 +430,7 @@ long l; } +void syntax(err) /* report syntax error and quit */ char *err; { @@ -403,9 +440,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') @@ -419,9 +456,10 @@ char *err; } +void addekid(ep, ekid) /* add a child to ep */ -register EPNODE *ep; -EPNODE *ekid; +register EPNODE *ep; +EPNODE *ekid; { if (ep->v.kid == NULL) ep->v.kid = ekid; @@ -437,7 +475,7 @@ EPNODE *ekid; char * getname() /* scan an identifier */ { - static char str[MAXWORD+1]; + static char str[MAXWORD+1]; register int i, lnext; lnext = nextc; @@ -479,20 +517,24 @@ getnum() /* scan a positive float */ lnext = scan(); } if (lnext == '.' && i < MAXWORD) { - str[i++] = lnext; - lnext = scan(); + str[i++] = lnext; + lnext = scan(); + if (i == 1 && !isdigit(lnext)) + syntax("badly formed number"); while (isdigit(lnext) && i < MAXWORD) { str[i++] = lnext; lnext = scan(); } } - if ((lnext == 'e' || lnext == 'E') && i < MAXWORD) { - str[i++] = lnext; - lnext = scan(); - if ((lnext == '-' || lnext == '+') && i < MAXWORD) { + if ((lnext == 'e' | lnext == 'E') && i < MAXWORD) { + str[i++] = lnext; + lnext = scan(); + if ((lnext == '-' | lnext == '+') && i < MAXWORD) { str[i++] = lnext; lnext = scan(); } + if (!isdigit(lnext)) + syntax("missing exponent"); while (isdigit(lnext) && i < MAXWORD) { str[i++] = lnext; lnext = scan(); @@ -506,7 +548,7 @@ getnum() /* scan a positive float */ EPNODE * getE1() /* E1 -> E1 ADDOP E2 */ - /* E2 */ + /* E2 */ { register EPNODE *ep1, *ep2; @@ -517,10 +559,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); @@ -529,7 +570,7 @@ getE1() /* E1 -> E1 ADDOP E2 */ EPNODE * getE2() /* E2 -> E2 MULOP E3 */ - /* E3 */ + /* E3 */ { register EPNODE *ep1, *ep2; @@ -540,10 +581,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); @@ -552,7 +592,7 @@ getE2() /* E2 -> E2 MULOP E3 */ EPNODE * getE3() /* E3 -> E4 ^ E3 */ - /* E4 */ + /* E4 */ { register EPNODE *ep1, *ep2; @@ -563,10 +603,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); @@ -575,7 +614,7 @@ getE3() /* E3 -> E4 ^ E3 */ EPNODE * getE4() /* E4 -> ADDOP E5 */ - /* E5 */ + /* E5 */ { register EPNODE *ep1, *ep2; @@ -603,13 +642,13 @@ getE4() /* E4 -> ADDOP E5 */ EPNODE * getE5() /* E5 -> (E1) */ - /* VAR */ - /* NUM */ - /* $N */ - /* FUNC(E1,..) */ - /* ARG */ + /* VAR */ + /* NUM */ + /* $N */ + /* FUNC(E1,..) */ + /* ARG */ { - int i; + int i; char *nam; register EPNODE *ep1, *ep2; @@ -622,39 +661,34 @@ getE5() /* E5 -> (E1) */ return(ep1); } -#ifdef INCHAN - if (nextc == '$') { + if (esupport&E_INCHAN && nextc == '$') { scan(); ep1 = newnode(); ep1->type = CHAN; ep1->v.chan = getinum(); return(ep1); } -#endif -#if defined(VARIABLE) || defined(FUNCTION) - if (isalpha(nextc) || nextc == CNTXMARK) { - nam = getname(); -#if defined(VARIABLE) && defined(FUNCTION) - ep1 = NULL; - if (curfunc != NULL) + 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) + 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) -#endif - { + if (ep1 == NULL) { ep1 = newnode(); ep1->type = VAR; ep1->v.ln = varinsert(nam); } -#ifdef FUNCTION - if (nextc == '(') { + if (esupport&E_FUNCTION && nextc == '(') { ep2 = newnode(); ep2->type = FUNC; addekid(ep2, ep1); @@ -666,19 +700,12 @@ getE5() /* E5 -> (E1) */ if (nextc != ')') syntax("')' expected"); scan(); - } -#ifndef VARIABLE - else + } else if (!(esupport&E_VARIABLE)) syntax("'(' expected"); -#endif -#endif -#ifdef RCONST - if (isconstvar(ep1)) + if (esupport&E_RCONST && isconstvar(ep1)) ep1 = rconst(ep1); -#endif return(ep1); } -#endif if (isdecimal(nextc)) { ep1 = newnode(); @@ -690,10 +717,9 @@ getE5() /* E5 -> (E1) */ } -#ifdef RCONST EPNODE * rconst(epar) /* reduce a constant expression */ -register EPNODE *epar; +register EPNODE *epar; { register EPNODE *ep; @@ -701,22 +727,21 @@ 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); } +int isconstvar(ep) /* is ep linked to a constant expression? */ -register EPNODE *ep; +register EPNODE *ep; { -#ifdef VARIABLE register EPNODE *ep1; -#ifdef FUNCTION - if (ep->type == FUNC) { + 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) @@ -724,40 +749,32 @@ register EPNODE *ep; 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 } -#if defined(FUNCTION) && defined(VARIABLE) +int isconstfun(ep) /* is ep linked to a constant function? */ -register EPNODE *ep; +register EPNODE *ep; { register EPNODE *dp; register LIBR *lp; if (ep->type != VAR) return(0); - dp = ep->v.ln->def; - if (dp != NULL && dp->type != ':') - return(0); - if ((dp == NULL || dp->v.kid->type != FUNC) - && ((lp = liblookup(ep->v.ln->name)) == NULL - || lp->atyp != ':')) - return(0); - return(1); + 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); } -#endif -#endif