ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
(Generate patch)

Comparing ray/src/common/caldefn.c (file contents):
Revision 1.4 by greg, Thu Jul 19 11:06:37 1990 UTC vs.
Revision 2.11 by greg, Wed Feb 12 17:38:03 1997 UTC

# Line 1 | Line 1
1 < /* Copyright (c) 1986 Regents of the University of California */
1 > /* Copyright (c) 1997 Regents of the University of California */
2  
3   #ifndef lint
4   static char SCCSid[] = "$SunId$ LBL";
# Line 18 | Line 18 | static char SCCSid[] = "$SunId$ LBL";
18   *  11/16/88  Added VARDEF structure for hard linking.
19   *
20   *  5/31/90  Added conditional compile (REDEFW) for redefinition warning.
21 + *
22 + *  4/23/91  Added ':' assignment for constant expressions
23 + *
24 + *  8/7/91  Added optional context path to append to variable names
25   */
26  
27   #include  <stdio.h>
# Line 26 | Line 30 | static char SCCSid[] = "$SunId$ LBL";
30  
31   #include  "calcomp.h"
32  
33 < #ifndef  NHASH
34 < #define  NHASH          521             /* hash size (a prime!) */
33 > #ifndef  NHASH
34 > #define  NHASH          521             /* hash size (a prime!) */
35   #endif
36  
37 < #define  newnode()      (EPNODE *)ecalloc(1, sizeof(EPNODE))
37 > #define  hash(s)        (shash(s)%NHASH)
38  
39 < extern char  *ecalloc(), *savestr();
39 > #define  newnode()      (EPNODE *)ecalloc(1, sizeof(EPNODE))
40  
41 + extern char  *ecalloc(), *emalloc(), *savestr(), *strcpy();
42 +
43   static double  dvalue();
44  
45 < long  eclock = -1;                      /* value storage timer */
45 > unsigned long  eclock = 0;              /* value storage timer */
46  
47 + #define  MAXCNTX        1023            /* maximum context length */
48 +
49 + static char  context[MAXCNTX+1];        /* current context path */
50 +
51   static VARDEF  *hashtbl[NHASH];         /* definition list */
52   static int  htndx;                      /* index for */        
53   static VARDEF  *htpos;                  /* ...dfirst() and */
54 < #ifdef  OUTCHAN
54 > #ifdef  OUTCHAN
55   static EPNODE  *ochpos;                 /* ...dnext */
56   static EPNODE  *outchan;
57   #endif
58  
59 < #ifdef  FUNCTION
60 < EPNODE  *curfunc;
61 < #define  dname(ep)      ((ep)->v.kid->type == SYM ? \
59 > #ifdef  FUNCTION
60 > EPNODE  *curfunc = NULL;
61 > #define  dname(ep)      ((ep)->v.kid->type == SYM ? \
62                          (ep)->v.kid->v.name : \
63                          (ep)->v.kid->v.kid->v.name)
64   #else
65 < #define  dname(ep)      ((ep)->v.kid->v.name)
65 > #define  dname(ep)      ((ep)->v.kid->v.name)
66   #endif
67  
68  
# Line 70 | Line 80 | char  *fname;
80      }
81      initfile(fp, fname, 0);
82      while (nextc != EOF)
83 <        loaddefn();
83 >        getstatement();
84      if (fname != NULL)
85          fclose(fp);
86   }
# Line 83 | Line 93 | int  ln;
93   {
94      initstr(str, fn, ln);
95      while (nextc != EOF)
96 <        loaddefn();
96 >        getstatement();
97   }
98  
99  
# Line 97 | Line 107 | char  *vname;
107  
108   double
109   evariable(ep)                   /* evaluate a variable */
110 < EPNODE  *ep;
110 > EPNODE  *ep;
111   {
112      register VARDEF  *dp = ep->v.ln;
113  
# Line 105 | Line 115 | EPNODE  *ep;
115   }
116  
117  
118 < varset(vname, val)              /* set a variable's value */
118 > varset(vname, assign, val)      /* set a variable's value */
119   char  *vname;
120 < double  val;
120 > int  assign;
121 > double  val;
122   {
123 +    char  *qname;
124      register EPNODE  *ep1, *ep2;
125 +                                        /* get qualified name */
126 +    qname = qualname(vname, 0);
127                                          /* check for quick set */
128 <    if ((ep1 = dlookup(vname)) != NULL && ep1->v.kid->type == SYM) {
128 >    if ((ep1 = dlookup(qname)) != NULL && ep1->v.kid->type == SYM) {
129          ep2 = ep1->v.kid->sibling;
130          if (ep2->type == NUM) {
131              ep2->v.num = val;
132 <            ep2->sibling->v.tick = -1;
132 >            ep1->type = assign;
133              return;
134          }
135      }
136                                          /* hand build definition */
137      ep1 = newnode();
138 <    ep1->type = '=';
138 >    ep1->type = assign;
139      ep2 = newnode();
140      ep2->type = SYM;
141      ep2->v.name = savestr(vname);
# Line 130 | Line 144 | double  val;
144      ep2->type = NUM;
145      ep2->v.num = val;
146      addekid(ep1, ep2);
147 <    ep2 = newnode();
148 <    ep2->type = TICK;
135 <    ep2->v.tick = -1;
136 <    addekid(ep1, ep2);
137 <    ep2 = newnode();
138 <    ep2->type = NUM;
139 <    addekid(ep1, ep2);
140 <    dclear(vname);
141 <    dpush(ep1);
147 >    dremove(qname);
148 >    dpush(qname, ep1);
149   }
150  
151  
152 < dclear(name)                    /* delete all definitions of name */
152 > dclear(name)                    /* delete variable definitions of name */
153   char  *name;
154   {
155      register EPNODE  *ep;
156  
157 +    while ((ep = dpop(name)) != NULL) {
158 +        if (ep->type == ':') {
159 +            dpush(name, ep);            /* don't clear constants */
160 +            return;
161 +        }
162 +        epfree(ep);
163 +    }
164 + }
165 +
166 +
167 + dremove(name)                   /* delete all definitions of name */
168 + char  *name;
169 + {
170 +    register EPNODE  *ep;
171 +
172      while ((ep = dpop(name)) != NULL)
173          epfree(ep);
174   }
# Line 161 | Line 183 | char  *name;
183   }
184  
185  
186 < #ifdef  OUTCHAN
187 < chanout()                       /* set output channels */
186 > char *
187 > setcontext(ctx)                 /* set a new context path */
188 > register char  *ctx;
189   {
190 +    register char  *cpp;
191 +
192 +    if (ctx == NULL)
193 +        return(context);                /* just asking */
194 +    while (*ctx == CNTXMARK)
195 +        ctx++;                          /* skip past marks */
196 +    if (!*ctx) {
197 +        context[0] = '\0';              /* empty means clear context */
198 +        return(context);
199 +    }
200 +    cpp = context;                      /* start context with mark */
201 +    *cpp++ = CNTXMARK;
202 +    do {                                /* carefully copy new context */
203 +        if (cpp >= context+MAXCNTX)
204 +            break;                      /* just copy what we can */
205 +        if (isid(*ctx))
206 +            *cpp++ = *ctx++;
207 +        else {
208 +            *cpp++ = '_'; ctx++;
209 +        }
210 +    } while (*ctx);
211 +    while (cpp[-1] == CNTXMARK)         /* cannot end in context mark */
212 +        cpp--;
213 +    *cpp = '\0';
214 +    return(context);
215 + }
216 +
217 +
218 + char *
219 + pushcontext(ctx)                /* push on another context */
220 + char  *ctx;
221 + {
222 +    extern char  *strncpy(), *strcpy();
223 +    char  oldcontext[MAXCNTX+1];
224 +    register int  n;
225 +
226 +    strcpy(oldcontext, context);        /* save old context */
227 +    setcontext(ctx);                    /* set new context */
228 +    n = strlen(context);                /* tack on old */
229 +    if (n+strlen(oldcontext) > MAXCNTX) {
230 +        strncpy(context+n, oldcontext, MAXCNTX-n);
231 +        context[MAXCNTX] = '\0';
232 +    } else
233 +        strcpy(context+n, oldcontext);
234 +    return(context);
235 + }
236 +
237 +
238 + char *
239 + popcontext()                    /* pop off top context */
240 + {
241 +    register char  *cp1, *cp2;
242 +
243 +    if (!context[0])                    /* nothing left to pop */
244 +        return(context);
245 +    cp2 = context;                      /* find mark */
246 +    while (*++cp2 && *cp2 != CNTXMARK)
247 +        ;
248 +    cp1 = context;                      /* copy tail to front */
249 +    while (*cp1++ = *cp2++)
250 +        ;
251 +    return(context);
252 + }
253 +
254 +
255 + char *
256 + qualname(nam, lvl)              /* get qualified name */
257 + register char  *nam;
258 + int  lvl;
259 + {
260 +    static char  nambuf[MAXWORD+1];
261 +    register char  *cp = nambuf, *cpp;
262 +                                /* check for explicit local */
263 +    if (*nam == CNTXMARK)
264 +        if (lvl > 0)            /* only action is to refuse search */
265 +            return(NULL);
266 +        else
267 +            nam++;
268 +    else if (nam == nambuf)     /* check for repeat call */
269 +        return(lvl > 0 ? NULL : nam);
270 +                                /* copy name to static buffer */
271 +    while (*nam) {
272 +        if (cp >= nambuf+MAXWORD)
273 +                goto toolong;
274 +        *cp++ = *nam++;
275 +    }
276 +                                /* check for explicit global */
277 +    if (cp > nambuf && cp[-1] == CNTXMARK) {
278 +        if (lvl > 0)
279 +            return(NULL);
280 +        *--cp = '\0';
281 +        return(nambuf);         /* already qualified */
282 +    }
283 +    cpp = context;              /* else skip the requested levels */
284 +    while (lvl-- > 0) {
285 +        if (!*cpp)
286 +            return(NULL);       /* return NULL if past global level */
287 +        while (*++cpp && *cpp != CNTXMARK)
288 +            ;
289 +    }
290 +    while (*cpp) {              /* copy context to static buffer */
291 +        if (cp >= nambuf+MAXWORD)
292 +            goto toolong;
293 +        *cp++ = *cpp++;
294 +    }
295 + toolong:
296 +    *cp = '\0';
297 +    return(nambuf);             /* return qualified name */
298 + }
299 +
300 +
301 + incontext(qn)                   /* is qualified name in current context? */
302 + register char  *qn;
303 + {
304 +    if (!context[0])                    /* global context accepts all */
305 +        return(1);
306 +    while (*qn && *qn != CNTXMARK)      /* find context mark */
307 +        qn++;
308 +    return(!strcmp(qn, context));
309 + }
310 +
311 +
312 + #ifdef  OUTCHAN
313 + chanout(cs)                     /* set output channels */
314 + int  (*cs)();
315 + {
316      register EPNODE  *ep;
317  
318      for (ep = outchan; ep != NULL; ep = ep->sibling)
319 <        chanset(ep->v.kid->v.chan, evalue(ep->v.kid->sibling));
319 >        (*cs)(ep->v.kid->v.chan, evalue(ep->v.kid->sibling));
320  
321   }
322   #endif
323  
324  
325 < dclearall()                     /* clear all definitions */
325 > dcleanup(lvl)           /* clear definitions (0->vars,1->output,2->consts) */
326 > int  lvl;
327   {
328      register int  i;
329      register VARDEF  *vp;
330      register EPNODE  *ep;
331 <
331 >                                /* if context is global, clear all */
332      for (i = 0; i < NHASH; i++)
333          for (vp = hashtbl[i]; vp != NULL; vp = vp->next)
334 <            dclear(vp->name);
335 < #ifdef  OUTCHAN
336 <    for (ep = outchan; ep != NULL; ep = ep->sibling)
337 <        epfree(ep);
338 <    outchan = NULL;
334 >            if (incontext(vp->name))
335 >                if (lvl >= 2)
336 >                    dremove(vp->name);
337 >                else
338 >                    dclear(vp->name);
339 > #ifdef  OUTCHAN
340 >    if (lvl >= 1) {
341 >        for (ep = outchan; ep != NULL; ep = ep->sibling)
342 >            epfree(ep);
343 >        outchan = NULL;
344 >    }
345   #endif
346   }
347  
# Line 197 | Line 353 | char  *name;
353      register VARDEF  *vp;
354      
355      if ((vp = varlookup(name)) == NULL)
356 <        return(NULL);
356 >        return(NULL);
357      return(vp->def);
358   }
359  
# Line 206 | Line 362 | VARDEF *
362   varlookup(name)                 /* look up a variable */
363   char  *name;
364   {
365 +    int  lvl = 0;
366 +    register char  *qname;
367      register VARDEF  *vp;
368 <    
369 <    for (vp = hashtbl[hash(name)]; vp != NULL; vp = vp->next)
370 <        if (!strcmp(vp->name, name))
371 <            return(vp);
368 >                                /* find most qualified match */
369 >    while ((qname = qualname(name, lvl++)) != NULL)
370 >        for (vp = hashtbl[hash(qname)]; vp != NULL; vp = vp->next)
371 >            if (!strcmp(vp->name, qname))
372 >                return(vp);
373      return(NULL);
374   }
375  
# Line 220 | Line 379 | varinsert(name)                        /* get a link to a variable */
379   char  *name;
380   {
381      register VARDEF  *vp;
382 <    int  hv;
382 >    int  hv;
383      
384 <    hv = hash(name);
385 <    for (vp = hashtbl[hv]; vp != NULL; vp = vp->next)
386 <        if (!strcmp(vp->name, name)) {
387 <            vp->nlinks++;
229 <            return(vp);
230 <        }
384 >    if ((vp = varlookup(name)) != NULL) {
385 >        vp->nlinks++;
386 >        return(vp);
387 >    }
388      vp = (VARDEF *)emalloc(sizeof(VARDEF));
389 + #ifdef  FUNCTION
390 +    vp->lib = liblookup(name);
391 + #else
392 +    vp->lib = NULL;
393 + #endif
394 +    if (vp->lib == NULL)                /* if name not in library */
395 +        name = qualname(name, 0);       /* use fully qualified version */
396 +    hv = hash(name);
397      vp->name = savestr(name);
398      vp->nlinks = 1;
399      vp->def = NULL;
235    vp->lib = NULL;
400      vp->next = hashtbl[hv];
401      hashtbl[hv] = vp;
402      return(vp);
403   }
404  
405  
406 + #ifdef  FUNCTION
407 + libupdate(fn)                   /* update library links */
408 + char  *fn;
409 + {
410 +    register int  i;
411 +    register VARDEF  *vp;
412 +                                        /* if fn is NULL then relink all */
413 +    for (i = 0; i < NHASH; i++)
414 +        for (vp = hashtbl[i]; vp != NULL; vp = vp->next)
415 +            if (vp->lib != NULL || fn == NULL || !strcmp(fn, vp->name))
416 +                vp->lib = liblookup(vp->name);
417 + }
418 + #endif
419 +
420 +
421   varfree(ln)                             /* release link to variable */
422 < register VARDEF  *ln;
422 > register VARDEF  *ln;
423   {
424      register VARDEF  *vp;
425 <    int  hv;
425 >    int  hv;
426  
427      if (--ln->nlinks > 0)
428 <        return;                         /* still active */
428 >        return;                         /* still active */
429  
430      hv = hash(ln->name);
431      vp = hashtbl[hv];
432      if (vp == ln)
433 <        hashtbl[hv] = vp->next;
433 >        hashtbl[hv] = vp->next;
434      else {
435 <        while (vp->next != ln)          /* must be in list */
436 <                vp = vp->next;
437 <        vp->next = ln->next;
435 >        while (vp->next != ln)          /* must be in list */
436 >                vp = vp->next;
437 >        vp->next = ln->next;
438      }
439      freestr(ln->name);
440      efree((char *)ln);
# Line 267 | Line 446 | dfirst()                       /* return pointer to first definition */
446   {
447      htndx = 0;
448      htpos = NULL;
449 < #ifdef  OUTCHAN
449 > #ifdef  OUTCHAN
450      ochpos = outchan;
451   #endif
452      return(dnext());
# Line 278 | Line 457 | EPNODE *
457   dnext()                         /* return pointer to next definition */
458   {
459      register EPNODE  *ep;
460 +    register char  *nm;
461  
462      while (htndx < NHASH) {
463 <        if (htpos == NULL)
464 <                htpos = hashtbl[htndx++];
465 <        while (htpos != NULL) {
466 <            ep = htpos->def;
467 <            htpos = htpos->next;
468 <            if (ep != NULL)
469 <                return(ep);
470 <        }
463 >        if (htpos == NULL)
464 >                htpos = hashtbl[htndx++];
465 >        while (htpos != NULL) {
466 >            ep = htpos->def;
467 >            nm = htpos->name;
468 >            htpos = htpos->next;
469 >            if (ep != NULL && incontext(nm))
470 >                return(ep);
471 >        }
472      }
473 < #ifdef  OUTCHAN
473 > #ifdef  OUTCHAN
474      if ((ep = ochpos) != NULL)
475 <        ochpos = ep->sibling;
475 >        ochpos = ep->sibling;
476      return(ep);
477   #else
478      return(NULL);
# Line 307 | Line 488 | char  *name;
488      register EPNODE  *dp;
489      
490      if ((vp = varlookup(name)) == NULL || vp->def == NULL)
491 <        return(NULL);
491 >        return(NULL);
492      dp = vp->def;
493      vp->def = dp->sibling;
494      varfree(vp);
# Line 315 | Line 496 | char  *name;
496   }
497  
498  
499 < dpush(ep)                       /* push on a definition */
500 < register EPNODE  *ep;
499 > dpush(nm, ep)                   /* push on a definition */
500 > char  *nm;
501 > register EPNODE  *ep;
502   {
503      register VARDEF  *vp;
504  
505 <    vp = varinsert(dname(ep));
505 >    vp = varinsert(nm);
506      ep->sibling = vp->def;
507      vp->def = ep;
508   }
509  
510  
511 < #ifdef  OUTCHAN
511 > #ifdef  OUTCHAN
512   addchan(sp)                     /* add an output channel assignment */
513 < EPNODE  *sp;
513 > EPNODE  *sp;
514   {
515 <    int  ch = sp->v.kid->v.chan;
515 >    int  ch = sp->v.kid->v.chan;
516      register EPNODE  *ep, *epl;
517  
518      for (epl = NULL, ep = outchan; ep != NULL; epl = ep, ep = ep->sibling)
# Line 357 | Line 539 | EPNODE  *sp;
539   #endif
540  
541  
542 < loaddefn()                      /* load next definition */
542 > getstatement()                  /* get next statement */
543   {
544      register EPNODE  *ep;
545 +    char  *qname;
546 +    register VARDEF  *vdef;
547  
548      if (nextc == ';') {         /* empty statement */
549          scan();
550          return;
551      }
552 < #ifdef  OUTCHAN
552 > #ifdef  OUTCHAN
553      if (nextc == '$') {         /* channel assignment */
554          ep = getchan();
555          addchan(ep);
# Line 373 | Line 557 | loaddefn()                     /* load next definition */
557   #endif
558      {                           /* ordinary definition */
559          ep = getdefn();
560 < #ifdef  REDEFW
561 <        if (dlookup(dname(ep)) != NULL) {
562 <                dclear(dname(ep));
563 <                wputs(dname(ep));
564 <                wputs(": redefined\n");
565 <        }
566 < #else
567 <        dclear(dname(ep));
560 >        qname = qualname(dname(ep), 0);
561 > #ifdef  REDEFW
562 >        if ((vdef = varlookup(qname)) != NULL)
563 >            if (vdef->def != NULL && epcmp(ep, vdef->def)) {
564 >                wputs(qname);
565 >                if (vdef->def->type == ':')
566 >                    wputs(": redefined constant expression\n");
567 >                else
568 >                    wputs(": redefined\n");
569 >            }
570 > #ifdef  FUNCTION
571 >            else if (ep->v.kid->type == FUNC && vdef->lib != NULL) {
572 >                wputs(qname);
573 >                wputs(": definition hides library function\n");
574 >            }
575   #endif
576 <        dpush(ep);
576 > #endif
577 >        if (ep->type == ':')
578 >            dremove(qname);
579 >        else
580 >            dclear(qname);
581 >        dpush(qname, ep);
582      }
583      if (nextc != EOF) {
584          if (nextc != ';')
# Line 394 | Line 590 | loaddefn()                     /* load next definition */
590  
591   EPNODE *
592   getdefn()                       /* A -> SYM = E1 */
593 <                                /*      FUNC(SYM,..) = E1 */
593 >                                /*      SYM : E1 */
594 >                                /*      FUNC(SYM,..) = E1 */
595 >                                /*      FUNC(SYM,..) : E1 */
596   {
597      register EPNODE  *ep1, *ep2;
598  
599 <    if (!isalpha(nextc))
599 >    if (!isalpha(nextc) && nextc != CNTXMARK)
600          syntax("illegal variable name");
601  
602      ep1 = newnode();
603      ep1->type = SYM;
604      ep1->v.name = savestr(getname());
605  
606 < #ifdef  FUNCTION
606 > #ifdef  FUNCTION
607      if (nextc == '(') {
608          ep2 = newnode();
609          ep2->type = FUNC;
# Line 424 | Line 622 | getdefn()                      /* A -> SYM = E1 */
622              syntax("')' expected");
623          scan();
624          curfunc = ep1;
625 <    } else
428 <        curfunc = NULL;
625 >    }
626   #endif
627  
628 <    if (nextc != '=')
629 <        syntax("'=' expected");
433 <    scan();
628 >    if (nextc != '=' && nextc != ':')
629 >        syntax("'=' or ':' expected");
630  
631      ep2 = newnode();
632 <    ep2->type = '=';
632 >    ep2->type = nextc;
633 >    scan();
634      addekid(ep2, ep1);
635      addekid(ep2, getE1());
636  
637 < #ifdef  FUNCTION
638 <    if (ep1->type == SYM)
637 >    if (
638 > #ifdef  FUNCTION
639 >            ep1->type == SYM &&
640   #endif
641 <    {
641 >            ep1->sibling->type != NUM) {
642          ep1 = newnode();
643          ep1->type = TICK;
644 <        ep1->v.tick = -1;
644 >        ep1->v.tick = 0;
645          addekid(ep2, ep1);
646          ep1 = newnode();
647          ep1->type = NUM;
648          addekid(ep2, ep1);
649      }
650  
651 + #ifdef  FUNCTION
652 +    curfunc = NULL;
653 + #endif
654 +
655      return(ep2);
656   }
657  
658  
659 < #ifdef  OUTCHAN
659 > #ifdef  OUTCHAN
660   EPNODE *
661   getchan()                       /* A -> $N = E1 */
662   {
# Line 491 | Line 693 | getchan()                      /* A -> $N = E1 */
693   static double
694   dvalue(name, d)                 /* evaluate a variable */
695   char  *name;
696 < EPNODE  *d;
696 > EPNODE  *d;
697   {
698      register EPNODE  *ep1, *ep2;
699      
# Line 501 | Line 703 | EPNODE  *d;
703          quit(1);
704      }
705      ep1 = d->v.kid->sibling;                    /* get expression */
706 +    if (ep1->type == NUM)
707 +        return(ep1->v.num);                     /* return if number */
708      ep2 = ep1->sibling;                         /* check time */
709 <    if (ep2->v.tick < 0 || ep2->v.tick < eclock) {
710 <        ep2->v.tick = eclock;
709 >    if (ep2->v.tick == 0 || ep2->v.tick < eclock) {
710 >        ep2->v.tick = d->type == ':' ? ~0L : eclock;
711          ep2 = ep2->sibling;
712 <        ep2->v.num = evalue(ep1);               /* compute new value */
712 >        ep2->v.num = evalue(ep1);               /* needs new value */
713      } else
714 <        ep2 = ep2->sibling;                     /* reuse old value */
714 >        ep2 = ep2->sibling;                     /* else reuse old value */
715  
716      return(ep2->v.num);
513 }
514
515
516 static int
517 hash(s)                         /* hash a string */
518 register char  *s;
519 {
520    register int  rval = 0;
521
522    while (*s)
523        rval += *s++;
524    
525    return(rval % NHASH);
717   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines