--- ray/src/common/calexpr.c 1990/08/18 16:28:52 1.7 +++ ray/src/common/calexpr.c 1998/08/17 17:57:30 2.17 @@ -1,7 +1,7 @@ -/* Copyright (c) 1986 Regents of the University of California */ +/* Copyright (c) 1998 Silicon Graphics, Inc. */ #ifndef lint -static char SCCSid[] = "$SunId$ LBL"; +static char SCCSid[] = "$SunId$ SGI"; #endif /* @@ -24,44 +24,48 @@ static char SCCSid[] = "$SunId$ LBL"; #include +#include + #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) == '.') - -extern double atof(), pow(); -extern char *fgets(), *savestr(); +extern char *savestr(); extern char *emalloc(), *ecalloc(); extern EPNODE *curfunc; extern double efunc(), evariable(); -static double euminus(), echannel(), eargument(), enumber(); +static double euminus(), eargument(), enumber(); +#ifdef INCHAN +static double echannel(); +#endif static double eadd(), esubtr(), emult(), edivi(), epow(); static double ebotch(); -extern int errno; +#ifdef DCL_ATOF +extern double atof(); +#endif + int nextc; /* lookahead character */ -double (*eoper[])() = { /* expression operations */ +double (*eoper[])() = { /* expression operations */ ebotch, -#ifdef VARIABLE +#ifdef VARIABLE evariable, #else ebotch, #endif enumber, euminus, -#ifdef INCHAN +#ifdef INCHAN echannel, #else ebotch, #endif -#ifdef FUNCTION +#ifdef FUNCTION efunc, eargument, #else @@ -78,8 +82,10 @@ double (*eoper[])() = { /* expression operations */ esubtr, 0, edivi, - 0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, ebotch, + 0,0, + 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, epow, @@ -123,8 +129,55 @@ char *expr; } +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); + } +} + + epfree(epar) /* free a parse tree */ -register EPNODE *epar; +register EPNODE *epar; { register EPNODE *ep; @@ -134,11 +187,11 @@ register EPNODE *epar; case VAR: varfree(epar->v.ln); break; -#endif case SYM: freestr(epar->v.name); break; +#endif case NUM: case CHAN: @@ -147,8 +200,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; } @@ -157,10 +212,10 @@ register EPNODE *epar; } /* the following used to be a switch */ -#ifdef FUNCTION +#ifdef FUNCTION static double eargument(ep) -EPNODE *ep; +EPNODE *ep; { return(argument(ep->v.chan)); } @@ -168,24 +223,24 @@ EPNODE *ep; 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 +#ifdef INCHAN static double echannel(ep) -EPNODE *ep; +EPNODE *ep; { return(chanvalue(ep->v.chan)); } @@ -193,7 +248,7 @@ EPNODE *ep; static double eadd(ep) -EPNODE *ep; +EPNODE *ep; { register EPNODE *ep1 = ep->v.kid; @@ -202,7 +257,7 @@ EPNODE *ep; static double esubtr(ep) -EPNODE *ep; +EPNODE *ep; { register EPNODE *ep1 = ep->v.kid; @@ -211,7 +266,7 @@ EPNODE *ep; static double emult(ep) -EPNODE *ep; +EPNODE *ep; { register EPNODE *ep1 = ep->v.kid; @@ -220,7 +275,7 @@ EPNODE *ep; static double edivi(ep) -EPNODE *ep; +EPNODE *ep; { register EPNODE *ep1 = ep->v.kid; double d; @@ -236,16 +291,16 @@ 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 @@ -259,7 +314,7 @@ EPNODE *ep; static double ebotch(ep) -EPNODE *ep; +EPNODE *ep; { eputs("Bad expression!\n"); quit(1); @@ -268,7 +323,7 @@ EPNODE *ep; EPNODE * ekid(ep, n) /* return pointer to a node's nth kid */ -register EPNODE *ep; +register EPNODE *ep; register int n; { @@ -282,7 +337,7 @@ register int n; int nekids(ep) /* return # of kids for node ep */ -register EPNODE *ep; +register EPNODE *ep; { register int n = 0; @@ -298,7 +353,7 @@ FILE *fp; char *fn; int ln; { - static char inpbuf[MAXLINE]; + static char inpbuf[MAXLINE]; infp = fp; linbuf = inpbuf; @@ -324,8 +379,24 @@ int ln; } -scan() /* scan next character */ +getscanpos(fnp, lnp, spp, fpp) /* 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() /* scan next character, return literal next */ +{ + register int lnext = 0; + do { if (linbuf[linepos] == '\0') if (infp == NULL || fgets(linbuf, MAXLINE, infp) == NULL) @@ -337,6 +408,8 @@ scan() /* scan next character */ } else nextc = linbuf[linepos++]; + if (!lnext) + lnext = nextc; if (nextc == '{') { scan(); while (nextc != '}') @@ -347,16 +420,17 @@ scan() /* scan next character */ scan(); } } while (isspace(nextc)); + return(lnext); } 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"); @@ -385,9 +459,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') @@ -402,8 +476,8 @@ char *err; 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; @@ -416,29 +490,35 @@ EPNODE *ekid; } +#if defined(VARIABLE) || defined(FUNCTION) char * getname() /* scan an identifier */ { - static char str[MAXWORD+1]; - register int i; + static char str[MAXWORD+1]; + register int i, lnext; - for (i = 0; i < MAXWORD && isid(nextc); i++, scan()) - str[i] = nextc; + lnext = nextc; + for (i = 0; i < MAXWORD && isid(lnext); i++, lnext = scan()) + str[i] = lnext; str[i] = '\0'; + while (isid(lnext)) /* skip rest of name */ + lnext = scan(); return(str); } +#endif int getinum() /* 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); } @@ -447,32 +527,37 @@ getinum() /* scan a positive integer */ double getnum() /* scan a positive float */ { - register int i; + register int i, lnext; char str[MAXWORD+1]; i = 0; - while (isdigit(nextc) && i < MAXWORD) { - str[i++] = nextc; - scan(); + lnext = nextc; + while (isdigit(lnext) && i < MAXWORD) { + 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 < MAXWORD) { + 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 ((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 < MAXWORD) { + str[i++] = lnext; + lnext = scan(); + if ((lnext == '-' | lnext == '+') && i < MAXWORD) { + str[i++] = lnext; + lnext = scan(); } - while (isdigit(nextc) && i < MAXWORD) { - str[i++] = nextc; - scan(); + if (!isdigit(lnext)) + syntax("missing exponent"); + while (isdigit(lnext) && i < MAXWORD) { + str[i++] = lnext; + lnext = scan(); } } str[i] = '\0'; @@ -483,7 +568,7 @@ getnum() /* scan a positive float */ EPNODE * getE1() /* E1 -> E1 ADDOP E2 */ - /* E2 */ + /* E2 */ { register EPNODE *ep1, *ep2; @@ -494,7 +579,7 @@ getE1() /* E1 -> E1 ADDOP E2 */ scan(); addekid(ep2, ep1); addekid(ep2, getE2()); -#ifdef RCONST +#ifdef RCONST if (ep1->type == NUM && ep1->sibling->type == NUM) ep2 = rconst(ep2); #endif @@ -506,7 +591,7 @@ getE1() /* E1 -> E1 ADDOP E2 */ EPNODE * getE2() /* E2 -> E2 MULOP E3 */ - /* E3 */ + /* E3 */ { register EPNODE *ep1, *ep2; @@ -517,7 +602,7 @@ getE2() /* E2 -> E2 MULOP E3 */ scan(); addekid(ep2, ep1); addekid(ep2, getE3()); -#ifdef RCONST +#ifdef RCONST if (ep1->type == NUM && ep1->sibling->type == NUM) ep2 = rconst(ep2); #endif @@ -528,23 +613,23 @@ getE2() /* E2 -> E2 MULOP E3 */ EPNODE * -getE3() /* E3 -> E3 ^ E4 */ - /* E4 */ +getE3() /* E3 -> E4 ^ E3 */ + /* E4 */ { register EPNODE *ep1, *ep2; ep1 = getE4(); - while (nextc == '^') { + if (nextc == '^') { ep2 = newnode(); ep2->type = nextc; scan(); addekid(ep2, ep1); - addekid(ep2, getE4()); -#ifdef RCONST + addekid(ep2, getE3()); +#ifdef RCONST if (ep1->type == NUM && ep1->sibling->type == NUM) ep2 = rconst(ep2); #endif - ep1 = ep2; + return(ep2); } return(ep1); } @@ -552,7 +637,7 @@ getE3() /* E3 -> E3 ^ E4 */ EPNODE * getE4() /* E4 -> ADDOP E5 */ - /* E5 */ + /* E5 */ { register EPNODE *ep1, *ep2; @@ -563,6 +648,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); @@ -576,13 +665,14 @@ 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; if (nextc == '(') { @@ -594,7 +684,7 @@ getE5() /* E5 -> (E1) */ return(ep1); } -#ifdef INCHAN +#ifdef INCHAN if (nextc == '$') { scan(); ep1 = newnode(); @@ -605,24 +695,27 @@ getE5() /* E5 -> (E1) */ #endif #if defined(VARIABLE) || defined(FUNCTION) - if (isalpha(nextc)) { - ep1 = newnode(); - ep1->type = VAR; - ep1->v.ln = varinsert(getname()); - + if (isalpha(nextc) || nextc == CNTXMARK) { + nam = getname(); #if defined(VARIABLE) && defined(FUNCTION) + ep1 = NULL; 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); + 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 -#ifdef FUNCTION + { + ep1 = newnode(); + ep1->type = VAR; + ep1->v.ln = varinsert(nam); + } +#ifdef FUNCTION if (nextc == '(') { ep2 = newnode(); ep2->type = FUNC; @@ -636,11 +729,15 @@ getE5() /* E5 -> (E1) */ syntax("')' expected"); scan(); } -#ifndef VARIABLE +#ifndef VARIABLE else syntax("'(' expected"); #endif #endif +#ifdef RCONST + if (isconstvar(ep1)) + ep1 = rconst(ep1); +#endif return(ep1); } #endif @@ -655,10 +752,10 @@ getE5() /* E5 -> (E1) */ } -#ifdef RCONST +#ifdef RCONST EPNODE * rconst(epar) /* reduce a constant expression */ -register EPNODE *epar; +register EPNODE *epar; { register EPNODE *ep; @@ -667,9 +764,59 @@ register EPNODE *epar; errno = 0; ep->v.num = evalue(epar); if (errno) - syntax("bad constant expression"); + syntax("bad constant expression"); epfree(epar); return(ep); } + + +isconstvar(ep) /* is ep linked to a constant expression? */ +register EPNODE *ep; +{ +#ifdef VARIABLE + register EPNODE *ep1; +#ifdef FUNCTION + + if (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 && !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) + return(0); +#endif + return(1); +#else + return(ep->type == FUNC); +#endif +} + + +#if defined(FUNCTION) && defined(VARIABLE) +isconstfun(ep) /* 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 && dp->v.kid->type == FUNC) + return(dp->type == ':'); + if ((lp = ep->v.ln->lib) != NULL) + return(lp->atyp == ':'); + return(0); +} +#endif #endif