ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 1.14
Committed: Thu Aug 8 12:12:16 1991 UTC (32 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.13: +18 -8 lines
Log Message:
fixed up dcleanup() routine for working with contexts

File Contents

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