ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 2.11
Committed: Wed Feb 12 17:38:03 1997 UTC (27 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.10: +9 -7 lines
Log Message:
fixed it so remembered contexts can be 1023 bytes long

File Contents

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