ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 2.14
Committed: Mon Mar 10 17:13:29 2003 UTC (21 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R5
Changes since 2.13: +1 -2 lines
Log Message:
Compile error fixes for Linux and other improvements

File Contents

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