ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 1.17
Committed: Fri Aug 9 08:27:56 1991 UTC (32 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.16: +22 -21 lines
Log Message:
changed location of context mark for locals/globals

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;
222 /* check for explicit local */
223 if (*nam == CNTXMARK)
224 if (lvl > 0) /* only action is to refuse search */
225 return(NULL);
226 else
227 nam++;
228 else if (nam == nambuf) /* check for repeat call */
229 return(lvl > 0 ? NULL : nam);
230 /* copy name to static buffer */
231 while (*nam) {
232 if (cp >= nambuf+MAXWORD-1)
233 goto toolong;
234 *cp++ = *nam++;
235 }
236 /* check for explicit global */
237 if (cp > nambuf && cp[-1] == CNTXMARK) {
238 if (lvl > 0)
239 return(NULL);
240 *--cp = '\0';
241 return(nambuf); /* already qualified */
242 }
243 cpp = context; /* else skip the requested levels */
244 while (lvl-- > 0) {
245 if (!*cpp)
246 return(NULL); /* return NULL if past global level */
247 while (*++cpp && *cpp != CNTXMARK)
248 ;
249 }
250 while (*cpp) { /* copy context to static buffer */
251 if (cp >= nambuf+MAXWORD-1)
252 goto toolong;
253 *cp++ = *cpp++;
254 }
255 *cp = '\0';
256 return(nambuf); /* return qualified name */
257 toolong:
258 *cp = '\0';
259 eputs(nambuf);
260 eputs(": name too long\n");
261 quit(1);
262 }
263
264
265 incontext(qn) /* is qualified name in current context? */
266 register char *qn;
267 {
268 while (*qn && *qn != CNTXMARK) /* find context mark */
269 ;
270 return(!strcmp(qn, context));
271 }
272
273
274 #ifdef OUTCHAN
275 chanout(cs) /* set output channels */
276 int (*cs)();
277 {
278 register EPNODE *ep;
279
280 for (ep = outchan; ep != NULL; ep = ep->sibling)
281 (*cs)(ep->v.kid->v.chan, evalue(ep->v.kid->sibling));
282
283 }
284 #endif
285
286
287 dcleanup(lvl) /* clear definitions (0->vars,1->output,2->consts) */
288 int lvl;
289 {
290 register int i;
291 register VARDEF *vp;
292 register EPNODE *ep;
293 /* if context is global, clear all */
294 for (i = 0; i < NHASH; i++)
295 for (vp = hashtbl[i]; vp != NULL; vp = vp->next)
296 if (!context[0] || incontext(vp->name))
297 if (lvl >= 2)
298 dremove(vp->name);
299 else
300 dclear(vp->name);
301 #ifdef OUTCHAN
302 if (lvl >= 1) {
303 for (ep = outchan; ep != NULL; ep = ep->sibling)
304 epfree(ep);
305 outchan = NULL;
306 }
307 #endif
308 }
309
310
311 EPNODE *
312 dlookup(name) /* look up a definition */
313 char *name;
314 {
315 register VARDEF *vp;
316
317 if ((vp = varlookup(name)) == NULL)
318 return(NULL);
319 return(vp->def);
320 }
321
322
323 VARDEF *
324 varlookup(name) /* look up a variable */
325 char *name;
326 {
327 int lvl = 0;
328 register char *qname;
329 register VARDEF *vp;
330 /* find most qualified match */
331 while ((qname = qualname(name, lvl++)) != NULL)
332 for (vp = hashtbl[hash(qname)]; vp != NULL; vp = vp->next)
333 if (!strcmp(vp->name, qname))
334 return(vp);
335 return(NULL);
336 }
337
338
339 VARDEF *
340 varinsert(name) /* get a link to a variable */
341 char *name;
342 {
343 register VARDEF *vp;
344 LIBR *libp;
345 int hv;
346
347 if ((vp = varlookup(name)) != NULL) {
348 vp->nlinks++;
349 return(vp);
350 }
351 #ifdef FUNCTION
352 libp = liblookup(name);
353 #else
354 libp = NULL;
355 #endif
356 if (libp == NULL) /* if name not in library */
357 name = qualname(name, 0); /* use fully qualified version */
358 hv = hash(name);
359 vp = (VARDEF *)emalloc(sizeof(VARDEF));
360 vp->name = savestr(name);
361 vp->nlinks = 1;
362 vp->def = NULL;
363 vp->lib = libp;
364 vp->next = hashtbl[hv];
365 hashtbl[hv] = vp;
366 return(vp);
367 }
368
369
370 varfree(ln) /* release link to variable */
371 register VARDEF *ln;
372 {
373 register VARDEF *vp;
374 int hv;
375
376 if (--ln->nlinks > 0)
377 return; /* still active */
378
379 hv = hash(ln->name);
380 vp = hashtbl[hv];
381 if (vp == ln)
382 hashtbl[hv] = vp->next;
383 else {
384 while (vp->next != ln) /* must be in list */
385 vp = vp->next;
386 vp->next = ln->next;
387 }
388 freestr(ln->name);
389 efree((char *)ln);
390 }
391
392
393 EPNODE *
394 dfirst() /* return pointer to first definition */
395 {
396 htndx = 0;
397 htpos = NULL;
398 #ifdef OUTCHAN
399 ochpos = outchan;
400 #endif
401 return(dnext());
402 }
403
404
405 EPNODE *
406 dnext() /* return pointer to next definition */
407 {
408 register EPNODE *ep;
409
410 while (htndx < NHASH) {
411 if (htpos == NULL)
412 htpos = hashtbl[htndx++];
413 while (htpos != NULL) {
414 ep = htpos->def;
415 htpos = htpos->next;
416 if (ep != NULL)
417 return(ep);
418 }
419 }
420 #ifdef OUTCHAN
421 if ((ep = ochpos) != NULL)
422 ochpos = ep->sibling;
423 return(ep);
424 #else
425 return(NULL);
426 #endif
427 }
428
429
430 EPNODE *
431 dpop(name) /* pop a definition */
432 char *name;
433 {
434 register VARDEF *vp;
435 register EPNODE *dp;
436
437 if ((vp = varlookup(name)) == NULL || vp->def == NULL)
438 return(NULL);
439 dp = vp->def;
440 vp->def = dp->sibling;
441 varfree(vp);
442 return(dp);
443 }
444
445
446 dpush(nm, ep) /* push on a definition */
447 char *nm;
448 register EPNODE *ep;
449 {
450 register VARDEF *vp;
451
452 vp = varinsert(nm);
453 ep->sibling = vp->def;
454 vp->def = ep;
455 }
456
457
458 #ifdef OUTCHAN
459 addchan(sp) /* add an output channel assignment */
460 EPNODE *sp;
461 {
462 int ch = sp->v.kid->v.chan;
463 register EPNODE *ep, *epl;
464
465 for (epl = NULL, ep = outchan; ep != NULL; epl = ep, ep = ep->sibling)
466 if (ep->v.kid->v.chan >= ch) {
467 if (epl != NULL)
468 epl->sibling = sp;
469 else
470 outchan = sp;
471 if (ep->v.kid->v.chan > ch)
472 sp->sibling = ep;
473 else {
474 sp->sibling = ep->sibling;
475 epfree(ep);
476 }
477 return;
478 }
479 if (epl != NULL)
480 epl->sibling = sp;
481 else
482 outchan = sp;
483 sp->sibling = NULL;
484
485 }
486 #endif
487
488
489 getstatement() /* get next statement */
490 {
491 register EPNODE *ep;
492 char *qname;
493 register VARDEF *vdef;
494
495 if (nextc == ';') { /* empty statement */
496 scan();
497 return;
498 }
499 #ifdef OUTCHAN
500 if (nextc == '$') { /* channel assignment */
501 ep = getchan();
502 addchan(ep);
503 } else
504 #endif
505 { /* ordinary definition */
506 ep = getdefn();
507 qname = qualname(dname(ep), 0);
508 #ifdef REDEFW
509 if ((vdef = varlookup(qname)) != NULL)
510 if (vdef->def != NULL) {
511 wputs(qname);
512 if (vdef->def->type == ':')
513 wputs(": redefined constant expression\n");
514 else
515 wputs(": redefined\n");
516 }
517 #ifdef FUNCTION
518 else if (ep->v.kid->type == FUNC && vdef->lib != NULL) {
519 wputs(qname);
520 wputs(": definition hides library function\n");
521 }
522 #endif
523 #endif
524 if (ep->type == ':')
525 dremove(qname);
526 else
527 dclear(qname);
528 dpush(qname, ep);
529 }
530 if (nextc != EOF) {
531 if (nextc != ';')
532 syntax("';' expected");
533 scan();
534 }
535 }
536
537
538 EPNODE *
539 getdefn() /* A -> SYM = E1 */
540 /* SYM : E1 */
541 /* FUNC(SYM,..) = E1 */
542 /* FUNC(SYM,..) : E1 */
543 {
544 register EPNODE *ep1, *ep2;
545
546 if (!isalpha(nextc))
547 syntax("illegal variable name");
548
549 ep1 = newnode();
550 ep1->type = SYM;
551 ep1->v.name = savestr(getname());
552
553 #ifdef FUNCTION
554 if (nextc == '(') {
555 ep2 = newnode();
556 ep2->type = FUNC;
557 addekid(ep2, ep1);
558 ep1 = ep2;
559 do {
560 scan();
561 if (!isalpha(nextc))
562 syntax("illegal variable name");
563 ep2 = newnode();
564 ep2->type = SYM;
565 ep2->v.name = savestr(getname());
566 addekid(ep1, ep2);
567 } while (nextc == ',');
568 if (nextc != ')')
569 syntax("')' expected");
570 scan();
571 curfunc = ep1;
572 } else
573 curfunc = NULL;
574 #endif
575
576 if (nextc != '=' && nextc != ':')
577 syntax("'=' or ':' expected");
578
579 ep2 = newnode();
580 ep2->type = nextc;
581 scan();
582 addekid(ep2, ep1);
583 addekid(ep2, getE1());
584
585 if (
586 #ifdef FUNCTION
587 ep1->type == SYM &&
588 #endif
589 ep1->sibling->type != NUM) {
590 ep1 = newnode();
591 ep1->type = TICK;
592 ep1->v.tick = -1;
593 addekid(ep2, ep1);
594 ep1 = newnode();
595 ep1->type = NUM;
596 addekid(ep2, ep1);
597 }
598
599 return(ep2);
600 }
601
602
603 #ifdef OUTCHAN
604 EPNODE *
605 getchan() /* A -> $N = E1 */
606 {
607 register EPNODE *ep1, *ep2;
608
609 if (nextc != '$')
610 syntax("missing '$'");
611 scan();
612
613 ep1 = newnode();
614 ep1->type = CHAN;
615 ep1->v.chan = getinum();
616
617 if (nextc != '=')
618 syntax("'=' expected");
619 scan();
620
621 ep2 = newnode();
622 ep2->type = '=';
623 addekid(ep2, ep1);
624 addekid(ep2, getE1());
625
626 return(ep2);
627 }
628 #endif
629
630
631
632 /*
633 * The following routines are for internal use only:
634 */
635
636
637 static double
638 dvalue(name, d) /* evaluate a variable */
639 char *name;
640 EPNODE *d;
641 {
642 register EPNODE *ep1, *ep2;
643
644 if (d == NULL || d->v.kid->type != SYM) {
645 eputs(name);
646 eputs(": undefined variable\n");
647 quit(1);
648 }
649 ep1 = d->v.kid->sibling; /* get expression */
650 if (ep1->type == NUM)
651 return(ep1->v.num); /* return if number */
652 ep2 = ep1->sibling; /* check time */
653 if (ep2->v.tick < 0 || ep2->v.tick < eclock) {
654 ep2->v.tick = d->type == ':' ? 1L<<30 : eclock;
655 ep2 = ep2->sibling;
656 ep2->v.num = evalue(ep1); /* needs new value */
657 } else
658 ep2 = ep2->sibling; /* else reuse old value */
659
660 return(ep2->v.num);
661 }
662
663
664 static int
665 hash(s) /* hash a string */
666 register char *s;
667 {
668 register int rval = 0;
669
670 while (*s)
671 rval += *s++;
672
673 return(rval % NHASH);
674 }