ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 2.16
Committed: Sat Jun 7 12:50:20 2003 UTC (20 years, 10 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.15: +87 -63 lines
Log Message:
Various small changes to reduce compile warnings/errors on Windows.

File Contents

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