ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 2.15
Committed: Sun Apr 27 06:08:03 2003 UTC (21 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.14: +2 -2 lines
Log Message:
Added -idN or -ifN and -od or -of options to rcalc

File Contents

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