ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 1.4
Committed: Thu Jul 19 11:06:37 1990 UTC (33 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.3: +5 -4 lines
Log Message:
added line numbers to error reports

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