ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 2.36
Committed: Tue Sep 26 18:33:14 2023 UTC (7 months, 3 weeks ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.35: +5 -9 lines
Log Message:
style: minor code clean-ups

File Contents

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