ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 1.1
Committed: Thu Feb 2 10:34:26 1989 UTC (35 years, 3 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

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