ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 2.31
Committed: Sat Mar 12 17:21:10 2022 UTC (2 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.30: +4 -3 lines
Log Message:
style: Minor code cleanup

File Contents

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