ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 1.9
Committed: Wed Apr 24 08:17:22 1991 UTC (33 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.8: +12 -6 lines
Log Message:
changed definition of dclearall() to dclean()

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 ':' defines for constant expressions (RCONST)
23 */
24
25 #include <stdio.h>
26
27 #include <ctype.h>
28
29 #include "calcomp.h"
30
31 #ifndef NHASH
32 #define NHASH 521 /* hash size (a prime!) */
33 #endif
34
35 #define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE))
36
37 extern char *ecalloc(), *savestr();
38
39 static double dvalue();
40
41 long eclock = -1; /* value storage timer */
42
43 static VARDEF *hashtbl[NHASH]; /* definition list */
44 static int htndx; /* index for */
45 static VARDEF *htpos; /* ...dfirst() and */
46 #ifdef OUTCHAN
47 static EPNODE *ochpos; /* ...dnext */
48 static EPNODE *outchan;
49 #endif
50
51 #ifdef FUNCTION
52 EPNODE *curfunc;
53 #define dname(ep) ((ep)->v.kid->type == SYM ? \
54 (ep)->v.kid->v.name : \
55 (ep)->v.kid->v.kid->v.name)
56 #else
57 #define dname(ep) ((ep)->v.kid->v.name)
58 #endif
59
60
61 fcompile(fname) /* get definitions from a file */
62 char *fname;
63 {
64 FILE *fp;
65
66 if (fname == NULL)
67 fp = stdin;
68 else if ((fp = fopen(fname, "r")) == NULL) {
69 eputs(fname);
70 eputs(": cannot open\n");
71 quit(1);
72 }
73 initfile(fp, fname, 0);
74 while (nextc != EOF)
75 loaddefn();
76 if (fname != NULL)
77 fclose(fp);
78 }
79
80
81 scompile(str, fn, ln) /* get definitions from a string */
82 char *str;
83 char *fn;
84 int ln;
85 {
86 initstr(str, fn, ln);
87 while (nextc != EOF)
88 loaddefn();
89 }
90
91
92 double
93 varvalue(vname) /* return a variable's value */
94 char *vname;
95 {
96 return(dvalue(vname, dlookup(vname)));
97 }
98
99
100 double
101 evariable(ep) /* evaluate a variable */
102 EPNODE *ep;
103 {
104 register VARDEF *dp = ep->v.ln;
105
106 return(dvalue(dp->name, dp->def));
107 }
108
109
110 varset(vname, assign, val) /* set a variable's value */
111 char *vname;
112 int assign;
113 double val;
114 {
115 register EPNODE *ep1, *ep2;
116 /* check for quick set */
117 if ((ep1 = dlookup(vname)) != NULL && ep1->v.kid->type == SYM) {
118 ep2 = ep1->v.kid->sibling;
119 if (ep2->type == NUM) {
120 ep2->v.num = val;
121 ep1->type = assign;
122 return;
123 }
124 }
125 /* hand build definition */
126 ep1 = newnode();
127 ep1->type = assign;
128 ep2 = newnode();
129 ep2->type = SYM;
130 ep2->v.name = savestr(vname);
131 addekid(ep1, ep2);
132 ep2 = newnode();
133 ep2->type = NUM;
134 ep2->v.num = val;
135 addekid(ep1, ep2);
136 dremove(vname);
137 dpush(ep1);
138 }
139
140
141 dclear(name) /* delete variable definitions of name */
142 char *name;
143 {
144 register EPNODE *ep;
145
146 while ((ep = dpop(name)) != NULL) {
147 if (ep->type == ':') {
148 dpush(ep); /* don't clear constants */
149 return;
150 }
151 epfree(ep);
152 }
153 }
154
155
156 dremove(name) /* delete all definitions of name */
157 char *name;
158 {
159 register EPNODE *ep;
160
161 while ((ep = dpop(name)) != NULL)
162 epfree(ep);
163 }
164
165
166 vardefined(name) /* return non-zero if variable defined */
167 char *name;
168 {
169 register EPNODE *dp;
170
171 return((dp = dlookup(name)) != NULL && dp->v.kid->type == SYM);
172 }
173
174
175 #ifdef OUTCHAN
176 chanout(cs) /* set output channels */
177 int (*cs)();
178 {
179 register EPNODE *ep;
180
181 for (ep = outchan; ep != NULL; ep = ep->sibling)
182 (*cs)(ep->v.kid->v.chan, evalue(ep->v.kid->sibling));
183
184 }
185 #endif
186
187
188 dcleanup(cons, ochans) /* clear definitions */
189 int cons, ochans;
190 {
191 register int i;
192 register VARDEF *vp;
193 register EPNODE *ep;
194
195 for (i = 0; i < NHASH; i++)
196 for (vp = hashtbl[i]; vp != NULL; vp = vp->next)
197 if (cons)
198 dremove(vp->name);
199 else
200 dclear(vp->name);
201 #ifdef OUTCHAN
202 if (ochans) {
203 for (ep = outchan; ep != NULL; ep = ep->sibling)
204 epfree(ep);
205 outchan = NULL;
206 }
207 #endif
208 }
209
210
211 EPNODE *
212 dlookup(name) /* look up a definition */
213 char *name;
214 {
215 register VARDEF *vp;
216
217 if ((vp = varlookup(name)) == NULL)
218 return(NULL);
219 return(vp->def);
220 }
221
222
223 VARDEF *
224 varlookup(name) /* look up a variable */
225 char *name;
226 {
227 register VARDEF *vp;
228
229 for (vp = hashtbl[hash(name)]; vp != NULL; vp = vp->next)
230 if (!strcmp(vp->name, name))
231 return(vp);
232 return(NULL);
233 }
234
235
236 VARDEF *
237 varinsert(name) /* get a link to a variable */
238 char *name;
239 {
240 register VARDEF *vp;
241 int hv;
242
243 hv = hash(name);
244 for (vp = hashtbl[hv]; vp != NULL; vp = vp->next)
245 if (!strcmp(vp->name, name)) {
246 vp->nlinks++;
247 return(vp);
248 }
249 vp = (VARDEF *)emalloc(sizeof(VARDEF));
250 vp->name = savestr(name);
251 vp->nlinks = 1;
252 vp->def = NULL;
253 vp->lib = NULL;
254 vp->next = hashtbl[hv];
255 hashtbl[hv] = vp;
256 return(vp);
257 }
258
259
260 varfree(ln) /* release link to variable */
261 register VARDEF *ln;
262 {
263 register VARDEF *vp;
264 int hv;
265
266 if (--ln->nlinks > 0)
267 return; /* still active */
268
269 hv = hash(ln->name);
270 vp = hashtbl[hv];
271 if (vp == ln)
272 hashtbl[hv] = vp->next;
273 else {
274 while (vp->next != ln) /* must be in list */
275 vp = vp->next;
276 vp->next = ln->next;
277 }
278 freestr(ln->name);
279 efree((char *)ln);
280 }
281
282
283 EPNODE *
284 dfirst() /* return pointer to first definition */
285 {
286 htndx = 0;
287 htpos = NULL;
288 #ifdef OUTCHAN
289 ochpos = outchan;
290 #endif
291 return(dnext());
292 }
293
294
295 EPNODE *
296 dnext() /* return pointer to next definition */
297 {
298 register EPNODE *ep;
299
300 while (htndx < NHASH) {
301 if (htpos == NULL)
302 htpos = hashtbl[htndx++];
303 while (htpos != NULL) {
304 ep = htpos->def;
305 htpos = htpos->next;
306 if (ep != NULL)
307 return(ep);
308 }
309 }
310 #ifdef OUTCHAN
311 if ((ep = ochpos) != NULL)
312 ochpos = ep->sibling;
313 return(ep);
314 #else
315 return(NULL);
316 #endif
317 }
318
319
320 EPNODE *
321 dpop(name) /* pop a definition */
322 char *name;
323 {
324 register VARDEF *vp;
325 register EPNODE *dp;
326
327 if ((vp = varlookup(name)) == NULL || vp->def == NULL)
328 return(NULL);
329 dp = vp->def;
330 vp->def = dp->sibling;
331 varfree(vp);
332 return(dp);
333 }
334
335
336 dpush(ep) /* push on a definition */
337 register EPNODE *ep;
338 {
339 register VARDEF *vp;
340
341 vp = varinsert(dname(ep));
342 ep->sibling = vp->def;
343 vp->def = ep;
344 }
345
346
347 #ifdef OUTCHAN
348 addchan(sp) /* add an output channel assignment */
349 EPNODE *sp;
350 {
351 int ch = sp->v.kid->v.chan;
352 register EPNODE *ep, *epl;
353
354 for (epl = NULL, ep = outchan; ep != NULL; epl = ep, ep = ep->sibling)
355 if (ep->v.kid->v.chan >= ch) {
356 if (epl != NULL)
357 epl->sibling = sp;
358 else
359 outchan = sp;
360 if (ep->v.kid->v.chan > ch)
361 sp->sibling = ep;
362 else {
363 sp->sibling = ep->sibling;
364 epfree(ep);
365 }
366 return;
367 }
368 if (epl != NULL)
369 epl->sibling = sp;
370 else
371 outchan = sp;
372 sp->sibling = NULL;
373
374 }
375 #endif
376
377
378 loaddefn() /* load next definition */
379 {
380 register EPNODE *ep;
381
382 if (nextc == ';') { /* empty statement */
383 scan();
384 return;
385 }
386 #ifdef OUTCHAN
387 if (nextc == '$') { /* channel assignment */
388 ep = getchan();
389 addchan(ep);
390 } else
391 #endif
392 { /* ordinary definition */
393 ep = getdefn();
394 #ifdef REDEFW
395 if (dlookup(dname(ep)) != NULL) {
396 dclear(dname(ep));
397 wputs(dname(ep));
398 if (dlookup(dname(ep)) == NULL)
399 wputs(": redefined\n");
400 else
401 wputs(": redefined constant expression\n");
402 }
403 #ifdef FUNCTION
404 else if (ep->v.kid->type == FUNC &&
405 liblookup(ep->v.kid->v.kid->v.name) != NULL) {
406 wputs(ep->v.kid->v.kid->v.name);
407 wputs(": redefined library function\n");
408 }
409 #endif
410 #else
411 dclear(dname(ep));
412 #endif
413 dpush(ep);
414 }
415 if (nextc != EOF) {
416 if (nextc != ';')
417 syntax("';' expected");
418 scan();
419 }
420 }
421
422
423 EPNODE *
424 getdefn() /* A -> SYM = E1 */
425 /* SYM : E1 */
426 /* FUNC(SYM,..) = E1 */
427 /* FUNC(SYM,..) : E1 */
428 {
429 register EPNODE *ep1, *ep2;
430
431 if (!isalpha(nextc))
432 syntax("illegal variable name");
433
434 ep1 = newnode();
435 ep1->type = SYM;
436 ep1->v.name = savestr(getname());
437
438 #ifdef FUNCTION
439 if (nextc == '(') {
440 ep2 = newnode();
441 ep2->type = FUNC;
442 addekid(ep2, ep1);
443 ep1 = ep2;
444 do {
445 scan();
446 if (!isalpha(nextc))
447 syntax("illegal variable name");
448 ep2 = newnode();
449 ep2->type = SYM;
450 ep2->v.name = savestr(getname());
451 addekid(ep1, ep2);
452 } while (nextc == ',');
453 if (nextc != ')')
454 syntax("')' expected");
455 scan();
456 curfunc = ep1;
457 } else
458 curfunc = NULL;
459 #endif
460
461 if (nextc != '=' && nextc != ':')
462 syntax("'=' or ':' expected");
463
464 ep2 = newnode();
465 ep2->type = nextc;
466 scan();
467 addekid(ep2, ep1);
468 #ifdef RCONST
469 if (
470 #ifdef FUNCTION
471 ep1->type == SYM &&
472 #endif
473 ep2->type == ':')
474 addekid(ep2, rconst(getE1()));
475 else
476 #endif
477 addekid(ep2, getE1());
478
479 if (
480 #ifdef FUNCTION
481 ep1->type == SYM &&
482 #endif
483 ep1->sibling->type != NUM) {
484 ep1 = newnode();
485 ep1->type = TICK;
486 ep1->v.tick = -1;
487 addekid(ep2, ep1);
488 ep1 = newnode();
489 ep1->type = NUM;
490 addekid(ep2, ep1);
491 }
492
493 return(ep2);
494 }
495
496
497 #ifdef OUTCHAN
498 EPNODE *
499 getchan() /* A -> $N = E1 */
500 {
501 register EPNODE *ep1, *ep2;
502
503 if (nextc != '$')
504 syntax("missing '$'");
505 scan();
506
507 ep1 = newnode();
508 ep1->type = CHAN;
509 ep1->v.chan = getinum();
510
511 if (nextc != '=')
512 syntax("'=' expected");
513 scan();
514
515 ep2 = newnode();
516 ep2->type = '=';
517 addekid(ep2, ep1);
518 addekid(ep2, getE1());
519
520 return(ep2);
521 }
522 #endif
523
524
525
526 /*
527 * The following routines are for internal use only:
528 */
529
530
531 static double
532 dvalue(name, d) /* evaluate a variable */
533 char *name;
534 EPNODE *d;
535 {
536 register EPNODE *ep1, *ep2;
537
538 if (d == NULL || d->v.kid->type != SYM) {
539 eputs(name);
540 eputs(": undefined variable\n");
541 quit(1);
542 }
543 ep1 = d->v.kid->sibling; /* get expression */
544 if (ep1->type == NUM)
545 return(ep1->v.num); /* return if number */
546 ep2 = ep1->sibling; /* check time */
547 if (ep2->v.tick < 0 || ep2->v.tick < eclock) {
548 ep2->v.tick = d->type == ':' ? 1L<<30 : eclock;
549 ep2 = ep2->sibling;
550 ep2->v.num = evalue(ep1); /* needs new value */
551 } else
552 ep2 = ep2->sibling; /* else reuse old value */
553
554 return(ep2->v.num);
555 }
556
557
558 static int
559 hash(s) /* hash a string */
560 register char *s;
561 {
562 register int rval = 0;
563
564 while (*s)
565 rval += *s++;
566
567 return(rval % NHASH);
568 }