ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 2.35
Committed: Tue Sep 26 00:14:02 2023 UTC (7 months, 2 weeks ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.34: +8 -6 lines
Log Message:
style: corrected efree() typing and channel free loop

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 2.35 static const char RCSid[] = "$Id: caldefn.c,v 2.34 2023/02/07 20:28:16 greg Exp $";
3 greg 1.1 #endif
4     /*
5     * Store variable definitions.
6     *
7     * 7/1/85 Greg Ward
8     *
9     * 11/11/85 Added conditional compiles (OUTCHAN) for control output.
10     *
11     * 4/2/86 Added conditional compiles for function definitions (FUNCTION).
12     *
13     * 1/15/88 Added clock for caching of variable values.
14     *
15     * 11/16/88 Added VARDEF structure for hard linking.
16 greg 1.2 *
17     * 5/31/90 Added conditional compile (REDEFW) for redefinition warning.
18 greg 1.8 *
19 greg 1.10 * 4/23/91 Added ':' assignment for constant expressions
20 greg 1.13 *
21     * 8/7/91 Added optional context path to append to variable names
22 greg 2.12 *
23     * 5/17/2001 Fixed clock counter wrapping behavior
24     *
25     * 2/19/03 Eliminated conditional compiles in favor of esupport extern.
26     */
27    
28 greg 2.13 #include "copyright.h"
29 greg 1.1
30     #include <ctype.h>
31    
32 schorsch 2.18 #include "rterror.h"
33 schorsch 2.22 #include "rtio.h"
34 schorsch 2.21 #include "rtmisc.h"
35 greg 1.1 #include "calcomp.h"
36    
37 greg 2.4 #ifndef NHASH
38     #define NHASH 521 /* hash size (a prime!) */
39 greg 1.1 #endif
40    
41 greg 2.5 #define hash(s) (shash(s)%NHASH)
42    
43 greg 2.4 #define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE))
44 greg 1.1
45 schorsch 2.18 static double dvalue(char *name, EPNODE *d);
46 greg 1.1
47 greg 2.12 #define MAXCLOCK (1L<<31) /* clock wrap value */
48 greg 1.1
49 greg 2.8 unsigned long eclock = 0; /* value storage timer */
50 greg 1.1
51 greg 2.11 #define MAXCNTX 1023 /* maximum context length */
52 greg 1.13
53 greg 2.11 static char context[MAXCNTX+1]; /* current context path */
54    
55 greg 1.1 static VARDEF *hashtbl[NHASH]; /* definition list */
56     static int htndx; /* index for */
57     static VARDEF *htpos; /* ...dfirst() and */
58     static EPNODE *ochpos; /* ...dnext */
59     static EPNODE *outchan;
60    
61 greg 2.10 EPNODE *curfunc = NULL;
62 greg 2.4 #define dname(ep) ((ep)->v.kid->type == SYM ? \
63 greg 1.1 (ep)->v.kid->v.name : \
64     (ep)->v.kid->v.kid->v.name)
65    
66    
67 greg 2.12 void
68 schorsch 2.16 fcompile( /* get definitions from a file */
69     char *fname
70     )
71 greg 1.1 {
72     FILE *fp;
73    
74     if (fname == NULL)
75     fp = stdin;
76     else if ((fp = fopen(fname, "r")) == NULL) {
77     eputs(fname);
78     eputs(": cannot open\n");
79     quit(1);
80     }
81 greg 2.34 #ifdef getc_unlocked /* avoid stupid semaphores */
82     flockfile(fp);
83     #endif
84     initfile(fp, fname, 0);
85 greg 1.1 while (nextc != EOF)
86 greg 1.13 getstatement();
87 greg 1.1 if (fname != NULL)
88     fclose(fp);
89 greg 2.34 #ifdef getc_unlocked
90     else
91     funlockfile(fp);
92     #endif
93 greg 1.1 }
94    
95    
96 greg 2.12 void
97 schorsch 2.16 scompile( /* get definitions from a string */
98     char *str,
99     char *fn,
100     int ln
101     )
102 greg 1.1 {
103 greg 1.4 initstr(str, fn, ln);
104 greg 1.1 while (nextc != EOF)
105 greg 1.13 getstatement();
106 greg 1.1 }
107    
108    
109     double
110 schorsch 2.16 varvalue( /* return a variable's value */
111     char *vname
112     )
113 greg 1.1 {
114     return(dvalue(vname, dlookup(vname)));
115     }
116    
117    
118     double
119 schorsch 2.16 evariable( /* evaluate a variable */
120     EPNODE *ep
121     )
122 greg 1.1 {
123 greg 2.25 VARDEF *dp = ep->v.ln;
124 greg 1.1
125     return(dvalue(dp->name, dp->def));
126     }
127    
128    
129 greg 2.12 void
130 schorsch 2.16 varset( /* set a variable's value */
131     char *vname,
132     int assign,
133     double val
134     )
135 greg 1.1 {
136 greg 1.13 char *qname;
137 greg 2.25 EPNODE *ep1, *ep2;
138 greg 1.13 /* get qualified name */
139     qname = qualname(vname, 0);
140 greg 1.1 /* check for quick set */
141 greg 2.25 if ((ep1 = dlookup(qname)) != NULL && ep1->v.kid->type == SYM &&
142     (ep1->type == ':') <= (assign == ':')) {
143 greg 1.1 ep2 = ep1->v.kid->sibling;
144     if (ep2->type == NUM) {
145     ep2->v.num = val;
146 greg 1.8 ep1->type = assign;
147 greg 1.1 return;
148     }
149     }
150 greg 2.26 if (ep1 != NULL && esupport&E_REDEFW) {
151     wputs(qname);
152     if (ep1->type == ':')
153     wputs(": reset constant expression\n");
154     else
155     wputs(": reset expression\n");
156     }
157 greg 1.1 /* hand build definition */
158     ep1 = newnode();
159 greg 1.8 ep1->type = assign;
160 greg 1.1 ep2 = newnode();
161     ep2->type = SYM;
162     ep2->v.name = savestr(vname);
163     addekid(ep1, ep2);
164     ep2 = newnode();
165     ep2->type = NUM;
166     ep2->v.num = val;
167     addekid(ep1, ep2);
168 greg 2.25 if (assign == ':')
169     dremove(qname);
170     else
171     dclear(qname);
172 greg 1.13 dpush(qname, ep1);
173 greg 1.1 }
174    
175    
176 greg 2.12 void
177 schorsch 2.16 dclear( /* delete variable definitions of name */
178     char *name
179     )
180 greg 1.1 {
181 greg 2.25 EPNODE *ep;
182 greg 1.1
183 greg 1.8 while ((ep = dpop(name)) != NULL) {
184     if (ep->type == ':') {
185 greg 1.13 dpush(name, ep); /* don't clear constants */
186 greg 1.8 return;
187     }
188     epfree(ep);
189     }
190     }
191    
192    
193 greg 2.12 void
194 schorsch 2.16 dremove( /* delete all definitions of name */
195     char *name
196     )
197 greg 1.8 {
198 greg 2.25 EPNODE *ep;
199 greg 1.8
200 greg 1.1 while ((ep = dpop(name)) != NULL)
201     epfree(ep);
202     }
203    
204    
205 greg 2.12 int
206 greg 2.30 vardefined( /* return '=' or ':' if variable/constant defined */
207 schorsch 2.16 char *name
208     )
209 greg 1.1 {
210 greg 2.31 EPNODE *dp = dlookup(name);
211 greg 1.1
212 greg 2.31 if (dp == NULL || dp->v.kid->type != SYM)
213 greg 2.30 return(0);
214 greg 2.31
215 greg 2.30 return(dp->type);
216 greg 1.1 }
217    
218    
219 greg 1.13 char *
220 greg 2.32 calcontext( /* set a new context path */
221 greg 2.25 char *ctx
222 schorsch 2.16 )
223 greg 1.13 {
224 greg 2.25 char *cpp;
225 greg 1.13
226     if (ctx == NULL)
227     return(context); /* just asking */
228 greg 2.6 while (*ctx == CNTXMARK)
229     ctx++; /* skip past marks */
230 greg 1.13 if (!*ctx) {
231 greg 2.6 context[0] = '\0'; /* empty means clear context */
232 greg 1.13 return(context);
233     }
234 greg 2.6 cpp = context; /* start context with mark */
235     *cpp++ = CNTXMARK;
236     do { /* carefully copy new context */
237 greg 2.11 if (cpp >= context+MAXCNTX)
238 greg 1.18 break; /* just copy what we can */
239 greg 1.13 if (isid(*ctx))
240     *cpp++ = *ctx++;
241     else {
242     *cpp++ = '_'; ctx++;
243     }
244     } while (*ctx);
245 greg 2.6 while (cpp[-1] == CNTXMARK) /* cannot end in context mark */
246     cpp--;
247 greg 1.13 *cpp = '\0';
248 greg 2.6 return(context);
249     }
250    
251    
252     char *
253 schorsch 2.16 pushcontext( /* push on another context */
254     char *ctx
255     )
256 greg 2.6 {
257 greg 2.11 char oldcontext[MAXCNTX+1];
258 greg 2.25 int n;
259 greg 2.6
260     strcpy(oldcontext, context); /* save old context */
261 greg 2.32 calcontext(ctx); /* set new context */
262 greg 2.6 n = strlen(context); /* tack on old */
263 greg 2.11 if (n+strlen(oldcontext) > MAXCNTX) {
264     strncpy(context+n, oldcontext, MAXCNTX-n);
265     context[MAXCNTX] = '\0';
266 greg 2.6 } else
267     strcpy(context+n, oldcontext);
268     return(context);
269     }
270    
271    
272     char *
273 schorsch 2.16 popcontext(void) /* pop off top context */
274 greg 2.6 {
275 greg 2.25 char *cp1, *cp2;
276 greg 2.6
277     if (!context[0]) /* nothing left to pop */
278     return(context);
279     cp2 = context; /* find mark */
280     while (*++cp2 && *cp2 != CNTXMARK)
281     ;
282     cp1 = context; /* copy tail to front */
283 schorsch 2.20 while ( (*cp1++ = *cp2++) )
284 greg 2.6 ;
285 greg 1.13 return(context);
286     }
287    
288    
289     char *
290 schorsch 2.16 qualname( /* get qualified name */
291 greg 2.25 char *nam,
292 schorsch 2.16 int lvl
293     )
294 greg 1.13 {
295 schorsch 2.17 static char nambuf[RMAXWORD+1];
296 greg 2.25 char *cp = nambuf, *cpp;
297 greg 1.17 /* check for explicit local */
298 greg 1.15 if (*nam == CNTXMARK)
299 greg 1.17 if (lvl > 0) /* only action is to refuse search */
300     return(NULL);
301     else
302     nam++;
303     else if (nam == nambuf) /* check for repeat call */
304     return(lvl > 0 ? NULL : nam);
305 greg 1.13 /* copy name to static buffer */
306     while (*nam) {
307 schorsch 2.17 if (cp >= nambuf+RMAXWORD)
308 greg 1.13 goto toolong;
309 greg 1.17 *cp++ = *nam++;
310 greg 1.13 }
311 greg 1.17 /* check for explicit global */
312     if (cp > nambuf && cp[-1] == CNTXMARK) {
313 greg 1.13 if (lvl > 0)
314 greg 1.17 return(NULL);
315     *--cp = '\0';
316     return(nambuf); /* already qualified */
317     }
318     cpp = context; /* else skip the requested levels */
319     while (lvl-- > 0) {
320     if (!*cpp)
321     return(NULL); /* return NULL if past global level */
322     while (*++cpp && *cpp != CNTXMARK)
323     ;
324     }
325 greg 1.13 while (*cpp) { /* copy context to static buffer */
326 schorsch 2.17 if (cp >= nambuf+RMAXWORD)
327 greg 1.13 goto toolong;
328     *cp++ = *cpp++;
329     }
330 greg 1.18 toolong:
331 greg 1.13 *cp = '\0';
332     return(nambuf); /* return qualified name */
333     }
334    
335    
336 greg 2.12 int
337 schorsch 2.16 incontext( /* is qualified name in current context? */
338 greg 2.25 char *qn
339 schorsch 2.16 )
340 greg 1.14 {
341 greg 2.9 if (!context[0]) /* global context accepts all */
342     return(1);
343 greg 1.14 while (*qn && *qn != CNTXMARK) /* find context mark */
344 greg 1.19 qn++;
345 greg 1.14 return(!strcmp(qn, context));
346     }
347    
348    
349 greg 2.12 void
350 schorsch 2.16 chanout( /* set output channels */
351     void (*cs)(int n, double v)
352     )
353 greg 1.1 {
354 greg 2.25 EPNODE *ep;
355 greg 1.1
356     for (ep = outchan; ep != NULL; ep = ep->sibling)
357 greg 1.6 (*cs)(ep->v.kid->v.chan, evalue(ep->v.kid->sibling));
358 greg 1.1
359     }
360    
361    
362 greg 2.12 void
363 schorsch 2.16 dcleanup( /* clear definitions (0->vars,1->output,2->consts) */
364     int lvl
365     )
366 greg 1.1 {
367 greg 2.25 int i;
368     VARDEF *vp;
369     EPNODE *ep;
370 greg 1.14 /* if context is global, clear all */
371 greg 1.1 for (i = 0; i < NHASH; i++)
372     for (vp = hashtbl[i]; vp != NULL; vp = vp->next)
373 schorsch 2.19 if (incontext(vp->name)) {
374 greg 1.14 if (lvl >= 2)
375     dremove(vp->name);
376     else
377     dclear(vp->name);
378 schorsch 2.19 }
379 greg 2.35 if (lvl >= 1)
380     while (outchan != NULL) {
381     ep = outchan;
382     outchan = ep->sibling;
383     ep->sibling = NULL;
384 greg 1.9 epfree(ep);
385 greg 2.35 }
386 greg 1.1 }
387    
388    
389     EPNODE *
390 schorsch 2.16 dlookup( /* look up a definition */
391     char *name
392     )
393 greg 1.1 {
394 greg 2.25 VARDEF *vp;
395 greg 1.1
396     if ((vp = varlookup(name)) == NULL)
397 greg 2.4 return(NULL);
398 greg 1.1 return(vp->def);
399     }
400    
401    
402     VARDEF *
403 schorsch 2.16 varlookup( /* look up a variable */
404     char *name
405     )
406 greg 1.1 {
407 greg 2.4 int lvl = 0;
408 greg 2.25 char *qname;
409     VARDEF *vp;
410 greg 2.4 /* find most qualified match */
411 greg 1.13 while ((qname = qualname(name, lvl++)) != NULL)
412     for (vp = hashtbl[hash(qname)]; vp != NULL; vp = vp->next)
413     if (!strcmp(vp->name, qname))
414     return(vp);
415 greg 1.1 return(NULL);
416     }
417    
418    
419     VARDEF *
420 schorsch 2.16 varinsert( /* get a link to a variable */
421     char *name
422     )
423 greg 1.1 {
424 greg 2.25 VARDEF *vp;
425 greg 2.4 int hv;
426 greg 1.1
427 greg 1.13 if ((vp = varlookup(name)) != NULL) {
428     vp->nlinks++;
429     return(vp);
430     }
431 greg 2.3 vp = (VARDEF *)emalloc(sizeof(VARDEF));
432     vp->lib = liblookup(name);
433     if (vp->lib == NULL) /* if name not in library */
434 greg 1.16 name = qualname(name, 0); /* use fully qualified version */
435 greg 1.1 hv = hash(name);
436     vp->name = savestr(name);
437     vp->nlinks = 1;
438     vp->def = NULL;
439     vp->next = hashtbl[hv];
440     hashtbl[hv] = vp;
441     return(vp);
442     }
443 greg 2.2
444    
445 greg 2.12 void
446 schorsch 2.16 libupdate( /* update library links */
447     char *fn
448     )
449 greg 2.2 {
450 greg 2.25 int i;
451     VARDEF *vp;
452 greg 2.2 /* if fn is NULL then relink all */
453     for (i = 0; i < NHASH; i++)
454     for (vp = hashtbl[i]; vp != NULL; vp = vp->next)
455 greg 2.33 if ((vp->lib != NULL) | (fn == NULL) || !strcmp(fn, vp->name))
456 greg 2.2 vp->lib = liblookup(vp->name);
457     }
458 greg 1.1
459    
460 greg 2.12 void
461 schorsch 2.16 varfree( /* release link to variable */
462 greg 2.25 VARDEF *ln
463 schorsch 2.16 )
464 greg 1.1 {
465 greg 2.25 VARDEF *vp;
466 greg 2.4 int hv;
467 greg 1.1
468     if (--ln->nlinks > 0)
469 greg 2.4 return; /* still active */
470 greg 1.1
471     hv = hash(ln->name);
472     vp = hashtbl[hv];
473     if (vp == ln)
474 greg 2.4 hashtbl[hv] = vp->next;
475 greg 1.1 else {
476 greg 2.4 while (vp->next != ln) /* must be in list */
477     vp = vp->next;
478     vp->next = ln->next;
479 greg 1.1 }
480     freestr(ln->name);
481 greg 2.35 efree(ln);
482 greg 1.1 }
483    
484    
485     EPNODE *
486 schorsch 2.16 dfirst(void) /* return pointer to first definition */
487 greg 1.1 {
488     htndx = 0;
489     htpos = NULL;
490     ochpos = outchan;
491     return(dnext());
492     }
493    
494    
495     EPNODE *
496 schorsch 2.16 dnext(void) /* return pointer to next definition */
497 greg 1.1 {
498 greg 2.25 EPNODE *ep;
499     char *nm;
500 greg 1.1
501     while (htndx < NHASH) {
502 greg 2.4 if (htpos == NULL)
503     htpos = hashtbl[htndx++];
504     while (htpos != NULL) {
505     ep = htpos->def;
506 greg 1.19 nm = htpos->name;
507 greg 2.4 htpos = htpos->next;
508     if (ep != NULL && incontext(nm))
509     return(ep);
510     }
511 greg 1.1 }
512     if ((ep = ochpos) != NULL)
513 greg 2.4 ochpos = ep->sibling;
514 greg 1.1 return(ep);
515     }
516    
517    
518     EPNODE *
519 schorsch 2.16 dpop( /* pop a definition */
520     char *name
521     )
522 greg 1.1 {
523 greg 2.25 VARDEF *vp;
524     EPNODE *dp;
525 greg 1.1
526     if ((vp = varlookup(name)) == NULL || vp->def == NULL)
527 greg 2.4 return(NULL);
528 greg 1.1 dp = vp->def;
529     vp->def = dp->sibling;
530     varfree(vp);
531     return(dp);
532     }
533    
534    
535 greg 2.12 void
536 schorsch 2.16 dpush( /* push on a definition */
537     char *nm,
538 greg 2.25 EPNODE *ep
539 schorsch 2.16 )
540 greg 1.1 {
541 greg 2.25 VARDEF *vp;
542 greg 1.1
543 greg 1.13 vp = varinsert(nm);
544 greg 1.1 ep->sibling = vp->def;
545     vp->def = ep;
546     }
547    
548    
549 greg 2.12 void
550 schorsch 2.16 addchan( /* add an output channel assignment */
551     EPNODE *sp
552     )
553 greg 1.1 {
554 greg 2.4 int ch = sp->v.kid->v.chan;
555 greg 2.25 EPNODE *ep, *epl;
556 greg 1.1
557     for (epl = NULL, ep = outchan; ep != NULL; epl = ep, ep = ep->sibling)
558     if (ep->v.kid->v.chan >= ch) {
559     if (epl != NULL)
560     epl->sibling = sp;
561     else
562     outchan = sp;
563     if (ep->v.kid->v.chan > ch)
564     sp->sibling = ep;
565     else {
566     sp->sibling = ep->sibling;
567     epfree(ep);
568     }
569     return;
570     }
571     if (epl != NULL)
572     epl->sibling = sp;
573     else
574     outchan = sp;
575     sp->sibling = NULL;
576    
577     }
578    
579    
580 greg 2.12 void
581 schorsch 2.16 getstatement(void) /* get next statement */
582 greg 1.1 {
583 greg 2.25 EPNODE *ep;
584 greg 1.13 char *qname;
585 greg 2.25 VARDEF *vdef;
586 greg 1.1
587     if (nextc == ';') { /* empty statement */
588     scan();
589     return;
590     }
591 greg 2.12 if (esupport&E_OUTCHAN &&
592     nextc == '$') { /* channel assignment */
593 greg 1.1 ep = getchan();
594     addchan(ep);
595 greg 2.12 } else { /* ordinary definition */
596 greg 1.1 ep = getdefn();
597 greg 1.13 qname = qualname(dname(ep), 0);
598 schorsch 2.19 if (esupport&E_REDEFW && (vdef = varlookup(qname)) != NULL) {
599 greg 2.7 if (vdef->def != NULL && epcmp(ep, vdef->def)) {
600 greg 1.16 wputs(qname);
601     if (vdef->def->type == ':')
602     wputs(": redefined constant expression\n");
603     else
604     wputs(": redefined\n");
605 greg 2.12 } else if (ep->v.kid->type == FUNC && vdef->lib != NULL) {
606 greg 1.16 wputs(qname);
607     wputs(": definition hides library function\n");
608     }
609 schorsch 2.19 }
610 greg 1.10 if (ep->type == ':')
611 greg 1.13 dremove(qname);
612 greg 1.10 else
613 greg 1.13 dclear(qname);
614     dpush(qname, ep);
615 greg 1.1 }
616     if (nextc != EOF) {
617     if (nextc != ';')
618     syntax("';' expected");
619     scan();
620     }
621     }
622    
623    
624     EPNODE *
625 schorsch 2.16 getdefn(void)
626     /* A -> SYM = E1 */
627     /* SYM : E1 */
628     /* FUNC(SYM,..) = E1 */
629     /* FUNC(SYM,..) : E1 */
630 greg 1.1 {
631 greg 2.25 EPNODE *ep1, *ep2;
632 greg 1.1
633 greg 2.33 if (!isalpha(nextc) & (nextc != CNTXMARK))
634 greg 1.1 syntax("illegal variable name");
635    
636     ep1 = newnode();
637     ep1->type = SYM;
638     ep1->v.name = savestr(getname());
639    
640 greg 2.12 if (esupport&E_FUNCTION && nextc == '(') {
641 greg 1.1 ep2 = newnode();
642     ep2->type = FUNC;
643     addekid(ep2, ep1);
644     ep1 = ep2;
645     do {
646     scan();
647     if (!isalpha(nextc))
648 greg 2.24 syntax("illegal parameter name");
649 greg 1.1 ep2 = newnode();
650     ep2->type = SYM;
651     ep2->v.name = savestr(getname());
652 greg 2.29 if (strchr(ep2->v.name, CNTXMARK) != NULL)
653     syntax("illegal parameter name");
654 greg 1.1 addekid(ep1, ep2);
655     } while (nextc == ',');
656     if (nextc != ')')
657     syntax("')' expected");
658     scan();
659     curfunc = ep1;
660 greg 2.10 }
661 greg 1.1
662 greg 2.33 if ((nextc != '=') & (nextc != ':'))
663 greg 1.8 syntax("'=' or ':' expected");
664 greg 1.1
665     ep2 = newnode();
666 greg 1.8 ep2->type = nextc;
667     scan();
668 greg 1.1 addekid(ep2, ep1);
669     addekid(ep2, getE1());
670    
671 greg 2.12 if (ep1->type == SYM && ep1->sibling->type != NUM) {
672 greg 1.1 ep1 = newnode();
673 greg 2.23 ep1->type = CLKT;
674 greg 2.8 ep1->v.tick = 0;
675 greg 1.1 addekid(ep2, ep1);
676     ep1 = newnode();
677     ep1->type = NUM;
678     addekid(ep2, ep1);
679     }
680 greg 2.10 curfunc = NULL;
681 greg 1.1
682     return(ep2);
683     }
684    
685    
686     EPNODE *
687 schorsch 2.16 getchan(void) /* A -> $N = E1 */
688 greg 1.1 {
689 greg 2.25 EPNODE *ep1, *ep2;
690 greg 1.1
691     if (nextc != '$')
692     syntax("missing '$'");
693     scan();
694    
695     ep1 = newnode();
696     ep1->type = CHAN;
697     ep1->v.chan = getinum();
698    
699     if (nextc != '=')
700     syntax("'=' expected");
701     scan();
702    
703     ep2 = newnode();
704     ep2->type = '=';
705     addekid(ep2, ep1);
706     addekid(ep2, getE1());
707    
708     return(ep2);
709     }
710    
711    
712    
713     /*
714     * The following routines are for internal use only:
715     */
716    
717    
718 schorsch 2.18 static double /* evaluate a variable */
719 greg 2.28 dvalue(char *name, EPNODE *d)
720 greg 1.1 {
721 greg 2.25 EPNODE *ep1, *ep2;
722 greg 1.1
723     if (d == NULL || d->v.kid->type != SYM) {
724     eputs(name);
725     eputs(": undefined variable\n");
726     quit(1);
727     }
728     ep1 = d->v.kid->sibling; /* get expression */
729 greg 1.5 if (ep1->type == NUM)
730     return(ep1->v.num); /* return if number */
731 greg 2.28 if (esupport&E_RCONST && d->type == ':') {
732     wputs(name);
733     wputs(": assigned non-constant value\n");
734     }
735 greg 1.1 ep2 = ep1->sibling; /* check time */
736 greg 2.12 if (eclock >= MAXCLOCK)
737     eclock = 1; /* wrap clock counter */
738     if (ep2->v.tick < MAXCLOCK &&
739 schorsch 2.20 (ep2->v.tick == 0) | (ep2->v.tick != eclock)) {
740 greg 2.12 ep2->v.tick = d->type == ':' ? MAXCLOCK : eclock;
741 greg 1.1 ep2 = ep2->sibling;
742 greg 1.5 ep2->v.num = evalue(ep1); /* needs new value */
743 greg 1.1 } else
744 greg 1.5 ep2 = ep2->sibling; /* else reuse old value */
745 greg 1.1
746     return(ep2->v.num);
747     }