ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 2.22
Committed: Sun Mar 28 20:33:12 2004 UTC (20 years, 1 month ago) by schorsch
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R7P2, rad3R7P1, rad3R6, rad3R6P1, rad3R8, rad3R9
Changes since 2.21: +2 -1 lines
Log Message:
Continued ANSIfication, and other fixes and clarifications.

File Contents

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