ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 2.9
Committed: Tue Mar 28 11:18:52 1995 UTC (29 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.8: +3 -1 lines
Log Message:
fixed problem where global context doesn't print everything

File Contents

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