ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 1.9
Committed: Wed Apr 24 08:17:22 1991 UTC (33 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.8: +12 -6 lines
Log Message:
changed definition of dclearall() to dclean()

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