ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/caldefn.c
Revision: 2.41
Committed: Wed Jan 1 19:02:08 2025 UTC (3 months, 4 weeks ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.40: +4 -4 lines
Log Message:
fix: Increased buffer size for qualified variable names to something sensible

File Contents

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