ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/Development/ray/src/common/calexpr.c
Revision: 2.56
Committed: Sat Dec 6 16:39:20 2025 UTC (13 days, 13 hours ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.55: +8 -3 lines
Log Message:
perf: Enabled more constant reductions with '-' operator

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 2.56 static const char RCSid[] = "$Id: calexpr.c,v 2.55 2025/12/06 04:07:05 greg Exp $";
3 greg 1.1 #endif
4     /*
5     * Compute data values using expression parser
6     *
7     * 7/1/85 Greg Ward
8     *
9     * 11/11/85 Made channel input conditional with (INCHAN) compiles.
10     *
11     * 4/2/86 Added conditional compiles for function definitions (FUNCTION).
12     *
13     * 1/29/87 Made variables conditional (VARIABLE)
14     *
15     * 5/19/88 Added constant subexpression elimination (RCONST)
16 greg 2.18 *
17     * 2/19/03 Eliminated conditional compiles in favor of esupport extern.
18     */
19    
20 greg 2.19 #include "copyright.h"
21 greg 1.1
22     #include <ctype.h>
23     #include <errno.h>
24 greg 2.8 #include <math.h>
25 greg 2.18 #include <stdlib.h>
26    
27 schorsch 2.29 #include "rtmisc.h"
28     #include "rtio.h"
29 schorsch 2.24 #include "rterror.h"
30 greg 1.1 #include "calcomp.h"
31    
32 greg 2.6 #define MAXLINE 256 /* maximum line length */
33 greg 1.1
34 greg 2.6 #define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE))
35 greg 1.1
36 greg 2.42 #define isdecimal(c) (isdigit(c) | ((c) == '.'))
37 greg 1.1
38 greg 2.44 #define envalue(ep) ((ep)->type==NUM ? (ep)->v.num : evalue(ep))
39    
40 greg 2.49 static double euminus(EPNODE *), enumber(EPNODE *);
41 schorsch 2.24 static double echannel(EPNODE *);
42     static double eadd(EPNODE *), esubtr(EPNODE *),
43     emult(EPNODE *), edivi(EPNODE *),
44     epow(EPNODE *);
45     static double ebotch(EPNODE *);
46 greg 1.1
47 greg 2.18 unsigned int esupport = /* what to support */
48 greg 2.21 E_VARIABLE | E_FUNCTION ;
49 greg 2.15
50 greg 2.30 int eofc = 0; /* optional end-of-file character */
51 greg 1.1 int nextc; /* lookahead character */
52    
53 greg 2.27 double (*eoper[])(EPNODE *) = { /* expression operations */
54 greg 1.1 ebotch,
55     evariable,
56     enumber,
57     euminus,
58     echannel,
59     efunc,
60     eargument,
61     ebotch,
62     ebotch,
63     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
64     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
65     emult,
66     eadd,
67     0,
68     esubtr,
69     0,
70     edivi,
71 greg 1.9 0,0,0,0,0,0,0,0,0,0,
72 greg 1.1 ebotch,
73 greg 1.9 0,0,
74     ebotch,
75 greg 1.1 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
76     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
77     epow,
78     };
79    
80     static FILE *infp; /* input file pointer */
81     static char *linbuf; /* line buffer */
82 greg 1.6 static char *infile; /* input file name */
83     static int lineno; /* input line number */
84 greg 1.1 static int linepos; /* position in buffer */
85    
86    
87     EPNODE *
88 schorsch 2.28 eparse( /* parse an expression string */
89     char *expr
90     )
91 greg 1.1 {
92     EPNODE *ep;
93    
94 greg 1.6 initstr(expr, NULL, 0);
95 greg 2.51 ecurfunc = NULL;
96 greg 1.1 ep = getE1();
97     if (nextc != EOF)
98 greg 2.51 esyntax("unexpected character");
99 greg 1.1 return(ep);
100     }
101    
102    
103     double
104 schorsch 2.28 eval( /* evaluate an expression string */
105     char *expr
106     )
107 greg 1.1 {
108 greg 2.38 int prev_support = esupport;
109 greg 2.37 EPNODE *ep;
110 greg 1.1 double rval;
111    
112 greg 2.38 esupport &= ~E_RCONST; /* don't bother reducing constant expr */
113 greg 1.1 ep = eparse(expr);
114 greg 2.38 esupport = prev_support; /* as you were */
115 greg 1.1 rval = evalue(ep);
116 greg 2.43 epfree(ep,1);
117 greg 1.1 return(rval);
118     }
119    
120    
121 greg 2.18 int
122 schorsch 2.28 epcmp( /* compare two expressions for equivalence */
123 greg 2.37 EPNODE *ep1,
124     EPNODE *ep2
125 schorsch 2.28 )
126 greg 2.16 {
127     double d;
128    
129     if (ep1->type != ep2->type)
130     return(1);
131    
132     switch (ep1->type) {
133    
134     case VAR:
135     return(ep1->v.ln != ep2->v.ln);
136    
137     case NUM:
138     if (ep2->v.num == 0)
139     return(ep1->v.num != 0);
140     d = ep1->v.num / ep2->v.num;
141 schorsch 2.26 return((d > 1.000000000001) | (d < 0.999999999999));
142 greg 2.16
143     case CHAN:
144     case ARG:
145     return(ep1->v.chan != ep2->v.chan);
146    
147     case '=':
148     case ':':
149     return(epcmp(ep1->v.kid->sibling, ep2->v.kid->sibling));
150    
151 greg 2.32 case CLKT:
152 greg 2.16 case SYM: /* should never get this one */
153     return(0);
154    
155     default:
156     ep1 = ep1->v.kid;
157     ep2 = ep2->v.kid;
158     while (ep1 != NULL) {
159     if (ep2 == NULL)
160     return(1);
161     if (epcmp(ep1, ep2))
162     return(1);
163     ep1 = ep1->sibling;
164     ep2 = ep2->sibling;
165     }
166     return(ep2 != NULL);
167     }
168     }
169    
170    
171 greg 2.18 void
172 schorsch 2.28 epfree( /* free a parse tree */
173 greg 2.43 EPNODE *epar,
174     int frep
175 schorsch 2.28 )
176 greg 1.1 {
177 greg 2.43 EPNODE *ep;
178 greg 1.1
179     switch (epar->type) {
180    
181     case VAR:
182     varfree(epar->v.ln);
183     break;
184    
185     case SYM:
186     freestr(epar->v.name);
187     break;
188    
189     case NUM:
190     case CHAN:
191     case ARG:
192 greg 2.32 case CLKT:
193 greg 1.1 break;
194    
195     default:
196 greg 2.43 if (epar->nkids < 0) {
197     ep = epar->v.kid - epar->nkids;
198     while (ep > epar->v.kid)
199     epfree(--ep, 0);
200     efree(ep); /* free array space */
201     } else
202     while ((ep = epar->v.kid) != NULL) {
203     epar->v.kid = ep->sibling;
204     epfree(ep, 1);
205     }
206 greg 1.1 break;
207    
208     }
209 greg 2.43 if (frep)
210     efree(epar);
211 greg 2.50 else
212     memset(epar, 0, sizeof(EPNODE));
213 greg 2.43 }
214    
215 greg 1.1
216 greg 2.45 static void
217 greg 2.44 epflatten( /* flatten hierarchies for '+', '*' */
218     EPNODE *epar
219     )
220     {
221 greg 2.54 EPNODE *ep, *ep1;
222 greg 2.53 double combined;
223 greg 2.44
224 greg 2.53 if (epar->nkids <= 0) /* can't handle array allocations */
225 greg 2.48 return;
226    
227 greg 2.44 for (ep = epar->v.kid; ep != NULL; ep = ep->sibling)
228 greg 2.53 while ((ep->type == epar->type) & (ep->nkids > 0)) {
229     ep1 = ep->v.kid;
230 greg 2.44 while (ep1->sibling != NULL)
231     ep1 = ep1->sibling;
232     ep1->sibling = ep->sibling;
233 greg 2.48 epar->nkids += ep->nkids - 1;
234 greg 2.44 ep1 = ep->v.kid;
235     *ep = *ep1;
236     efree(ep1); /* not epfree()! */
237     }
238 greg 2.55 if (!(esupport & E_RCONST))
239 greg 2.53 return;
240 greg 2.54 ep1 = NULL; /* combine constants in sum/product */
241 greg 2.53 for (ep = epar->v.kid; ep != NULL; ep = ep->sibling)
242     if (ep->type == NUM) {
243     if (ep1 == NULL) combined = (ep1 = ep)->v.num;
244     else if (epar->type == '+') combined += ep->v.num;
245 greg 2.54 else /* epar->type=='*' */ combined *= ep->v.num;
246 greg 2.53 }
247     if (ep1 == NULL)
248     return;
249 greg 2.55 ep1->v.num = combined; /* assumes commutative property, also */
250 greg 2.53 while (ep1->sibling != NULL)
251     if (ep1->sibling->type == NUM) {
252 greg 2.54 ep = ep1->sibling;
253     ep1->sibling = ep->sibling;
254 greg 2.55 epar->nkids--;
255     efree(ep); /* drop subsumed constant */
256 greg 2.53 } else
257 greg 2.54 ep1 = ep1->sibling;
258 greg 2.55
259     if (epar->nkids == 1) { /* late constant expression? */
260     ep = epar->v.kid;
261     *epar = *ep;
262     efree(ep);
263     }
264 greg 2.44 }
265    
266    
267     void
268 greg 2.47 epoptimize( /* flatten operations, lists -> arrays */
269 greg 2.43 EPNODE *epar
270     )
271     {
272     EPNODE *ep;
273    
274 greg 2.45 if ((epar->type == '+') | (epar->type == '*'))
275 greg 2.47 epflatten(epar); /* flatten associative operations */
276 greg 2.44
277 greg 2.45 if (epar->nkids) /* do children if any */
278 greg 2.44 for (ep = epar->v.kid; ep != NULL; ep = ep->sibling)
279     epoptimize(ep);
280    
281     if (epar->nkids > 4) { /* make list into array if > 4 kids */
282 greg 2.43 int n = 1;
283     epar->v.kid = (EPNODE *)erealloc(epar->v.kid,
284     sizeof(EPNODE)*epar->nkids);
285     while (n < epar->nkids) {
286     ep = epar->v.kid[n-1].sibling;
287     epar->v.kid[n] = *ep;
288     efree(ep); /* not epfree()! */
289     epar->v.kid[n-1].sibling = epar->v.kid + n;
290     n++;
291     }
292 greg 2.44 epar->nkids = -n;
293 greg 2.43 }
294 greg 1.1 }
295    
296     /* the following used to be a switch */
297     static double
298 schorsch 2.28 enumber(
299     EPNODE *ep
300     )
301 greg 1.1 {
302     return(ep->v.num);
303     }
304    
305     static double
306 schorsch 2.28 euminus(
307     EPNODE *ep
308     )
309 greg 1.1 {
310 greg 2.37 EPNODE *ep1 = ep->v.kid;
311 greg 1.1
312     return(-evalue(ep1));
313     }
314    
315     static double
316 schorsch 2.28 echannel(
317     EPNODE *ep
318     )
319 greg 1.1 {
320     return(chanvalue(ep->v.chan));
321     }
322    
323     static double
324 schorsch 2.28 eadd(
325     EPNODE *ep
326     )
327 greg 1.1 {
328 greg 2.44 double sum = 0;
329 greg 2.37 EPNODE *ep1 = ep->v.kid;
330 greg 1.1
331 greg 2.44 do
332     sum += envalue(ep1);
333     while ((ep1 = ep1->sibling) != NULL);
334    
335     return(sum);
336 greg 1.1 }
337    
338     static double
339 schorsch 2.28 esubtr(
340     EPNODE *ep
341     )
342 greg 1.1 {
343 greg 2.37 EPNODE *ep1 = ep->v.kid;
344 greg 2.44 EPNODE *ep2 = ep1->sibling;
345 greg 1.1
346 greg 2.44 return(envalue(ep1) - envalue(ep2));
347 greg 1.1 }
348    
349     static double
350 schorsch 2.28 emult(
351     EPNODE *ep
352     )
353 greg 1.1 {
354 greg 2.44 double prod = 1;
355 greg 2.37 EPNODE *ep1 = ep->v.kid;
356 greg 1.1
357 greg 2.44 do
358     prod *= envalue(ep1);
359     while ((ep1 = ep1->sibling) != NULL);
360    
361     return(prod);
362 greg 1.1 }
363    
364     static double
365 schorsch 2.28 edivi(
366     EPNODE *ep
367     )
368 greg 1.1 {
369 greg 2.37 EPNODE *ep1 = ep->v.kid;
370 greg 2.48 double den = evalue(ep1->sibling);
371 greg 1.1
372 greg 2.48 if (den == 0.0) {
373 greg 1.1 wputs("Division by zero\n");
374     errno = ERANGE;
375     return(0.0);
376     }
377 greg 2.48 return(envalue(ep1) / den);
378 greg 1.1 }
379    
380     static double
381 schorsch 2.28 epow(
382     EPNODE *ep
383     )
384 greg 1.1 {
385 greg 2.37 EPNODE *ep1 = ep->v.kid;
386 greg 1.1 double d;
387 greg 2.6 int lasterrno;
388 greg 1.1
389     lasterrno = errno;
390     errno = 0;
391     d = pow(evalue(ep1), evalue(ep1->sibling));
392 greg 2.31 #ifdef isnan
393 greg 2.36 if (errno == 0) {
394 greg 2.31 if (isnan(d))
395     errno = EDOM;
396     else if (isinf(d))
397     errno = ERANGE;
398 greg 2.36 }
399 greg 1.1 #endif
400 greg 2.42 if ((errno == EDOM) | (errno == ERANGE)) {
401 greg 1.1 wputs("Illegal power\n");
402     return(0.0);
403     }
404     errno = lasterrno;
405     return(d);
406     }
407    
408     static double
409 schorsch 2.28 ebotch(
410     EPNODE *ep
411     )
412 greg 1.1 {
413     eputs("Bad expression!\n");
414     quit(1);
415 schorsch 2.22 return 0.0; /* pro forma return */
416 greg 1.1 }
417    
418    
419     EPNODE *
420 schorsch 2.28 ekid( /* return pointer to a node's nth kid */
421 greg 2.37 EPNODE *ep,
422     int n
423 schorsch 2.28 )
424 greg 1.1 {
425 greg 2.43 if (ep->nkids < 0) { /* allocated array? */
426     if (n >= -ep->nkids)
427     return(NULL);
428     return(ep->v.kid + n);
429     }
430     ep = ep->v.kid; /* else get from list */
431     while (n-- > 0)
432     if ((ep = ep->sibling) == NULL)
433     break;
434 greg 1.1 return(ep);
435     }
436    
437    
438 greg 2.18 void
439 schorsch 2.28 initfile( /* prepare input file */
440     FILE *fp,
441     char *fn,
442     int ln
443     )
444 greg 1.1 {
445 greg 2.6 static char inpbuf[MAXLINE];
446 greg 1.1
447     infp = fp;
448     linbuf = inpbuf;
449 greg 1.6 infile = fn;
450     lineno = ln;
451 greg 1.1 linepos = 0;
452     inpbuf[0] = '\0';
453 greg 2.51 escan();
454 greg 1.1 }
455    
456    
457 greg 2.18 void
458 schorsch 2.28 initstr( /* prepare input string */
459     char *s,
460     char *fn,
461     int ln
462     )
463 greg 1.1 {
464     infp = NULL;
465 greg 1.6 infile = fn;
466     lineno = ln;
467 greg 1.1 linbuf = s;
468     linepos = 0;
469 greg 2.51 escan();
470 greg 1.1 }
471    
472    
473 greg 2.18 void
474 schorsch 2.28 getscanpos( /* return current scan position */
475     char **fnp,
476     int *lnp,
477     char **spp,
478     FILE **fpp
479     )
480 greg 1.13 {
481     if (fnp != NULL) *fnp = infile;
482     if (lnp != NULL) *lnp = lineno;
483     if (spp != NULL) *spp = linbuf+linepos;
484     if (fpp != NULL) *fpp = infp;
485     }
486    
487    
488 greg 1.12 int
489 greg 2.51 escan(void) /* scan next character, return literal next */
490 greg 1.1 {
491 greg 2.37 int lnext = 0;
492 greg 1.12
493 greg 1.1 do {
494     if (linbuf[linepos] == '\0')
495     if (infp == NULL || fgets(linbuf, MAXLINE, infp) == NULL)
496     nextc = EOF;
497     else {
498     nextc = linbuf[0];
499 greg 1.6 lineno++;
500 greg 1.1 linepos = 1;
501     }
502     else
503     nextc = linbuf[linepos++];
504 greg 1.12 if (!lnext)
505     lnext = nextc;
506 greg 2.30 if (nextc == eofc) {
507     nextc = EOF;
508     break;
509     }
510 greg 1.1 if (nextc == '{') {
511 greg 2.51 escan();
512 greg 1.1 while (nextc != '}')
513     if (nextc == EOF)
514 greg 2.51 esyntax("'}' expected");
515 greg 1.1 else
516 greg 2.51 escan();
517     escan();
518 greg 1.1 }
519     } while (isspace(nextc));
520 greg 1.12 return(lnext);
521 greg 1.1 }
522    
523    
524 greg 1.6 char *
525 schorsch 2.28 long2ascii( /* convert long to ascii */
526     long l
527     )
528 greg 1.6 {
529 greg 2.6 static char buf[16];
530 greg 2.37 char *cp;
531 greg 2.6 int neg = 0;
532 greg 1.6
533     if (l == 0)
534     return("0");
535     if (l < 0) {
536     l = -l;
537     neg++;
538     }
539     cp = buf + sizeof(buf);
540     *--cp = '\0';
541     while (l) {
542     *--cp = l % 10 + '0';
543     l /= 10;
544     }
545     if (neg)
546     *--cp = '-';
547     return(cp);
548     }
549    
550    
551 greg 2.18 void
552 greg 2.51 esyntax( /* report syntax error and quit */
553 schorsch 2.28 char *err
554     )
555 greg 1.1 {
556 greg 2.37 int i;
557 greg 1.1
558 greg 2.42 if ((infile != NULL) | (lineno != 0)) {
559 greg 1.6 if (infile != NULL) eputs(infile);
560     if (lineno != 0) {
561     eputs(infile != NULL ? ", line " : "line ");
562 greg 2.9 eputs(long2ascii((long)lineno));
563 greg 1.6 }
564 greg 2.7 eputs(":\n");
565 greg 1.1 }
566 greg 1.7 eputs(linbuf);
567     if (linbuf[strlen(linbuf)-1] != '\n')
568     eputs("\n");
569     for (i = 0; i < linepos-1; i++)
570     eputs(linbuf[i] == '\t' ? "\t" : " ");
571     eputs("^ ");
572 greg 1.1 eputs(err);
573     eputs("\n");
574     quit(1);
575     }
576    
577    
578 greg 2.18 void
579 schorsch 2.28 addekid( /* add a child to ep */
580 greg 2.37 EPNODE *ep,
581 greg 2.43 EPNODE *ek
582 schorsch 2.28 )
583 greg 1.1 {
584 greg 2.47 if (ep->nkids < 0) {
585     eputs("Cannot add kid to EPNODE array\n");
586     quit(1);
587     }
588 greg 2.43 ep->nkids++;
589 greg 1.1 if (ep->v.kid == NULL)
590 greg 2.43 ep->v.kid = ek;
591 greg 1.1 else {
592     for (ep = ep->v.kid; ep->sibling != NULL; ep = ep->sibling)
593     ;
594 greg 2.43 ep->sibling = ek;
595 greg 1.1 }
596 greg 2.44 ek->sibling = NULL; /* shouldn't be necessary */
597 greg 1.1 }
598    
599    
600     char *
601 schorsch 2.28 getname(void) /* scan an identifier */
602 greg 1.1 {
603 schorsch 2.23 static char str[RMAXWORD+1];
604 greg 2.37 int i, lnext;
605 greg 1.1
606 greg 1.12 lnext = nextc;
607 greg 2.51 for (i = 0; i < RMAXWORD && isid(lnext); i++, lnext = escan())
608 greg 1.12 str[i] = lnext;
609 greg 1.1 str[i] = '\0';
610 greg 1.15 while (isid(lnext)) /* skip rest of name */
611 greg 2.51 lnext = escan();
612 greg 1.1
613     return(str);
614     }
615    
616    
617     int
618 schorsch 2.28 getinum(void) /* scan a positive integer */
619 greg 1.1 {
620 greg 2.37 int n, lnext;
621 greg 1.1
622     n = 0;
623 greg 1.12 lnext = nextc;
624     while (isdigit(lnext)) {
625     n = n * 10 + lnext - '0';
626 greg 2.51 lnext = escan();
627 greg 1.1 }
628     return(n);
629     }
630    
631    
632     double
633 schorsch 2.28 getnum(void) /* scan a positive float */
634 greg 1.1 {
635 greg 2.37 int i, lnext;
636 schorsch 2.23 char str[RMAXWORD+1];
637 greg 1.1
638     i = 0;
639 greg 1.12 lnext = nextc;
640 schorsch 2.23 while (isdigit(lnext) && i < RMAXWORD) {
641 greg 1.12 str[i++] = lnext;
642 greg 2.51 lnext = escan();
643 greg 1.1 }
644 greg 2.42 if ((lnext == '.') & (i < RMAXWORD)) {
645 greg 2.6 str[i++] = lnext;
646 greg 2.51 lnext = escan();
647 gwlarson 2.17 if (i == 1 && !isdigit(lnext))
648 greg 2.51 esyntax("badly formed number");
649 schorsch 2.23 while (isdigit(lnext) && i < RMAXWORD) {
650 greg 1.12 str[i++] = lnext;
651 greg 2.51 lnext = escan();
652 greg 1.1 }
653     }
654 schorsch 2.26 if ((lnext == 'e') | (lnext == 'E') && i < RMAXWORD) {
655 greg 2.6 str[i++] = lnext;
656 greg 2.51 lnext = escan();
657 schorsch 2.26 if ((lnext == '-') | (lnext == '+') && i < RMAXWORD) {
658 greg 1.12 str[i++] = lnext;
659 greg 2.51 lnext = escan();
660 greg 1.1 }
661 gwlarson 2.17 if (!isdigit(lnext))
662 greg 2.51 esyntax("missing exponent");
663 schorsch 2.23 while (isdigit(lnext) && i < RMAXWORD) {
664 greg 1.12 str[i++] = lnext;
665 greg 2.51 lnext = escan();
666 greg 1.1 }
667     }
668     str[i] = '\0';
669    
670     return(atof(str));
671     }
672    
673    
674     EPNODE *
675 greg 2.34 getE1(void) /* E1 -> E1 ADDOP E2 */
676 greg 2.6 /* E2 */
677 greg 1.1 {
678 greg 2.37 EPNODE *ep1, *ep2;
679 greg 1.1
680     ep1 = getE2();
681 greg 2.42 while ((nextc == '+') | (nextc == '-')) {
682 greg 1.1 ep2 = newnode();
683     ep2->type = nextc;
684 greg 2.51 escan();
685 greg 1.1 addekid(ep2, ep1);
686     addekid(ep2, getE2());
687 greg 2.56 if (esupport&E_RCONST && ep1->sibling->type == NUM) {
688     if (ep1->type == NUM) {
689 greg 1.1 ep2 = rconst(ep2);
690 greg 2.56 } else if (ep2->type == '-') {
691     ep1->sibling->v.num *= -1;
692     ep2->type = '+'; /* associative&commutative */
693     }
694     }
695 greg 1.1 ep1 = ep2;
696     }
697     return(ep1);
698     }
699    
700    
701     EPNODE *
702 greg 2.34 getE2(void) /* E2 -> E2 MULOP E3 */
703 greg 2.6 /* E3 */
704 greg 1.1 {
705 greg 2.37 EPNODE *ep1, *ep2;
706 greg 1.1
707     ep1 = getE3();
708 greg 2.42 while ((nextc == '*') | (nextc == '/')) {
709 greg 1.1 ep2 = newnode();
710     ep2->type = nextc;
711 greg 2.51 escan();
712 greg 1.1 addekid(ep2, ep1);
713     addekid(ep2, getE3());
714 greg 2.34 if (esupport&E_RCONST) {
715 greg 2.52 EPNODE *ep3 = ep1->sibling;
716     if ((ep1->type == NUM) & (ep3->type == NUM)) {
717     ep2 = rconst(ep2);
718     } else if (ep3->type == NUM) {
719     if (ep2->type == '/') {
720     if (ep3->v.num == 0)
721     esyntax("divide by zero constant");
722     ep2->type = '*'; /* for speed */
723     ep3->v.num = 1./ep3->v.num;
724     } else if (ep3->v.num == 0) {
725     ep1->sibling = NULL; /* (E2 * 0) */
726     epfree(ep2,1);
727     ep2 = ep3;
728 greg 2.34 }
729 greg 2.52 } else if (ep1->type == NUM && ep1->v.num == 0) {
730     epfree(ep3,1); /* (0 * E3) or (0 / E3) */
731     ep1->sibling = NULL;
732     efree(ep2);
733     ep2 = ep1;
734     }
735 greg 2.34 }
736 greg 1.1 ep1 = ep2;
737     }
738     return(ep1);
739     }
740    
741    
742     EPNODE *
743 greg 2.34 getE3(void) /* E3 -> E4 ^ E3 */
744 greg 2.6 /* E4 */
745 greg 1.1 {
746 greg 2.37 EPNODE *ep1, *ep2;
747 greg 1.1
748 greg 2.34 ep1 = getE4();
749     if (nextc != '^')
750     return(ep1);
751 greg 1.1 ep2 = newnode();
752     ep2->type = nextc;
753 greg 2.51 escan();
754 greg 1.1 addekid(ep2, ep1);
755 greg 1.8 addekid(ep2, getE3());
756 greg 2.34 if (esupport&E_RCONST) {
757 greg 2.52 EPNODE *ep3 = ep1->sibling;
758     if ((ep1->type == NUM) & (ep3->type == NUM)) {
759     ep2 = rconst(ep2);
760     } else if (ep1->type == NUM && ep1->v.num == 0) {
761     epfree(ep3,1); /* (0 ^ E3) */
762     ep1->sibling = NULL;
763     efree(ep2);
764     ep2 = ep1;
765     } else if ((ep3->type == NUM && ep3->v.num == 0) |
766 greg 2.34 (ep1->type == NUM && ep1->v.num == 1)) {
767 greg 2.52 epfree(ep2,0); /* (E4 ^ 0) or (1 ^ E3) */
768     ep2->type = NUM;
769     ep2->v.num = 1;
770     } else if (ep3->type == NUM && ep3->v.num == 1) {
771     efree(ep3); /* (E4 ^ 1) */
772     ep1->sibling = NULL;
773     efree(ep2);
774     ep2 = ep1;
775     }
776 greg 2.34 }
777 greg 1.8 return(ep2);
778 greg 1.1 }
779    
780    
781     EPNODE *
782 greg 2.34 getE4(void) /* E4 -> ADDOP E5 */
783 greg 2.6 /* E5 */
784 greg 1.1 {
785 greg 2.37 EPNODE *ep1, *ep2;
786 greg 1.1
787     if (nextc == '-') {
788 greg 2.51 escan();
789 greg 1.3 ep2 = getE5();
790     if (ep2->type == NUM) {
791 greg 2.52 ep2->v.num = -ep2->v.num;
792     return(ep2);
793 greg 1.3 }
794 greg 1.16 if (ep2->type == UMINUS) { /* don't generate -(-E5) */
795 greg 2.33 ep1 = ep2->v.kid;
796 greg 2.41 efree(ep2);
797 greg 2.33 return(ep1);
798 greg 1.16 }
799 greg 1.1 ep1 = newnode();
800     ep1->type = UMINUS;
801 greg 1.3 addekid(ep1, ep2);
802 greg 1.1 return(ep1);
803     }
804     if (nextc == '+')
805 greg 2.51 escan();
806 greg 1.1 return(getE5());
807     }
808    
809    
810     EPNODE *
811 schorsch 2.28 getE5(void) /* E5 -> (E1) */
812 greg 2.6 /* VAR */
813     /* NUM */
814     /* $N */
815     /* FUNC(E1,..) */
816     /* ARG */
817 greg 1.1 {
818 schorsch 2.22 int i;
819     char *nam;
820 greg 2.37 EPNODE *ep1, *ep2;
821 greg 1.1
822 schorsch 2.22 if (nextc == '(') {
823 greg 2.52 escan();
824     ep1 = getE1();
825     if (nextc != ')')
826     esyntax("')' expected");
827     escan();
828     return(ep1);
829 schorsch 2.22 }
830     if (esupport&E_INCHAN && nextc == '$') {
831 greg 2.52 escan();
832     ep1 = newnode();
833     ep1->type = CHAN;
834     ep1->v.chan = getinum();
835     return(ep1);
836 schorsch 2.22 }
837     if (esupport&(E_VARIABLE|E_FUNCTION) &&
838 greg 2.42 (isalpha(nextc) | (nextc == CNTXMARK))) {
839 greg 2.52 nam = getname();
840     ep1 = NULL;
841     if ((esupport&(E_VARIABLE|E_FUNCTION)) == (E_VARIABLE|E_FUNCTION)
842 greg 2.51 && ecurfunc != NULL)
843 greg 2.52 for (i = 1, ep2 = ecurfunc->v.kid->sibling;
844     ep2 != NULL; i++, ep2 = ep2->sibling)
845     if (!strcmp(ep2->v.name, nam)) {
846 schorsch 2.22 ep1 = newnode();
847 greg 2.52 ep1->type = ARG;
848     ep1->v.chan = i;
849     break;
850     }
851     if (ep1 == NULL) {
852     ep1 = newnode();
853     ep1->type = VAR;
854     ep1->v.ln = varinsert(nam);
855     }
856     if (esupport&E_FUNCTION && nextc == '(') {
857     ep2 = newnode();
858     ep2->type = FUNC;
859     addekid(ep2, ep1);
860     ep1 = ep2;
861     do {
862     escan();
863     addekid(ep1, getE1());
864     } while (nextc == ',');
865     if (nextc != ')')
866     esyntax("')' expected");
867     escan();
868     } else if (!(esupport&E_VARIABLE))
869     esyntax("'(' expected");
870     if (esupport&E_RCONST && isconstvar(ep1))
871     ep1 = rconst(ep1);
872     return(ep1);
873 schorsch 2.22 }
874     if (isdecimal(nextc)) {
875 greg 2.52 ep1 = newnode();
876     ep1->type = NUM;
877     ep1->v.num = getnum();
878     return(ep1);
879 schorsch 2.22 }
880 greg 2.51 esyntax("unexpected character");
881 schorsch 2.22 return NULL; /* pro forma return */
882 greg 1.1 }
883    
884    
885     EPNODE *
886 schorsch 2.28 rconst( /* reduce a constant expression */
887 greg 2.37 EPNODE *epar
888 schorsch 2.28 )
889 greg 1.1 {
890 greg 2.37 EPNODE *ep;
891 greg 1.1
892     ep = newnode();
893     ep->type = NUM;
894     errno = 0;
895     ep->v.num = evalue(epar);
896 greg 2.42 if ((errno == EDOM) | (errno == ERANGE))
897 greg 2.51 esyntax("bad constant expression");
898 greg 2.43 epfree(epar,1);
899 greg 1.1
900     return(ep);
901 greg 1.9 }
902    
903    
904 greg 2.18 int
905 schorsch 2.28 isconstvar( /* is ep linked to a constant expression? */
906 greg 2.37 EPNODE *ep
907 schorsch 2.28 )
908 greg 1.9 {
909 greg 2.37 EPNODE *ep1;
910 greg 1.10
911 greg 2.18 if (esupport&E_FUNCTION && ep->type == FUNC) {
912 greg 1.11 if (!isconstfun(ep->v.kid))
913     return(0);
914 greg 1.9 for (ep1 = ep->v.kid->sibling; ep1 != NULL; ep1 = ep1->sibling)
915 greg 1.11 if (ep1->type != NUM && !isconstfun(ep1))
916 greg 1.9 return(0);
917     return(1);
918     }
919     if (ep->type != VAR)
920     return(0);
921     ep1 = ep->v.ln->def;
922     if (ep1 == NULL || ep1->type != ':')
923     return(0);
924 greg 2.18 if (esupport&E_FUNCTION && ep1->v.kid->type != SYM)
925 greg 1.9 return(0);
926     return(1);
927 greg 1.1 }
928 greg 1.11
929    
930 greg 2.18 int
931 schorsch 2.28 isconstfun( /* is ep linked to a constant function? */
932 greg 2.37 EPNODE *ep
933 schorsch 2.28 )
934 greg 1.11 {
935 greg 2.37 EPNODE *dp;
936 greg 2.51 ELIBR *lp;
937 greg 1.11
938     if (ep->type != VAR)
939     return(0);
940 schorsch 2.25 if ((dp = ep->v.ln->def) != NULL) {
941 greg 2.18 if (dp->v.kid->type == FUNC)
942     return(dp->type == ':');
943     else
944     return(0); /* don't identify masked library functions */
945 schorsch 2.25 }
946 greg 2.4 if ((lp = ep->v.ln->lib) != NULL)
947 greg 2.3 return(lp->atyp == ':');
948     return(0);
949 greg 1.11 }