--- ray/src/common/caldefn.c 1991/07/16 10:37:45 1.11 +++ ray/src/common/caldefn.c 2003/02/22 02:07:21 2.12 @@ -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: caldefn.c,v 2.12 2003/02/22 02:07:21 greg Exp $"; #endif - /* * Store variable definitions. * @@ -20,44 +17,110 @@ static char SCCSid[] = "$SunId$ LBL"; * 5/31/90 Added conditional compile (REDEFW) for redefinition warning. * * 4/23/91 Added ':' assignment for constant expressions + * + * 8/7/91 Added optional context path to append to variable names + * + * 5/17/2001 Fixed clock counter wrapping behavior + * + * 2/19/03 Eliminated conditional compiles in favor of esupport extern. */ +/* ==================================================================== + * The Radiance Software License, Version 1.0 + * + * Copyright (c) 1990 - 2002 The Regents of the University of California, + * through Lawrence Berkeley National Laboratory. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes Radiance software + * (http://radsite.lbl.gov/) + * developed by the Lawrence Berkeley National Laboratory + * (http://www.lbl.gov/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Radiance," "Lawrence Berkeley National Laboratory" + * and "The Regents of the University of California" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact radiance@radsite.lbl.gov. + * + * 5. Products derived from this software may not be called "Radiance", + * nor may "Radiance" appear in their name, without prior written + * permission of Lawrence Berkeley National Laboratory. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Lawrence Berkeley National Laboratory OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of Lawrence Berkeley National Laboratory. For more + * information on Lawrence Berkeley National Laboratory, please see + * . + */ + #include +#include + #include #include "calcomp.h" -#ifndef NHASH -#define NHASH 521 /* hash size (a prime!) */ +#ifndef NHASH +#define NHASH 521 /* hash size (a prime!) */ #endif -#define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE)) +#define hash(s) (shash(s)%NHASH) -extern char *ecalloc(), *savestr(); +#define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE)) static double dvalue(); -long eclock = -1; /* value storage timer */ +#define MAXCLOCK (1L<<31) /* clock wrap value */ +unsigned long eclock = 0; /* value storage timer */ + +#define MAXCNTX 1023 /* maximum context length */ + +static char context[MAXCNTX+1]; /* current context path */ + static VARDEF *hashtbl[NHASH]; /* definition list */ static int htndx; /* index for */ static VARDEF *htpos; /* ...dfirst() and */ -#ifdef OUTCHAN static EPNODE *ochpos; /* ...dnext */ static EPNODE *outchan; -#endif -#ifdef FUNCTION -EPNODE *curfunc; -#define dname(ep) ((ep)->v.kid->type == SYM ? \ +EPNODE *curfunc = NULL; +#define dname(ep) ((ep)->v.kid->type == SYM ? \ (ep)->v.kid->v.name : \ (ep)->v.kid->v.kid->v.name) -#else -#define dname(ep) ((ep)->v.kid->v.name) -#endif +void fcompile(fname) /* get definitions from a file */ char *fname; { @@ -72,12 +135,13 @@ char *fname; } initfile(fp, fname, 0); while (nextc != EOF) - loaddefn(); + getstatement(); if (fname != NULL) fclose(fp); } +void scompile(str, fn, ln) /* get definitions from a string */ char *str; char *fn; @@ -85,7 +149,7 @@ int ln; { initstr(str, fn, ln); while (nextc != EOF) - loaddefn(); + getstatement(); } @@ -99,7 +163,7 @@ char *vname; double evariable(ep) /* evaluate a variable */ -EPNODE *ep; +EPNODE *ep; { register VARDEF *dp = ep->v.ln; @@ -107,14 +171,18 @@ EPNODE *ep; } +void varset(vname, assign, val) /* set a variable's value */ char *vname; int assign; -double val; +double val; { + char *qname; register EPNODE *ep1, *ep2; + /* get qualified name */ + qname = qualname(vname, 0); /* check for quick set */ - if ((ep1 = dlookup(vname)) != NULL && ep1->v.kid->type == SYM) { + if ((ep1 = dlookup(qname)) != NULL && ep1->v.kid->type == SYM) { ep2 = ep1->v.kid->sibling; if (ep2->type == NUM) { ep2->v.num = val; @@ -133,11 +201,12 @@ double val; ep2->type = NUM; ep2->v.num = val; addekid(ep1, ep2); - dremove(vname); - dpush(ep1); + dremove(qname); + dpush(qname, ep1); } +void dclear(name) /* delete variable definitions of name */ char *name; { @@ -145,7 +214,7 @@ char *name; while ((ep = dpop(name)) != NULL) { if (ep->type == ':') { - dpush(ep); /* don't clear constants */ + dpush(name, ep); /* don't clear constants */ return; } epfree(ep); @@ -153,6 +222,7 @@ char *name; } +void dremove(name) /* delete all definitions of name */ char *name; { @@ -163,6 +233,7 @@ char *name; } +int vardefined(name) /* return non-zero if variable defined */ char *name; { @@ -172,7 +243,134 @@ char *name; } -#ifdef OUTCHAN +char * +setcontext(ctx) /* set a new context path */ +register char *ctx; +{ + register char *cpp; + + if (ctx == NULL) + return(context); /* just asking */ + while (*ctx == CNTXMARK) + ctx++; /* skip past marks */ + if (!*ctx) { + context[0] = '\0'; /* empty means clear context */ + return(context); + } + cpp = context; /* start context with mark */ + *cpp++ = CNTXMARK; + do { /* carefully copy new context */ + if (cpp >= context+MAXCNTX) + break; /* just copy what we can */ + if (isid(*ctx)) + *cpp++ = *ctx++; + else { + *cpp++ = '_'; ctx++; + } + } while (*ctx); + while (cpp[-1] == CNTXMARK) /* cannot end in context mark */ + cpp--; + *cpp = '\0'; + return(context); +} + + +char * +pushcontext(ctx) /* push on another context */ +char *ctx; +{ + extern char *strncpy(), *strcpy(); + char oldcontext[MAXCNTX+1]; + register int n; + + strcpy(oldcontext, context); /* save old context */ + setcontext(ctx); /* set new context */ + n = strlen(context); /* tack on old */ + if (n+strlen(oldcontext) > MAXCNTX) { + strncpy(context+n, oldcontext, MAXCNTX-n); + context[MAXCNTX] = '\0'; + } else + strcpy(context+n, oldcontext); + return(context); +} + + +char * +popcontext() /* pop off top context */ +{ + register char *cp1, *cp2; + + if (!context[0]) /* nothing left to pop */ + return(context); + cp2 = context; /* find mark */ + while (*++cp2 && *cp2 != CNTXMARK) + ; + cp1 = context; /* copy tail to front */ + while (*cp1++ = *cp2++) + ; + return(context); +} + + +char * +qualname(nam, lvl) /* get qualified name */ +register char *nam; +int lvl; +{ + static char nambuf[MAXWORD+1]; + register char *cp = nambuf, *cpp; + /* check for explicit local */ + if (*nam == CNTXMARK) + if (lvl > 0) /* only action is to refuse search */ + return(NULL); + else + nam++; + else if (nam == nambuf) /* check for repeat call */ + return(lvl > 0 ? NULL : nam); + /* copy name to static buffer */ + while (*nam) { + if (cp >= nambuf+MAXWORD) + goto toolong; + *cp++ = *nam++; + } + /* check for explicit global */ + if (cp > nambuf && cp[-1] == CNTXMARK) { + if (lvl > 0) + return(NULL); + *--cp = '\0'; + return(nambuf); /* already qualified */ + } + cpp = context; /* else skip the requested levels */ + while (lvl-- > 0) { + if (!*cpp) + return(NULL); /* return NULL if past global level */ + while (*++cpp && *cpp != CNTXMARK) + ; + } + while (*cpp) { /* copy context to static buffer */ + if (cp >= nambuf+MAXWORD) + goto toolong; + *cp++ = *cpp++; + } +toolong: + *cp = '\0'; + return(nambuf); /* return qualified name */ +} + + +int +incontext(qn) /* is qualified name in current context? */ +register char *qn; +{ + if (!context[0]) /* global context accepts all */ + return(1); + while (*qn && *qn != CNTXMARK) /* find context mark */ + qn++; + return(!strcmp(qn, context)); +} + + +void chanout(cs) /* set output channels */ int (*cs)(); { @@ -182,29 +380,28 @@ int (*cs)(); (*cs)(ep->v.kid->v.chan, evalue(ep->v.kid->sibling)); } -#endif -dcleanup(lvl) /* clear definitions (0->vars,1->consts,2->output) */ +void +dcleanup(lvl) /* clear definitions (0->vars,1->output,2->consts) */ int lvl; { register int i; register VARDEF *vp; register EPNODE *ep; - + /* if context is global, clear all */ for (i = 0; i < NHASH; i++) for (vp = hashtbl[i]; vp != NULL; vp = vp->next) - if (lvl >= 1) - dremove(vp->name); - else - dclear(vp->name); -#ifdef OUTCHAN - if (lvl >= 2) { + if (incontext(vp->name)) + if (lvl >= 2) + dremove(vp->name); + else + dclear(vp->name); + if (lvl >= 1) { for (ep = outchan; ep != NULL; ep = ep->sibling) epfree(ep); outchan = NULL; } -#endif } @@ -215,7 +412,7 @@ char *name; register VARDEF *vp; if ((vp = varlookup(name)) == NULL) - return(NULL); + return(NULL); return(vp->def); } @@ -224,11 +421,14 @@ VARDEF * varlookup(name) /* look up a variable */ char *name; { + int lvl = 0; + register char *qname; register VARDEF *vp; - - for (vp = hashtbl[hash(name)]; vp != NULL; vp = vp->next) - if (!strcmp(vp->name, name)) - return(vp); + /* find most qualified match */ + while ((qname = qualname(name, lvl++)) != NULL) + for (vp = hashtbl[hash(qname)]; vp != NULL; vp = vp->next) + if (!strcmp(vp->name, qname)) + return(vp); return(NULL); } @@ -238,42 +438,58 @@ varinsert(name) /* get a link to a variable */ char *name; { register VARDEF *vp; - int hv; + int hv; - hv = hash(name); - for (vp = hashtbl[hv]; vp != NULL; vp = vp->next) - if (!strcmp(vp->name, name)) { - vp->nlinks++; - return(vp); - } + if ((vp = varlookup(name)) != NULL) { + vp->nlinks++; + return(vp); + } vp = (VARDEF *)emalloc(sizeof(VARDEF)); + vp->lib = liblookup(name); + if (vp->lib == NULL) /* if name not in library */ + name = qualname(name, 0); /* use fully qualified version */ + hv = hash(name); vp->name = savestr(name); vp->nlinks = 1; vp->def = NULL; - vp->lib = NULL; vp->next = hashtbl[hv]; hashtbl[hv] = vp; return(vp); } +void +libupdate(fn) /* update library links */ +char *fn; +{ + register int i; + register VARDEF *vp; + /* if fn is NULL then relink all */ + for (i = 0; i < NHASH; i++) + for (vp = hashtbl[i]; vp != NULL; vp = vp->next) + if (vp->lib != NULL || fn == NULL || !strcmp(fn, vp->name)) + vp->lib = liblookup(vp->name); +} + + +void varfree(ln) /* release link to variable */ -register VARDEF *ln; +register VARDEF *ln; { register VARDEF *vp; - int hv; + int hv; if (--ln->nlinks > 0) - return; /* still active */ + return; /* still active */ hv = hash(ln->name); vp = hashtbl[hv]; if (vp == ln) - hashtbl[hv] = vp->next; + hashtbl[hv] = vp->next; else { - while (vp->next != ln) /* must be in list */ - vp = vp->next; - vp->next = ln->next; + while (vp->next != ln) /* must be in list */ + vp = vp->next; + vp->next = ln->next; } freestr(ln->name); efree((char *)ln); @@ -285,9 +501,7 @@ dfirst() /* return pointer to first definition */ { htndx = 0; htpos = NULL; -#ifdef OUTCHAN ochpos = outchan; -#endif return(dnext()); } @@ -296,24 +510,22 @@ EPNODE * dnext() /* return pointer to next definition */ { register EPNODE *ep; + register char *nm; while (htndx < NHASH) { - if (htpos == NULL) - htpos = hashtbl[htndx++]; - while (htpos != NULL) { - ep = htpos->def; - htpos = htpos->next; - if (ep != NULL) - return(ep); - } + if (htpos == NULL) + htpos = hashtbl[htndx++]; + while (htpos != NULL) { + ep = htpos->def; + nm = htpos->name; + htpos = htpos->next; + if (ep != NULL && incontext(nm)) + return(ep); + } } -#ifdef OUTCHAN if ((ep = ochpos) != NULL) - ochpos = ep->sibling; + ochpos = ep->sibling; return(ep); -#else - return(NULL); -#endif } @@ -325,7 +537,7 @@ char *name; register EPNODE *dp; if ((vp = varlookup(name)) == NULL || vp->def == NULL) - return(NULL); + return(NULL); dp = vp->def; vp->def = dp->sibling; varfree(vp); @@ -333,22 +545,24 @@ char *name; } -dpush(ep) /* push on a definition */ -register EPNODE *ep; +void +dpush(nm, ep) /* push on a definition */ +char *nm; +register EPNODE *ep; { register VARDEF *vp; - vp = varinsert(dname(ep)); + vp = varinsert(nm); ep->sibling = vp->def; vp->def = ep; } -#ifdef OUTCHAN +void addchan(sp) /* add an output channel assignment */ -EPNODE *sp; +EPNODE *sp; { - int ch = sp->v.kid->v.chan; + int ch = sp->v.kid->v.chan; register EPNODE *ep, *epl; for (epl = NULL, ep = outchan; ep != NULL; epl = ep, ep = ep->sibling) @@ -372,47 +586,42 @@ EPNODE *sp; sp->sibling = NULL; } -#endif -loaddefn() /* load next definition */ +void +getstatement() /* get next statement */ { register EPNODE *ep; - EPNODE *lastdef; + char *qname; + register VARDEF *vdef; if (nextc == ';') { /* empty statement */ scan(); return; } -#ifdef OUTCHAN - if (nextc == '$') { /* channel assignment */ + if (esupport&E_OUTCHAN && + nextc == '$') { /* channel assignment */ ep = getchan(); addchan(ep); - } else -#endif - { /* ordinary definition */ + } else { /* ordinary definition */ ep = getdefn(); -#ifdef REDEFW - if ((lastdef = dlookup(dname(ep))) != NULL) { - wputs(dname(ep)); - if (lastdef->type == ':') - wputs(": redefined constant expression\n"); - else - wputs(": redefined\n"); - } -#ifdef FUNCTION - else if (ep->v.kid->type == FUNC && - liblookup(ep->v.kid->v.kid->v.name) != NULL) { - wputs(ep->v.kid->v.kid->v.name); - wputs(": definition hides library function\n"); - } -#endif -#endif + qname = qualname(dname(ep), 0); + if (esupport&E_REDEFW && (vdef = varlookup(qname)) != NULL) + if (vdef->def != NULL && epcmp(ep, vdef->def)) { + wputs(qname); + if (vdef->def->type == ':') + wputs(": redefined constant expression\n"); + else + wputs(": redefined\n"); + } else if (ep->v.kid->type == FUNC && vdef->lib != NULL) { + wputs(qname); + wputs(": definition hides library function\n"); + } if (ep->type == ':') - dremove(dname(ep)); + dremove(qname); else - dclear(dname(ep)); - dpush(ep); + dclear(qname); + dpush(qname, ep); } if (nextc != EOF) { if (nextc != ';') @@ -425,20 +634,19 @@ loaddefn() /* load next definition */ EPNODE * getdefn() /* A -> SYM = E1 */ /* SYM : E1 */ - /* FUNC(SYM,..) = E1 */ + /* FUNC(SYM,..) = E1 */ /* FUNC(SYM,..) : E1 */ { register EPNODE *ep1, *ep2; - if (!isalpha(nextc)) + if (!isalpha(nextc) && nextc != CNTXMARK) syntax("illegal variable name"); ep1 = newnode(); ep1->type = SYM; ep1->v.name = savestr(getname()); -#ifdef FUNCTION - if (nextc == '(') { + if (esupport&E_FUNCTION && nextc == '(') { ep2 = newnode(); ep2->type = FUNC; addekid(ep2, ep1); @@ -456,9 +664,7 @@ getdefn() /* A -> SYM = E1 */ syntax("')' expected"); scan(); curfunc = ep1; - } else - curfunc = NULL; -#endif + } if (nextc != '=' && nextc != ':') syntax("'=' or ':' expected"); @@ -469,25 +675,21 @@ getdefn() /* A -> SYM = E1 */ addekid(ep2, ep1); addekid(ep2, getE1()); - if ( -#ifdef FUNCTION - ep1->type == SYM && -#endif - ep1->sibling->type != NUM) { + if (ep1->type == SYM && ep1->sibling->type != NUM) { ep1 = newnode(); ep1->type = TICK; - ep1->v.tick = -1; + ep1->v.tick = 0; addekid(ep2, ep1); ep1 = newnode(); ep1->type = NUM; addekid(ep2, ep1); } + curfunc = NULL; return(ep2); } -#ifdef OUTCHAN EPNODE * getchan() /* A -> $N = E1 */ { @@ -512,7 +714,6 @@ getchan() /* A -> $N = E1 */ return(ep2); } -#endif @@ -524,7 +725,7 @@ getchan() /* A -> $N = E1 */ static double dvalue(name, d) /* evaluate a variable */ char *name; -EPNODE *d; +EPNODE *d; { register EPNODE *ep1, *ep2; @@ -537,25 +738,15 @@ EPNODE *d; if (ep1->type == NUM) return(ep1->v.num); /* return if number */ ep2 = ep1->sibling; /* check time */ - if (ep2->v.tick < 0 || ep2->v.tick < eclock) { - ep2->v.tick = d->type == ':' ? 1L<<30 : eclock; + if (eclock >= MAXCLOCK) + eclock = 1; /* wrap clock counter */ + if (ep2->v.tick < MAXCLOCK && + ep2->v.tick == 0 | ep2->v.tick != eclock) { + ep2->v.tick = d->type == ':' ? MAXCLOCK : eclock; ep2 = ep2->sibling; ep2->v.num = evalue(ep1); /* needs new value */ } else ep2 = ep2->sibling; /* else reuse old value */ return(ep2->v.num); -} - - -static int -hash(s) /* hash a string */ -register char *s; -{ - register int rval = 0; - - while (*s) - rval += *s++; - - return(rval % NHASH); }