ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 1.14
Committed: Thu Aug 8 12:12:16 1991 UTC (32 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.13: +18 -8 lines
Log Message:
fixed up dcleanup() routine for working with contexts

File Contents

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