ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 2.18
Committed: Thu Jul 17 09:21:29 2003 UTC (20 years, 9 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.17: +5 -9 lines
Log Message:
Added prototypes and includes from patch by Randolph Fritz.
Added more required includes and reduced other compile warnings.

File Contents

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