--- ray/src/common/calexpr.c 2003/06/07 12:50:20 2.22 +++ ray/src/common/calexpr.c 2024/02/24 19:00:23 2.44 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: calexpr.c,v 2.22 2003/06/07 12:50:20 schorsch Exp $"; +static const char RCSid[] = "$Id: calexpr.c,v 2.44 2024/02/24 19:00:23 greg Exp $"; #endif /* * Compute data values using expression parser @@ -19,32 +19,38 @@ static const char RCSid[] = "$Id: calexpr.c,v 2.22 200 #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 newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE)) -#define isdecimal(c) (isdigit(c) || (c) == '.') +#define isdecimal(c) (isdigit(c) | ((c) == '.')) -static double euminus(), eargument(), enumber(); -static double echannel(); -static double eadd(), esubtr(), emult(), edivi(), epow(); -static double ebotch(); +#define envalue(ep) ((ep)->type==NUM ? (ep)->v.num : evalue(ep)) +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 *); + 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, evariable, enumber, @@ -79,8 +85,9 @@ static int linepos; /* position in buffer */ EPNODE * -eparse(expr) /* parse an expression string */ -char *expr; +eparse( /* parse an expression string */ + char *expr +) { EPNODE *ep; @@ -94,22 +101,28 @@ char *expr; double -eval(expr) /* evaluate an expression string */ -char *expr; +eval( /* evaluate an expression string */ + char *expr +) { - register EPNODE *ep; + int prev_support = esupport; + EPNODE *ep; double rval; + esupport &= ~E_RCONST; /* don't bother reducing constant expr */ ep = eparse(expr); + esupport = prev_support; /* as you were */ rval = evalue(ep); - epfree(ep); + epfree(ep,1); return(rval); } int -epcmp(ep1, ep2) /* compare two expressions for equivalence */ -register EPNODE *ep1, *ep2; +epcmp( /* compare two expressions for equivalence */ + EPNODE *ep1, + EPNODE *ep2 +) { double d; @@ -125,7 +138,7 @@ register EPNODE *ep1, *ep2; if (ep2->v.num == 0) return(ep1->v.num != 0); d = ep1->v.num / ep2->v.num; - return(d > 1.000000000001 | d < 0.999999999999); + return((d > 1.000000000001) | (d < 0.999999999999)); case CHAN: case ARG: @@ -135,7 +148,7 @@ register EPNODE *ep1, *ep2; case ':': return(epcmp(ep1->v.kid->sibling, ep2->v.kid->sibling)); - case TICK: + case CLKT: case SYM: /* should never get this one */ return(0); @@ -156,10 +169,12 @@ register EPNODE *ep1, *ep2; void -epfree(epar) /* free a parse tree */ -register EPNODE *epar; +epfree( /* free a parse tree */ + EPNODE *epar, + int frep +) { - register EPNODE *ep; + EPNODE *ep; switch (epar->type) { @@ -174,111 +189,196 @@ register EPNODE *epar; case NUM: case CHAN: case ARG: - case TICK: + case CLKT: break; default: - while ((ep = epar->v.kid) != NULL) { - epar->v.kid = ep->sibling; - epfree(ep); - } + if (epar->nkids < 0) { + ep = epar->v.kid - epar->nkids; + while (ep > epar->v.kid) + epfree(--ep, 0); + efree(ep); /* free array space */ + } else + while ((ep = epar->v.kid) != NULL) { + epar->v.kid = ep->sibling; + epfree(ep, 1); + } break; } + if (frep) + efree(epar); +} - efree((char *)epar); + +void +epflatten( /* flatten hierarchies for '+', '*' */ + EPNODE *epar +) +{ + EPNODE *ep; + + if (epar->nkids < 0) /* don't really handle this properly */ + epar->nkids *= -1; + + for (ep = epar->v.kid; ep != NULL; ep = ep->sibling) + while (ep->type == epar->type) { + EPNODE *ep1 = ep->v.kid; + while (ep1->sibling != NULL) + ep1 = ep1->sibling; + ep1->sibling = ep->sibling; + epar->nkids += nekids(ep) - 1; + ep1 = ep->v.kid; + *ep = *ep1; + efree(ep1); /* not epfree()! */ + } } + +void +epoptimize( /* flatten operations and lists -> arrays */ + EPNODE *epar +) +{ + EPNODE *ep; + + if ((epar->type == '+') | (epar->type == '*')) + epflatten(epar); /* commutative & associative */ + + if (epar->nkids) /* do children if any */ + for (ep = epar->v.kid; ep != NULL; ep = ep->sibling) + epoptimize(ep); + + if (epar->nkids > 4) { /* make list into array if > 4 kids */ + int n = 1; + epar->v.kid = (EPNODE *)erealloc(epar->v.kid, + sizeof(EPNODE)*epar->nkids); + while (n < epar->nkids) { + ep = epar->v.kid[n-1].sibling; + epar->v.kid[n] = *ep; + efree(ep); /* not epfree()! */ + epar->v.kid[n-1].sibling = epar->v.kid + n; + n++; + } + epar->nkids = -n; + } +} + /* the following used to be a switch */ static double -eargument(ep) -EPNODE *ep; +eargument( + EPNODE *ep +) { return(argument(ep->v.chan)); } 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; + EPNODE *ep1 = ep->v.kid; return(-evalue(ep1)); } static double -echannel(ep) -EPNODE *ep; +echannel( + EPNODE *ep +) { return(chanvalue(ep->v.chan)); } static double -eadd(ep) -EPNODE *ep; +eadd( + EPNODE *ep +) { - register EPNODE *ep1 = ep->v.kid; + double sum = 0; + EPNODE *ep1 = ep->v.kid; - return(evalue(ep1) + evalue(ep1->sibling)); + do + sum += envalue(ep1); + while ((ep1 = ep1->sibling) != NULL); + + return(sum); } static double -esubtr(ep) -EPNODE *ep; +esubtr( + EPNODE *ep +) { - register EPNODE *ep1 = ep->v.kid; + EPNODE *ep1 = ep->v.kid; + EPNODE *ep2 = ep1->sibling; - return(evalue(ep1) - evalue(ep1->sibling)); + return(envalue(ep1) - envalue(ep2)); } static double -emult(ep) -EPNODE *ep; +emult( + EPNODE *ep +) { - register EPNODE *ep1 = ep->v.kid; + double prod = 1; + EPNODE *ep1 = ep->v.kid; - return(evalue(ep1) * evalue(ep1->sibling)); + do + prod *= envalue(ep1); + while ((ep1 = ep1->sibling) != NULL); + + return(prod); } static double -edivi(ep) -EPNODE *ep; +edivi( + EPNODE *ep +) { - register EPNODE *ep1 = ep->v.kid; + EPNODE *ep1 = ep->v.kid; + EPNODE *ep2 = ep1->sibling; double d; - d = evalue(ep1->sibling); + d = envalue(ep2); if (d == 0.0) { wputs("Division by zero\n"); errno = ERANGE; return(0.0); } - return(evalue(ep1) / d); + return(envalue(ep1) / d); } static double -epow(ep) -EPNODE *ep; +epow( + EPNODE *ep +) { - register EPNODE *ep1 = ep->v.kid; + EPNODE *ep1 = ep->v.kid; double d; int lasterrno; lasterrno = errno; errno = 0; d = pow(evalue(ep1), evalue(ep1->sibling)); -#ifdef IEEE - if (!finite(d)) - errno = EDOM; +#ifdef isnan + if (errno == 0) { + if (isnan(d)) + errno = EDOM; + else if (isinf(d)) + errno = ERANGE; + } #endif - if (errno == EDOM || errno == ERANGE) { + if ((errno == EDOM) | (errno == ERANGE)) { wputs("Illegal power\n"); return(0.0); } @@ -287,8 +387,9 @@ EPNODE *ep; } static double -ebotch(ep) -EPNODE *ep; +ebotch( + EPNODE *ep +) { eputs("Bad expression!\n"); quit(1); @@ -297,37 +398,30 @@ EPNODE *ep; 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 */ + EPNODE *ep, + int n +) { - - for (ep = ep->v.kid; ep != NULL; ep = ep->sibling) - if (--n < 0) - break; - + if (ep->nkids < 0) { /* allocated array? */ + if (n >= -ep->nkids) + return(NULL); + return(ep->v.kid + n); + } + ep = ep->v.kid; /* else get from list */ + while (n-- > 0) + if ((ep = ep->sibling) == NULL) + break; return(ep); } -int -nekids(ep) /* return # of kids for node ep */ -register EPNODE *ep; -{ - register int n = 0; - - for (ep = ep->v.kid; ep != NULL; ep = ep->sibling) - n++; - - return(n); -} - - void -initfile(fp, fn, ln) /* prepare input file */ -FILE *fp; -char *fn; -int ln; +initfile( /* prepare input file */ + FILE *fp, + char *fn, + int ln +) { static char inpbuf[MAXLINE]; @@ -342,10 +436,11 @@ int ln; void -initstr(s, fn, ln) /* prepare input string */ -char *s; -char *fn; -int ln; +initstr( /* prepare input string */ + char *s, + char *fn, + int ln +) { infp = NULL; infile = fn; @@ -357,11 +452,12 @@ int ln; void -getscanpos(fnp, lnp, spp, fpp) /* return current scan position */ -char **fnp; -int *lnp; -char **spp; -FILE **fpp; +getscanpos( /* return current scan position */ + char **fnp, + int *lnp, + char **spp, + FILE **fpp +) { if (fnp != NULL) *fnp = infile; if (lnp != NULL) *lnp = lineno; @@ -371,9 +467,9 @@ FILE **fpp; int -scan() /* scan next character, return literal next */ +scan(void) /* scan next character, return literal next */ { - register int lnext = 0; + int lnext = 0; do { if (linbuf[linepos] == '\0') @@ -388,6 +484,10 @@ scan() /* scan next character, return literal next nextc = linbuf[linepos++]; if (!lnext) lnext = nextc; + if (nextc == eofc) { + nextc = EOF; + break; + } if (nextc == '{') { scan(); while (nextc != '}') @@ -403,11 +503,12 @@ scan() /* scan next character, return literal next char * -long2ascii(l) /* convert long to ascii */ -long l; +long2ascii( /* convert long to ascii */ + long l +) { static char buf[16]; - register char *cp; + char *cp; int neg = 0; if (l == 0) @@ -429,12 +530,13 @@ long l; void -syntax(err) /* report syntax error and quit */ -char *err; +syntax( /* report syntax error and quit */ + char *err +) { - register int i; + int i; - if (infile != NULL || lineno != 0) { + if ((infile != NULL) | (lineno != 0)) { if (infile != NULL) eputs(infile); if (lineno != 0) { eputs(infile != NULL ? ", line " : "line "); @@ -455,29 +557,33 @@ char *err; void -addekid(ep, ekid) /* add a child to ep */ -register EPNODE *ep; -EPNODE *ekid; +addekid( /* add a child to ep */ + EPNODE *ep, + EPNODE *ek +) { + if (ep->nkids < 0) /* we don't really handle this properly */ + ep->nkids *= -1; + ep->nkids++; if (ep->v.kid == NULL) - ep->v.kid = ekid; + ep->v.kid = ek; else { for (ep = ep->v.kid; ep->sibling != NULL; ep = ep->sibling) ; - ep->sibling = ekid; + ep->sibling = ek; } - ekid->sibling = NULL; + ek->sibling = NULL; /* shouldn't be necessary */ } char * -getname() /* scan an identifier */ +getname(void) /* scan an identifier */ { - static char str[MAXWORD+1]; - register int i, lnext; + static char str[RMAXWORD+1]; + int i, lnext; lnext = nextc; - for (i = 0; i < MAXWORD && isid(lnext); i++, lnext = scan()) + for (i = 0; i < RMAXWORD && isid(lnext); i++, lnext = scan()) str[i] = lnext; str[i] = '\0'; while (isid(lnext)) /* skip rest of name */ @@ -488,9 +594,9 @@ getname() /* scan an identifier */ int -getinum() /* scan a positive integer */ +getinum(void) /* scan a positive integer */ { - register int n, lnext; + int n, lnext; n = 0; lnext = nextc; @@ -503,37 +609,37 @@ getinum() /* scan a positive integer */ double -getnum() /* scan a positive float */ +getnum(void) /* scan a positive float */ { - register int i, lnext; - char str[MAXWORD+1]; + int i, lnext; + char str[RMAXWORD+1]; i = 0; lnext = nextc; - while (isdigit(lnext) && i < MAXWORD) { + while (isdigit(lnext) && i < RMAXWORD) { str[i++] = lnext; lnext = scan(); } - if (lnext == '.' && i < MAXWORD) { + if ((lnext == '.') & (i < RMAXWORD)) { str[i++] = lnext; lnext = scan(); if (i == 1 && !isdigit(lnext)) syntax("badly formed number"); - while (isdigit(lnext) && i < MAXWORD) { + while (isdigit(lnext) && i < RMAXWORD) { str[i++] = lnext; lnext = scan(); } } - if ((lnext == 'e' | lnext == 'E') && i < MAXWORD) { + if ((lnext == 'e') | (lnext == 'E') && i < RMAXWORD) { str[i++] = lnext; lnext = scan(); - if ((lnext == '-' | lnext == '+') && i < MAXWORD) { + if ((lnext == '-') | (lnext == '+') && i < RMAXWORD) { str[i++] = lnext; lnext = scan(); } if (!isdigit(lnext)) syntax("missing exponent"); - while (isdigit(lnext) && i < MAXWORD) { + while (isdigit(lnext) && i < RMAXWORD) { str[i++] = lnext; lnext = scan(); } @@ -545,20 +651,20 @@ getnum() /* scan a positive float */ EPNODE * -getE1() /* E1 -> E1 ADDOP E2 */ +getE1(void) /* E1 -> E1 ADDOP E2 */ /* E2 */ { - register EPNODE *ep1, *ep2; + EPNODE *ep1, *ep2; ep1 = getE2(); - while (nextc == '+' || nextc == '-') { + while ((nextc == '+') | (nextc == '-')) { ep2 = newnode(); ep2->type = nextc; scan(); addekid(ep2, ep1); addekid(ep2, getE2()); if (esupport&E_RCONST && - ep1->type == NUM && ep1->sibling->type == NUM) + (ep1->type == NUM) & (ep1->sibling->type == NUM)) ep2 = rconst(ep2); ep1 = ep2; } @@ -567,21 +673,40 @@ getE1() /* E1 -> E1 ADDOP E2 */ EPNODE * -getE2() /* E2 -> E2 MULOP E3 */ +getE2(void) /* E2 -> E2 MULOP E3 */ /* E3 */ { - register EPNODE *ep1, *ep2; + EPNODE *ep1, *ep2; ep1 = getE3(); - while (nextc == '*' || nextc == '/') { + while ((nextc == '*') | (nextc == '/')) { ep2 = newnode(); ep2->type = nextc; scan(); addekid(ep2, ep1); addekid(ep2, getE3()); - if (esupport&E_RCONST && - ep1->type == NUM && ep1->sibling->type == NUM) - ep2 = rconst(ep2); + if (esupport&E_RCONST) { + EPNODE *ep3 = ep1->sibling; + if ((ep1->type == NUM) & (ep3->type == NUM)) { + ep2 = rconst(ep2); + } else if (ep3->type == NUM) { + if (ep2->type == '/') { + if (ep3->v.num == 0) + syntax("divide by zero constant"); + ep2->type = '*'; /* for speed */ + ep3->v.num = 1./ep3->v.num; + } else if (ep3->v.num == 0) { + ep1->sibling = NULL; /* (E2 * 0) */ + epfree(ep2,1); + ep2 = ep3; + } + } else if (ep1->type == NUM && ep1->v.num == 0) { + epfree(ep3,1); /* (0 * E3) or (0 / E3) */ + ep1->sibling = NULL; + efree(ep2); + ep2 = ep1; + } + } ep1 = ep2; } return(ep1); @@ -589,32 +714,50 @@ getE2() /* E2 -> E2 MULOP E3 */ EPNODE * -getE3() /* E3 -> E4 ^ E3 */ +getE3(void) /* E3 -> E4 ^ E3 */ /* E4 */ { - register EPNODE *ep1, *ep2; + EPNODE *ep1, *ep2; - ep1 = getE4(); - if (nextc == '^') { + ep1 = getE4(); + if (nextc != '^') + return(ep1); ep2 = newnode(); ep2->type = nextc; scan(); addekid(ep2, ep1); addekid(ep2, getE3()); - if (esupport&E_RCONST && - ep1->type == NUM && ep1->sibling->type == NUM) - ep2 = rconst(ep2); + if (esupport&E_RCONST) { + EPNODE *ep3 = ep1->sibling; + if ((ep1->type == NUM) & (ep3->type == NUM)) { + ep2 = rconst(ep2); + } else if (ep1->type == NUM && ep1->v.num == 0) { + epfree(ep3,1); /* (0 ^ E3) */ + ep1->sibling = NULL; + efree(ep2); + ep2 = ep1; + } else if ((ep3->type == NUM && ep3->v.num == 0) | + (ep1->type == NUM && ep1->v.num == 1)) { + epfree(ep2,1); /* (E4 ^ 0) or (1 ^ E3) */ + ep2 = newnode(); + ep2->type = NUM; + ep2->v.num = 1; + } else if (ep3->type == NUM && ep3->v.num == 1) { + efree(ep3); /* (E4 ^ 1) */ + ep1->sibling = NULL; + efree(ep2); + ep2 = ep1; + } + } return(ep2); - } - return(ep1); } EPNODE * -getE4() /* E4 -> ADDOP E5 */ +getE4(void) /* E4 -> ADDOP E5 */ /* E5 */ { - register EPNODE *ep1, *ep2; + EPNODE *ep1, *ep2; if (nextc == '-') { scan(); @@ -624,8 +767,9 @@ getE4() /* E4 -> ADDOP E5 */ return(ep2); } if (ep2->type == UMINUS) { /* don't generate -(-E5) */ - efree((char *)ep2); - return(ep2->v.kid); + ep1 = ep2->v.kid; + efree(ep2); + return(ep1); } ep1 = newnode(); ep1->type = UMINUS; @@ -639,7 +783,7 @@ getE4() /* E4 -> ADDOP E5 */ EPNODE * -getE5() /* E5 -> (E1) */ +getE5(void) /* E5 -> (E1) */ /* VAR */ /* NUM */ /* $N */ @@ -648,7 +792,7 @@ getE5() /* E5 -> (E1) */ { int i; char *nam; - register EPNODE *ep1, *ep2; + EPNODE *ep1, *ep2; if (nextc == '(') { scan(); @@ -658,7 +802,6 @@ getE5() /* E5 -> (E1) */ scan(); return(ep1); } - if (esupport&E_INCHAN && nextc == '$') { scan(); ep1 = newnode(); @@ -666,9 +809,8 @@ getE5() /* E5 -> (E1) */ ep1->v.chan = getinum(); return(ep1); } - if (esupport&(E_VARIABLE|E_FUNCTION) && - (isalpha(nextc) || nextc == CNTXMARK)) { + (isalpha(nextc) | (nextc == CNTXMARK))) { nam = getname(); ep1 = NULL; if ((esupport&(E_VARIABLE|E_FUNCTION)) == (E_VARIABLE|E_FUNCTION) @@ -704,7 +846,6 @@ getE5() /* E5 -> (E1) */ ep1 = rconst(ep1); return(ep1); } - if (isdecimal(nextc)) { ep1 = newnode(); ep1->type = NUM; @@ -717,28 +858,30 @@ getE5() /* E5 -> (E1) */ EPNODE * -rconst(epar) /* reduce a constant expression */ -register EPNODE *epar; +rconst( /* reduce a constant expression */ + EPNODE *epar +) { - register EPNODE *ep; + EPNODE *ep; ep = newnode(); ep->type = NUM; errno = 0; ep->v.num = evalue(epar); - if (errno == EDOM || errno == ERANGE) + if ((errno == EDOM) | (errno == ERANGE)) syntax("bad constant expression"); - epfree(epar); + epfree(epar,1); return(ep); } int -isconstvar(ep) /* is ep linked to a constant expression? */ -register EPNODE *ep; +isconstvar( /* is ep linked to a constant expression? */ + EPNODE *ep +) { - register EPNODE *ep1; + EPNODE *ep1; if (esupport&E_FUNCTION && ep->type == FUNC) { if (!isconstfun(ep->v.kid)) @@ -760,19 +903,21 @@ register EPNODE *ep; int -isconstfun(ep) /* is ep linked to a constant function? */ -register EPNODE *ep; +isconstfun( /* is ep linked to a constant function? */ + EPNODE *ep +) { - register EPNODE *dp; - register LIBR *lp; + EPNODE *dp; + LIBR *lp; if (ep->type != VAR) return(0); - if ((dp = ep->v.ln->def) != NULL) + 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);