ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 2.33
Committed: Fri Apr 8 23:32:25 2022 UTC (2 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.32: +4 -4 lines
Log Message:
perf: Removing some conditionals with binary operations

File Contents

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