ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 1.19
Committed: Wed Aug 14 15:50:38 1991 UTC (32 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.18: +4 -2 lines
Log Message:
added context testing to dnext()

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.18 static char context[MAXWORD+1]; /* current context path */
46 greg 1.13
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 greg 1.18 if (cpp >= context+MAXWORD)
199     break; /* just copy what we can */
200 greg 1.13 if (isid(*ctx))
201     *cpp++ = *ctx++;
202     else {
203     *cpp++ = '_'; ctx++;
204     }
205     } while (*ctx);
206     *cpp = '\0';
207     return(context);
208     }
209    
210    
211     char *
212     qualname(nam, lvl) /* get qualified name */
213     register char *nam;
214     int lvl;
215     {
216 greg 1.18 static char nambuf[MAXWORD+1];
217 greg 1.17 register char *cp = nambuf, *cpp;
218     /* check for explicit local */
219 greg 1.15 if (*nam == CNTXMARK)
220 greg 1.17 if (lvl > 0) /* only action is to refuse search */
221     return(NULL);
222     else
223     nam++;
224     else if (nam == nambuf) /* check for repeat call */
225     return(lvl > 0 ? NULL : nam);
226 greg 1.13 /* copy name to static buffer */
227     while (*nam) {
228 greg 1.18 if (cp >= nambuf+MAXWORD)
229 greg 1.13 goto toolong;
230 greg 1.17 *cp++ = *nam++;
231 greg 1.13 }
232 greg 1.17 /* check for explicit global */
233     if (cp > nambuf && cp[-1] == CNTXMARK) {
234 greg 1.13 if (lvl > 0)
235 greg 1.17 return(NULL);
236     *--cp = '\0';
237     return(nambuf); /* already qualified */
238     }
239     cpp = context; /* 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 greg 1.13 while (*cpp) { /* copy context to static buffer */
247 greg 1.18 if (cp >= nambuf+MAXWORD)
248 greg 1.13 goto toolong;
249     *cp++ = *cpp++;
250     }
251 greg 1.18 toolong:
252 greg 1.13 *cp = '\0';
253     return(nambuf); /* return qualified name */
254     }
255    
256    
257 greg 1.14 incontext(qn) /* is qualified name in current context? */
258     register char *qn;
259     {
260     while (*qn && *qn != CNTXMARK) /* find context mark */
261 greg 1.19 qn++;
262 greg 1.14 return(!strcmp(qn, context));
263     }
264    
265    
266 greg 1.1 #ifdef OUTCHAN
267 greg 1.6 chanout(cs) /* set output channels */
268     int (*cs)();
269 greg 1.1 {
270     register EPNODE *ep;
271    
272     for (ep = outchan; ep != NULL; ep = ep->sibling)
273 greg 1.6 (*cs)(ep->v.kid->v.chan, evalue(ep->v.kid->sibling));
274 greg 1.1
275     }
276     #endif
277    
278    
279 greg 1.12 dcleanup(lvl) /* clear definitions (0->vars,1->output,2->consts) */
280 greg 1.10 int lvl;
281 greg 1.1 {
282     register int i;
283     register VARDEF *vp;
284     register EPNODE *ep;
285 greg 1.14 /* if context is global, clear all */
286 greg 1.1 for (i = 0; i < NHASH; i++)
287     for (vp = hashtbl[i]; vp != NULL; vp = vp->next)
288 greg 1.14 if (!context[0] || incontext(vp->name))
289     if (lvl >= 2)
290     dremove(vp->name);
291     else
292     dclear(vp->name);
293 greg 1.1 #ifdef OUTCHAN
294 greg 1.12 if (lvl >= 1) {
295 greg 1.9 for (ep = outchan; ep != NULL; ep = ep->sibling)
296     epfree(ep);
297     outchan = NULL;
298     }
299 greg 1.1 #endif
300     }
301    
302    
303     EPNODE *
304     dlookup(name) /* look up a definition */
305     char *name;
306     {
307     register VARDEF *vp;
308    
309     if ((vp = varlookup(name)) == NULL)
310     return(NULL);
311     return(vp->def);
312     }
313    
314    
315     VARDEF *
316     varlookup(name) /* look up a variable */
317     char *name;
318     {
319 greg 1.13 int lvl = 0;
320     register char *qname;
321 greg 1.1 register VARDEF *vp;
322 greg 1.13 /* find most qualified match */
323     while ((qname = qualname(name, lvl++)) != NULL)
324     for (vp = hashtbl[hash(qname)]; vp != NULL; vp = vp->next)
325     if (!strcmp(vp->name, qname))
326     return(vp);
327 greg 1.1 return(NULL);
328     }
329    
330    
331     VARDEF *
332     varinsert(name) /* get a link to a variable */
333     char *name;
334     {
335     register VARDEF *vp;
336 greg 1.16 LIBR *libp;
337 greg 1.1 int hv;
338    
339 greg 1.13 if ((vp = varlookup(name)) != NULL) {
340     vp->nlinks++;
341     return(vp);
342     }
343 greg 1.16 #ifdef FUNCTION
344     libp = liblookup(name);
345     #else
346     libp = NULL;
347     #endif
348     if (libp == NULL) /* if name not in library */
349     name = qualname(name, 0); /* use fully qualified version */
350 greg 1.1 hv = hash(name);
351     vp = (VARDEF *)emalloc(sizeof(VARDEF));
352     vp->name = savestr(name);
353     vp->nlinks = 1;
354     vp->def = NULL;
355 greg 1.16 vp->lib = libp;
356 greg 1.1 vp->next = hashtbl[hv];
357     hashtbl[hv] = vp;
358     return(vp);
359     }
360    
361    
362     varfree(ln) /* release link to variable */
363     register VARDEF *ln;
364     {
365     register VARDEF *vp;
366     int hv;
367    
368     if (--ln->nlinks > 0)
369     return; /* still active */
370    
371     hv = hash(ln->name);
372     vp = hashtbl[hv];
373     if (vp == ln)
374     hashtbl[hv] = vp->next;
375     else {
376     while (vp->next != ln) /* must be in list */
377     vp = vp->next;
378     vp->next = ln->next;
379     }
380     freestr(ln->name);
381     efree((char *)ln);
382     }
383    
384    
385     EPNODE *
386     dfirst() /* return pointer to first definition */
387     {
388     htndx = 0;
389     htpos = NULL;
390     #ifdef OUTCHAN
391     ochpos = outchan;
392     #endif
393     return(dnext());
394     }
395    
396    
397     EPNODE *
398     dnext() /* return pointer to next definition */
399     {
400     register EPNODE *ep;
401 greg 1.19 register char *nm;
402 greg 1.1
403     while (htndx < NHASH) {
404     if (htpos == NULL)
405     htpos = hashtbl[htndx++];
406     while (htpos != NULL) {
407     ep = htpos->def;
408 greg 1.19 nm = htpos->name;
409 greg 1.1 htpos = htpos->next;
410 greg 1.19 if (ep != NULL && incontext(nm))
411 greg 1.1 return(ep);
412     }
413     }
414     #ifdef OUTCHAN
415     if ((ep = ochpos) != NULL)
416     ochpos = ep->sibling;
417     return(ep);
418     #else
419     return(NULL);
420     #endif
421     }
422    
423    
424     EPNODE *
425     dpop(name) /* pop a definition */
426     char *name;
427     {
428     register VARDEF *vp;
429     register EPNODE *dp;
430    
431     if ((vp = varlookup(name)) == NULL || vp->def == NULL)
432     return(NULL);
433     dp = vp->def;
434     vp->def = dp->sibling;
435     varfree(vp);
436     return(dp);
437     }
438    
439    
440 greg 1.13 dpush(nm, ep) /* push on a definition */
441     char *nm;
442 greg 1.1 register EPNODE *ep;
443     {
444     register VARDEF *vp;
445    
446 greg 1.13 vp = varinsert(nm);
447 greg 1.1 ep->sibling = vp->def;
448     vp->def = ep;
449     }
450    
451    
452     #ifdef OUTCHAN
453     addchan(sp) /* add an output channel assignment */
454     EPNODE *sp;
455     {
456     int ch = sp->v.kid->v.chan;
457     register EPNODE *ep, *epl;
458    
459     for (epl = NULL, ep = outchan; ep != NULL; epl = ep, ep = ep->sibling)
460     if (ep->v.kid->v.chan >= ch) {
461     if (epl != NULL)
462     epl->sibling = sp;
463     else
464     outchan = sp;
465     if (ep->v.kid->v.chan > ch)
466     sp->sibling = ep;
467     else {
468     sp->sibling = ep->sibling;
469     epfree(ep);
470     }
471     return;
472     }
473     if (epl != NULL)
474     epl->sibling = sp;
475     else
476     outchan = sp;
477     sp->sibling = NULL;
478    
479     }
480     #endif
481    
482    
483 greg 1.13 getstatement() /* get next statement */
484 greg 1.1 {
485     register EPNODE *ep;
486 greg 1.13 char *qname;
487 greg 1.16 register VARDEF *vdef;
488 greg 1.1
489     if (nextc == ';') { /* empty statement */
490     scan();
491     return;
492     }
493     #ifdef OUTCHAN
494     if (nextc == '$') { /* channel assignment */
495     ep = getchan();
496     addchan(ep);
497     } else
498     #endif
499     { /* ordinary definition */
500     ep = getdefn();
501 greg 1.13 qname = qualname(dname(ep), 0);
502 greg 1.2 #ifdef REDEFW
503 greg 1.16 if ((vdef = varlookup(qname)) != NULL)
504     if (vdef->def != NULL) {
505     wputs(qname);
506     if (vdef->def->type == ':')
507     wputs(": redefined constant expression\n");
508     else
509     wputs(": redefined\n");
510     }
511 greg 1.8 #ifdef FUNCTION
512 greg 1.16 else if (ep->v.kid->type == FUNC && vdef->lib != NULL) {
513     wputs(qname);
514     wputs(": definition hides library function\n");
515     }
516 greg 1.8 #endif
517 greg 1.2 #endif
518 greg 1.10 if (ep->type == ':')
519 greg 1.13 dremove(qname);
520 greg 1.10 else
521 greg 1.13 dclear(qname);
522     dpush(qname, ep);
523 greg 1.1 }
524     if (nextc != EOF) {
525     if (nextc != ';')
526     syntax("';' expected");
527     scan();
528     }
529     }
530    
531    
532     EPNODE *
533     getdefn() /* A -> SYM = E1 */
534 greg 1.8 /* SYM : E1 */
535 greg 1.1 /* FUNC(SYM,..) = E1 */
536 greg 1.8 /* FUNC(SYM,..) : E1 */
537 greg 1.1 {
538     register EPNODE *ep1, *ep2;
539    
540 greg 1.18 if (!isalpha(nextc) && nextc != CNTXMARK)
541 greg 1.1 syntax("illegal variable name");
542    
543     ep1 = newnode();
544     ep1->type = SYM;
545     ep1->v.name = savestr(getname());
546    
547     #ifdef FUNCTION
548     if (nextc == '(') {
549     ep2 = newnode();
550     ep2->type = FUNC;
551     addekid(ep2, ep1);
552     ep1 = ep2;
553     do {
554     scan();
555     if (!isalpha(nextc))
556     syntax("illegal variable name");
557     ep2 = newnode();
558     ep2->type = SYM;
559     ep2->v.name = savestr(getname());
560     addekid(ep1, ep2);
561     } while (nextc == ',');
562     if (nextc != ')')
563     syntax("')' expected");
564     scan();
565     curfunc = ep1;
566     } else
567     curfunc = NULL;
568     #endif
569    
570 greg 1.8 if (nextc != '=' && nextc != ':')
571     syntax("'=' or ':' expected");
572 greg 1.1
573     ep2 = newnode();
574 greg 1.8 ep2->type = nextc;
575     scan();
576 greg 1.1 addekid(ep2, ep1);
577     addekid(ep2, getE1());
578    
579 greg 1.7 if (
580 greg 1.1 #ifdef FUNCTION
581 greg 1.7 ep1->type == SYM &&
582 greg 1.1 #endif
583 greg 1.7 ep1->sibling->type != NUM) {
584 greg 1.1 ep1 = newnode();
585     ep1->type = TICK;
586     ep1->v.tick = -1;
587     addekid(ep2, ep1);
588     ep1 = newnode();
589     ep1->type = NUM;
590     addekid(ep2, ep1);
591     }
592    
593     return(ep2);
594     }
595    
596    
597     #ifdef OUTCHAN
598     EPNODE *
599     getchan() /* A -> $N = E1 */
600     {
601     register EPNODE *ep1, *ep2;
602    
603     if (nextc != '$')
604     syntax("missing '$'");
605     scan();
606    
607     ep1 = newnode();
608     ep1->type = CHAN;
609     ep1->v.chan = getinum();
610    
611     if (nextc != '=')
612     syntax("'=' expected");
613     scan();
614    
615     ep2 = newnode();
616     ep2->type = '=';
617     addekid(ep2, ep1);
618     addekid(ep2, getE1());
619    
620     return(ep2);
621     }
622     #endif
623    
624    
625    
626     /*
627     * The following routines are for internal use only:
628     */
629    
630    
631     static double
632     dvalue(name, d) /* evaluate a variable */
633     char *name;
634     EPNODE *d;
635     {
636     register EPNODE *ep1, *ep2;
637    
638     if (d == NULL || d->v.kid->type != SYM) {
639     eputs(name);
640     eputs(": undefined variable\n");
641     quit(1);
642     }
643     ep1 = d->v.kid->sibling; /* get expression */
644 greg 1.5 if (ep1->type == NUM)
645     return(ep1->v.num); /* return if number */
646 greg 1.1 ep2 = ep1->sibling; /* check time */
647     if (ep2->v.tick < 0 || ep2->v.tick < eclock) {
648 greg 1.8 ep2->v.tick = d->type == ':' ? 1L<<30 : eclock;
649 greg 1.1 ep2 = ep2->sibling;
650 greg 1.5 ep2->v.num = evalue(ep1); /* needs new value */
651 greg 1.1 } else
652 greg 1.5 ep2 = ep2->sibling; /* else reuse old value */
653 greg 1.1
654     return(ep2->v.num);
655     }
656    
657    
658     static int
659     hash(s) /* hash a string */
660     register char *s;
661     {
662     register int rval = 0;
663    
664     while (*s)
665     rval += *s++;
666    
667     return(rval % NHASH);
668     }