ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 1.10
Committed: Mon Apr 29 08:33:13 1991 UTC (33 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.9: +14 -21 lines
Log Message:
minor changes to ':' assignment code

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
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(lvl) /* clear definitions (0->vars,1->consts,2->output) */
189 int lvl;
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 (lvl >= 1)
198 dremove(vp->name);
199 else
200 dclear(vp->name);
201 #ifdef OUTCHAN
202 if (lvl >= 2) {
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 EPNODE *lastdef;
382
383 if (nextc == ';') { /* empty statement */
384 scan();
385 return;
386 }
387 #ifdef OUTCHAN
388 if (nextc == '$') { /* channel assignment */
389 ep = getchan();
390 addchan(ep);
391 } else
392 #endif
393 { /* ordinary definition */
394 ep = getdefn();
395 #ifdef REDEFW
396 if ((lastdef = dlookup(dname(ep))) != NULL) {
397 wputs(dname(ep));
398 if (lastdef->type == ':')
399 wputs(": redefined constant expression\n");
400 else
401 wputs(": redefined\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 #endif
411 if (ep->type == ':')
412 dremove(dname(ep));
413 else
414 dclear(dname(ep));
415 dpush(ep);
416 }
417 if (nextc != EOF) {
418 if (nextc != ';')
419 syntax("';' expected");
420 scan();
421 }
422 }
423
424
425 EPNODE *
426 getdefn() /* A -> SYM = E1 */
427 /* SYM : E1 */
428 /* FUNC(SYM,..) = E1 */
429 /* FUNC(SYM,..) : E1 */
430 {
431 register EPNODE *ep1, *ep2;
432
433 if (!isalpha(nextc))
434 syntax("illegal variable name");
435
436 ep1 = newnode();
437 ep1->type = SYM;
438 ep1->v.name = savestr(getname());
439
440 #ifdef FUNCTION
441 if (nextc == '(') {
442 ep2 = newnode();
443 ep2->type = FUNC;
444 addekid(ep2, ep1);
445 ep1 = ep2;
446 do {
447 scan();
448 if (!isalpha(nextc))
449 syntax("illegal variable name");
450 ep2 = newnode();
451 ep2->type = SYM;
452 ep2->v.name = savestr(getname());
453 addekid(ep1, ep2);
454 } while (nextc == ',');
455 if (nextc != ')')
456 syntax("')' expected");
457 scan();
458 curfunc = ep1;
459 } else
460 curfunc = NULL;
461 #endif
462
463 if (nextc != '=' && nextc != ':')
464 syntax("'=' or ':' expected");
465
466 ep2 = newnode();
467 ep2->type = nextc;
468 scan();
469 addekid(ep2, ep1);
470 addekid(ep2, getE1());
471
472 if (
473 #ifdef FUNCTION
474 ep1->type == SYM &&
475 #endif
476 ep1->sibling->type != NUM) {
477 ep1 = newnode();
478 ep1->type = TICK;
479 ep1->v.tick = -1;
480 addekid(ep2, ep1);
481 ep1 = newnode();
482 ep1->type = NUM;
483 addekid(ep2, ep1);
484 }
485
486 return(ep2);
487 }
488
489
490 #ifdef OUTCHAN
491 EPNODE *
492 getchan() /* A -> $N = E1 */
493 {
494 register EPNODE *ep1, *ep2;
495
496 if (nextc != '$')
497 syntax("missing '$'");
498 scan();
499
500 ep1 = newnode();
501 ep1->type = CHAN;
502 ep1->v.chan = getinum();
503
504 if (nextc != '=')
505 syntax("'=' expected");
506 scan();
507
508 ep2 = newnode();
509 ep2->type = '=';
510 addekid(ep2, ep1);
511 addekid(ep2, getE1());
512
513 return(ep2);
514 }
515 #endif
516
517
518
519 /*
520 * The following routines are for internal use only:
521 */
522
523
524 static double
525 dvalue(name, d) /* evaluate a variable */
526 char *name;
527 EPNODE *d;
528 {
529 register EPNODE *ep1, *ep2;
530
531 if (d == NULL || d->v.kid->type != SYM) {
532 eputs(name);
533 eputs(": undefined variable\n");
534 quit(1);
535 }
536 ep1 = d->v.kid->sibling; /* get expression */
537 if (ep1->type == NUM)
538 return(ep1->v.num); /* return if number */
539 ep2 = ep1->sibling; /* check time */
540 if (ep2->v.tick < 0 || ep2->v.tick < eclock) {
541 ep2->v.tick = d->type == ':' ? 1L<<30 : eclock;
542 ep2 = ep2->sibling;
543 ep2->v.num = evalue(ep1); /* needs new value */
544 } else
545 ep2 = ep2->sibling; /* else reuse old value */
546
547 return(ep2->v.num);
548 }
549
550
551 static int
552 hash(s) /* hash a string */
553 register char *s;
554 {
555 register int rval = 0;
556
557 while (*s)
558 rval += *s++;
559
560 return(rval % NHASH);
561 }