ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 1.19
Committed: Wed Aug 14 15:50:38 1991 UTC (32 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.18: +4 -2 lines
Log Message:
added context testing to dnext()

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