ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 1.7
Committed: Fri Jul 20 08:30:23 1990 UTC (33 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.6: +3 -2 lines
Log Message:
forgot addition for elimination of TICK for numeric def'ns

File Contents

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