ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 2.5
Committed: Sat Nov 21 21:42:42 1992 UTC (31 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.4: +2 -15 lines
Log Message:
changed to better hash function shash()

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