ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 2.9
Committed: Tue Mar 28 11:18:52 1995 UTC (29 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.8: +3 -1 lines
Log Message:
fixed problem where global context doesn't print everything

File Contents

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