ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 1.8
Committed: Tue Apr 23 12:59:33 1991 UTC (33 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.7: +52 -12 lines
Log Message:
added ':' definitions for constant expressions

File Contents

# User Rev Content
1 greg 1.1 /* Copyright (c) 1986 Regents of the University of California */
2    
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     dclearall() /* clear all definitions */
189     {
190     register int i;
191     register VARDEF *vp;
192     register EPNODE *ep;
193    
194     for (i = 0; i < NHASH; i++)
195     for (vp = hashtbl[i]; vp != NULL; vp = vp->next)
196 greg 1.8 dremove(vp->name);
197 greg 1.1 #ifdef OUTCHAN
198     for (ep = outchan; ep != NULL; ep = ep->sibling)
199     epfree(ep);
200     outchan = NULL;
201     #endif
202     }
203    
204    
205     EPNODE *
206     dlookup(name) /* look up a definition */
207     char *name;
208     {
209     register VARDEF *vp;
210    
211     if ((vp = varlookup(name)) == NULL)
212     return(NULL);
213     return(vp->def);
214     }
215    
216    
217     VARDEF *
218     varlookup(name) /* look up a variable */
219     char *name;
220     {
221     register VARDEF *vp;
222    
223     for (vp = hashtbl[hash(name)]; vp != NULL; vp = vp->next)
224     if (!strcmp(vp->name, name))
225     return(vp);
226     return(NULL);
227     }
228    
229    
230     VARDEF *
231     varinsert(name) /* get a link to a variable */
232     char *name;
233     {
234     register VARDEF *vp;
235     int hv;
236    
237     hv = hash(name);
238     for (vp = hashtbl[hv]; vp != NULL; vp = vp->next)
239     if (!strcmp(vp->name, name)) {
240     vp->nlinks++;
241     return(vp);
242     }
243     vp = (VARDEF *)emalloc(sizeof(VARDEF));
244     vp->name = savestr(name);
245     vp->nlinks = 1;
246     vp->def = NULL;
247     vp->lib = NULL;
248     vp->next = hashtbl[hv];
249     hashtbl[hv] = vp;
250     return(vp);
251     }
252    
253    
254     varfree(ln) /* release link to variable */
255     register VARDEF *ln;
256     {
257     register VARDEF *vp;
258     int hv;
259    
260     if (--ln->nlinks > 0)
261     return; /* still active */
262    
263     hv = hash(ln->name);
264     vp = hashtbl[hv];
265     if (vp == ln)
266     hashtbl[hv] = vp->next;
267     else {
268     while (vp->next != ln) /* must be in list */
269     vp = vp->next;
270     vp->next = ln->next;
271     }
272     freestr(ln->name);
273     efree((char *)ln);
274     }
275    
276    
277     EPNODE *
278     dfirst() /* return pointer to first definition */
279     {
280     htndx = 0;
281     htpos = NULL;
282     #ifdef OUTCHAN
283     ochpos = outchan;
284     #endif
285     return(dnext());
286     }
287    
288    
289     EPNODE *
290     dnext() /* return pointer to next definition */
291     {
292     register EPNODE *ep;
293    
294     while (htndx < NHASH) {
295     if (htpos == NULL)
296     htpos = hashtbl[htndx++];
297     while (htpos != NULL) {
298     ep = htpos->def;
299     htpos = htpos->next;
300     if (ep != NULL)
301     return(ep);
302     }
303     }
304     #ifdef OUTCHAN
305     if ((ep = ochpos) != NULL)
306     ochpos = ep->sibling;
307     return(ep);
308     #else
309     return(NULL);
310     #endif
311     }
312    
313    
314     EPNODE *
315     dpop(name) /* pop a definition */
316     char *name;
317     {
318     register VARDEF *vp;
319     register EPNODE *dp;
320    
321     if ((vp = varlookup(name)) == NULL || vp->def == NULL)
322     return(NULL);
323     dp = vp->def;
324     vp->def = dp->sibling;
325     varfree(vp);
326     return(dp);
327     }
328    
329    
330     dpush(ep) /* push on a definition */
331     register EPNODE *ep;
332     {
333     register VARDEF *vp;
334    
335     vp = varinsert(dname(ep));
336     ep->sibling = vp->def;
337     vp->def = ep;
338     }
339    
340    
341     #ifdef OUTCHAN
342     addchan(sp) /* add an output channel assignment */
343     EPNODE *sp;
344     {
345     int ch = sp->v.kid->v.chan;
346     register EPNODE *ep, *epl;
347    
348     for (epl = NULL, ep = outchan; ep != NULL; epl = ep, ep = ep->sibling)
349     if (ep->v.kid->v.chan >= ch) {
350     if (epl != NULL)
351     epl->sibling = sp;
352     else
353     outchan = sp;
354     if (ep->v.kid->v.chan > ch)
355     sp->sibling = ep;
356     else {
357     sp->sibling = ep->sibling;
358     epfree(ep);
359     }
360     return;
361     }
362     if (epl != NULL)
363     epl->sibling = sp;
364     else
365     outchan = sp;
366     sp->sibling = NULL;
367    
368     }
369     #endif
370    
371    
372     loaddefn() /* load next definition */
373     {
374     register EPNODE *ep;
375    
376     if (nextc == ';') { /* empty statement */
377     scan();
378     return;
379     }
380     #ifdef OUTCHAN
381     if (nextc == '$') { /* channel assignment */
382     ep = getchan();
383     addchan(ep);
384     } else
385     #endif
386     { /* ordinary definition */
387     ep = getdefn();
388 greg 1.2 #ifdef REDEFW
389     if (dlookup(dname(ep)) != NULL) {
390 greg 1.8 dclear(dname(ep));
391     wputs(dname(ep));
392     if (dlookup(dname(ep)) == NULL)
393 greg 1.2 wputs(": redefined\n");
394 greg 1.8 else
395     wputs(": redefined constant expression\n");
396 greg 1.2 }
397 greg 1.8 #ifdef FUNCTION
398     else if (ep->v.kid->type == FUNC &&
399     liblookup(ep->v.kid->v.kid->v.name) != NULL) {
400     wputs(ep->v.kid->v.kid->v.name);
401     wputs(": redefined library function\n");
402     }
403     #endif
404 greg 1.2 #else
405 greg 1.1 dclear(dname(ep));
406 greg 1.2 #endif
407 greg 1.1 dpush(ep);
408     }
409     if (nextc != EOF) {
410     if (nextc != ';')
411     syntax("';' expected");
412     scan();
413     }
414     }
415    
416    
417     EPNODE *
418     getdefn() /* A -> SYM = E1 */
419 greg 1.8 /* SYM : E1 */
420 greg 1.1 /* FUNC(SYM,..) = E1 */
421 greg 1.8 /* FUNC(SYM,..) : E1 */
422 greg 1.1 {
423     register EPNODE *ep1, *ep2;
424    
425     if (!isalpha(nextc))
426     syntax("illegal variable name");
427    
428     ep1 = newnode();
429     ep1->type = SYM;
430     ep1->v.name = savestr(getname());
431    
432     #ifdef FUNCTION
433     if (nextc == '(') {
434     ep2 = newnode();
435     ep2->type = FUNC;
436     addekid(ep2, ep1);
437     ep1 = ep2;
438     do {
439     scan();
440     if (!isalpha(nextc))
441     syntax("illegal variable name");
442     ep2 = newnode();
443     ep2->type = SYM;
444     ep2->v.name = savestr(getname());
445     addekid(ep1, ep2);
446     } while (nextc == ',');
447     if (nextc != ')')
448     syntax("')' expected");
449     scan();
450     curfunc = ep1;
451     } else
452     curfunc = NULL;
453     #endif
454    
455 greg 1.8 if (nextc != '=' && nextc != ':')
456     syntax("'=' or ':' expected");
457 greg 1.1
458     ep2 = newnode();
459 greg 1.8 ep2->type = nextc;
460     scan();
461 greg 1.1 addekid(ep2, ep1);
462 greg 1.8 #ifdef RCONST
463     if (
464     #ifdef FUNCTION
465     ep1->type == SYM &&
466     #endif
467     ep2->type == ':')
468     addekid(ep2, rconst(getE1()));
469     else
470     #endif
471 greg 1.1 addekid(ep2, getE1());
472    
473 greg 1.7 if (
474 greg 1.1 #ifdef FUNCTION
475 greg 1.7 ep1->type == SYM &&
476 greg 1.1 #endif
477 greg 1.7 ep1->sibling->type != NUM) {
478 greg 1.1 ep1 = newnode();
479     ep1->type = TICK;
480     ep1->v.tick = -1;
481     addekid(ep2, ep1);
482     ep1 = newnode();
483     ep1->type = NUM;
484     addekid(ep2, ep1);
485     }
486    
487     return(ep2);
488     }
489    
490    
491     #ifdef OUTCHAN
492     EPNODE *
493     getchan() /* A -> $N = E1 */
494     {
495     register EPNODE *ep1, *ep2;
496    
497     if (nextc != '$')
498     syntax("missing '$'");
499     scan();
500    
501     ep1 = newnode();
502     ep1->type = CHAN;
503     ep1->v.chan = getinum();
504    
505     if (nextc != '=')
506     syntax("'=' expected");
507     scan();
508    
509     ep2 = newnode();
510     ep2->type = '=';
511     addekid(ep2, ep1);
512     addekid(ep2, getE1());
513    
514     return(ep2);
515     }
516     #endif
517    
518    
519    
520     /*
521     * The following routines are for internal use only:
522     */
523    
524    
525     static double
526     dvalue(name, d) /* evaluate a variable */
527     char *name;
528     EPNODE *d;
529     {
530     register EPNODE *ep1, *ep2;
531    
532     if (d == NULL || d->v.kid->type != SYM) {
533     eputs(name);
534     eputs(": undefined variable\n");
535     quit(1);
536     }
537     ep1 = d->v.kid->sibling; /* get expression */
538 greg 1.5 if (ep1->type == NUM)
539     return(ep1->v.num); /* return if number */
540 greg 1.1 ep2 = ep1->sibling; /* check time */
541     if (ep2->v.tick < 0 || ep2->v.tick < eclock) {
542 greg 1.8 ep2->v.tick = d->type == ':' ? 1L<<30 : eclock;
543 greg 1.1 ep2 = ep2->sibling;
544 greg 1.5 ep2->v.num = evalue(ep1); /* needs new value */
545 greg 1.1 } else
546 greg 1.5 ep2 = ep2->sibling; /* else reuse old value */
547 greg 1.1
548     return(ep2->v.num);
549     }
550    
551    
552     static int
553     hash(s) /* hash a string */
554     register char *s;
555     {
556     register int rval = 0;
557    
558     while (*s)
559     rval += *s++;
560    
561     return(rval % NHASH);
562     }