ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 2.19
Committed: Mon Jul 21 22:30:17 2003 UTC (20 years, 9 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.18: +5 -3 lines
Log Message:
Eliminated copystruct() macro, which is unnecessary in ANSI.
Reduced ambiguity warnings for nested if/if/else clauses.

File Contents

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