ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/Development/ray/src/common/calexpr.c
Revision: 2.53
Committed: Sat Dec 6 02:32:21 2025 UTC (3 weeks, 5 days ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.52: +27 -5 lines
Log Message:
perf: Combine redundant constants in sums and products during optimization

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 2.53 static const char RCSid[] = "$Id: calexpr.c,v 2.52 2025/11/25 02:59:53 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.53 EPNODE *ep, *ep1, *ep2;
222     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.53 if ((epar->nkids <= 2) | !(esupport & E_RCONST))
239     return;
240     ep1 = NULL; /* combine numbers in sum/product */
241     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     else combined *= ep->v.num;
246     }
247     if (ep1 == NULL)
248     return;
249     ep1->v.num = combined; /* elide others */
250     while (ep1->sibling != NULL)
251     if (ep1->sibling->type == NUM) {
252     ep2 = ep1->sibling;
253     ep1->sibling = ep2->sibling;
254     efree(ep2);
255     if (--epar->nkids <= 2)
256     break;
257     } else
258     ep1 = ep1->sibling;
259 greg 2.44 }
260    
261    
262     void
263 greg 2.47 epoptimize( /* flatten operations, lists -> arrays */
264 greg 2.43 EPNODE *epar
265     )
266     {
267     EPNODE *ep;
268    
269 greg 2.45 if ((epar->type == '+') | (epar->type == '*'))
270 greg 2.47 epflatten(epar); /* flatten associative operations */
271 greg 2.44
272 greg 2.45 if (epar->nkids) /* do children if any */
273 greg 2.44 for (ep = epar->v.kid; ep != NULL; ep = ep->sibling)
274     epoptimize(ep);
275    
276     if (epar->nkids > 4) { /* make list into array if > 4 kids */
277 greg 2.43 int n = 1;
278     epar->v.kid = (EPNODE *)erealloc(epar->v.kid,
279     sizeof(EPNODE)*epar->nkids);
280     while (n < epar->nkids) {
281     ep = epar->v.kid[n-1].sibling;
282     epar->v.kid[n] = *ep;
283     efree(ep); /* not epfree()! */
284     epar->v.kid[n-1].sibling = epar->v.kid + n;
285     n++;
286     }
287 greg 2.44 epar->nkids = -n;
288 greg 2.43 }
289 greg 1.1 }
290    
291     /* the following used to be a switch */
292     static double
293 schorsch 2.28 enumber(
294     EPNODE *ep
295     )
296 greg 1.1 {
297     return(ep->v.num);
298     }
299    
300     static double
301 schorsch 2.28 euminus(
302     EPNODE *ep
303     )
304 greg 1.1 {
305 greg 2.37 EPNODE *ep1 = ep->v.kid;
306 greg 1.1
307     return(-evalue(ep1));
308     }
309    
310     static double
311 schorsch 2.28 echannel(
312     EPNODE *ep
313     )
314 greg 1.1 {
315     return(chanvalue(ep->v.chan));
316     }
317    
318     static double
319 schorsch 2.28 eadd(
320     EPNODE *ep
321     )
322 greg 1.1 {
323 greg 2.44 double sum = 0;
324 greg 2.37 EPNODE *ep1 = ep->v.kid;
325 greg 1.1
326 greg 2.44 do
327     sum += envalue(ep1);
328     while ((ep1 = ep1->sibling) != NULL);
329    
330     return(sum);
331 greg 1.1 }
332    
333     static double
334 schorsch 2.28 esubtr(
335     EPNODE *ep
336     )
337 greg 1.1 {
338 greg 2.37 EPNODE *ep1 = ep->v.kid;
339 greg 2.44 EPNODE *ep2 = ep1->sibling;
340 greg 1.1
341 greg 2.44 return(envalue(ep1) - envalue(ep2));
342 greg 1.1 }
343    
344     static double
345 schorsch 2.28 emult(
346     EPNODE *ep
347     )
348 greg 1.1 {
349 greg 2.44 double prod = 1;
350 greg 2.37 EPNODE *ep1 = ep->v.kid;
351 greg 1.1
352 greg 2.44 do
353     prod *= envalue(ep1);
354     while ((ep1 = ep1->sibling) != NULL);
355    
356     return(prod);
357 greg 1.1 }
358    
359     static double
360 schorsch 2.28 edivi(
361     EPNODE *ep
362     )
363 greg 1.1 {
364 greg 2.37 EPNODE *ep1 = ep->v.kid;
365 greg 2.48 double den = evalue(ep1->sibling);
366 greg 1.1
367 greg 2.48 if (den == 0.0) {
368 greg 1.1 wputs("Division by zero\n");
369     errno = ERANGE;
370     return(0.0);
371     }
372 greg 2.48 return(envalue(ep1) / den);
373 greg 1.1 }
374    
375     static double
376 schorsch 2.28 epow(
377     EPNODE *ep
378     )
379 greg 1.1 {
380 greg 2.37 EPNODE *ep1 = ep->v.kid;
381 greg 1.1 double d;
382 greg 2.6 int lasterrno;
383 greg 1.1
384     lasterrno = errno;
385     errno = 0;
386     d = pow(evalue(ep1), evalue(ep1->sibling));
387 greg 2.31 #ifdef isnan
388 greg 2.36 if (errno == 0) {
389 greg 2.31 if (isnan(d))
390     errno = EDOM;
391     else if (isinf(d))
392     errno = ERANGE;
393 greg 2.36 }
394 greg 1.1 #endif
395 greg 2.42 if ((errno == EDOM) | (errno == ERANGE)) {
396 greg 1.1 wputs("Illegal power\n");
397     return(0.0);
398     }
399     errno = lasterrno;
400     return(d);
401     }
402    
403     static double
404 schorsch 2.28 ebotch(
405     EPNODE *ep
406     )
407 greg 1.1 {
408     eputs("Bad expression!\n");
409     quit(1);
410 schorsch 2.22 return 0.0; /* pro forma return */
411 greg 1.1 }
412    
413    
414     EPNODE *
415 schorsch 2.28 ekid( /* return pointer to a node's nth kid */
416 greg 2.37 EPNODE *ep,
417     int n
418 schorsch 2.28 )
419 greg 1.1 {
420 greg 2.43 if (ep->nkids < 0) { /* allocated array? */
421     if (n >= -ep->nkids)
422     return(NULL);
423     return(ep->v.kid + n);
424     }
425     ep = ep->v.kid; /* else get from list */
426     while (n-- > 0)
427     if ((ep = ep->sibling) == NULL)
428     break;
429 greg 1.1 return(ep);
430     }
431    
432    
433 greg 2.18 void
434 schorsch 2.28 initfile( /* prepare input file */
435     FILE *fp,
436     char *fn,
437     int ln
438     )
439 greg 1.1 {
440 greg 2.6 static char inpbuf[MAXLINE];
441 greg 1.1
442     infp = fp;
443     linbuf = inpbuf;
444 greg 1.6 infile = fn;
445     lineno = ln;
446 greg 1.1 linepos = 0;
447     inpbuf[0] = '\0';
448 greg 2.51 escan();
449 greg 1.1 }
450    
451    
452 greg 2.18 void
453 schorsch 2.28 initstr( /* prepare input string */
454     char *s,
455     char *fn,
456     int ln
457     )
458 greg 1.1 {
459     infp = NULL;
460 greg 1.6 infile = fn;
461     lineno = ln;
462 greg 1.1 linbuf = s;
463     linepos = 0;
464 greg 2.51 escan();
465 greg 1.1 }
466    
467    
468 greg 2.18 void
469 schorsch 2.28 getscanpos( /* return current scan position */
470     char **fnp,
471     int *lnp,
472     char **spp,
473     FILE **fpp
474     )
475 greg 1.13 {
476     if (fnp != NULL) *fnp = infile;
477     if (lnp != NULL) *lnp = lineno;
478     if (spp != NULL) *spp = linbuf+linepos;
479     if (fpp != NULL) *fpp = infp;
480     }
481    
482    
483 greg 1.12 int
484 greg 2.51 escan(void) /* scan next character, return literal next */
485 greg 1.1 {
486 greg 2.37 int lnext = 0;
487 greg 1.12
488 greg 1.1 do {
489     if (linbuf[linepos] == '\0')
490     if (infp == NULL || fgets(linbuf, MAXLINE, infp) == NULL)
491     nextc = EOF;
492     else {
493     nextc = linbuf[0];
494 greg 1.6 lineno++;
495 greg 1.1 linepos = 1;
496     }
497     else
498     nextc = linbuf[linepos++];
499 greg 1.12 if (!lnext)
500     lnext = nextc;
501 greg 2.30 if (nextc == eofc) {
502     nextc = EOF;
503     break;
504     }
505 greg 1.1 if (nextc == '{') {
506 greg 2.51 escan();
507 greg 1.1 while (nextc != '}')
508     if (nextc == EOF)
509 greg 2.51 esyntax("'}' expected");
510 greg 1.1 else
511 greg 2.51 escan();
512     escan();
513 greg 1.1 }
514     } while (isspace(nextc));
515 greg 1.12 return(lnext);
516 greg 1.1 }
517    
518    
519 greg 1.6 char *
520 schorsch 2.28 long2ascii( /* convert long to ascii */
521     long l
522     )
523 greg 1.6 {
524 greg 2.6 static char buf[16];
525 greg 2.37 char *cp;
526 greg 2.6 int neg = 0;
527 greg 1.6
528     if (l == 0)
529     return("0");
530     if (l < 0) {
531     l = -l;
532     neg++;
533     }
534     cp = buf + sizeof(buf);
535     *--cp = '\0';
536     while (l) {
537     *--cp = l % 10 + '0';
538     l /= 10;
539     }
540     if (neg)
541     *--cp = '-';
542     return(cp);
543     }
544    
545    
546 greg 2.18 void
547 greg 2.51 esyntax( /* report syntax error and quit */
548 schorsch 2.28 char *err
549     )
550 greg 1.1 {
551 greg 2.37 int i;
552 greg 1.1
553 greg 2.42 if ((infile != NULL) | (lineno != 0)) {
554 greg 1.6 if (infile != NULL) eputs(infile);
555     if (lineno != 0) {
556     eputs(infile != NULL ? ", line " : "line ");
557 greg 2.9 eputs(long2ascii((long)lineno));
558 greg 1.6 }
559 greg 2.7 eputs(":\n");
560 greg 1.1 }
561 greg 1.7 eputs(linbuf);
562     if (linbuf[strlen(linbuf)-1] != '\n')
563     eputs("\n");
564     for (i = 0; i < linepos-1; i++)
565     eputs(linbuf[i] == '\t' ? "\t" : " ");
566     eputs("^ ");
567 greg 1.1 eputs(err);
568     eputs("\n");
569     quit(1);
570     }
571    
572    
573 greg 2.18 void
574 schorsch 2.28 addekid( /* add a child to ep */
575 greg 2.37 EPNODE *ep,
576 greg 2.43 EPNODE *ek
577 schorsch 2.28 )
578 greg 1.1 {
579 greg 2.47 if (ep->nkids < 0) {
580     eputs("Cannot add kid to EPNODE array\n");
581     quit(1);
582     }
583 greg 2.43 ep->nkids++;
584 greg 1.1 if (ep->v.kid == NULL)
585 greg 2.43 ep->v.kid = ek;
586 greg 1.1 else {
587     for (ep = ep->v.kid; ep->sibling != NULL; ep = ep->sibling)
588     ;
589 greg 2.43 ep->sibling = ek;
590 greg 1.1 }
591 greg 2.44 ek->sibling = NULL; /* shouldn't be necessary */
592 greg 1.1 }
593    
594    
595     char *
596 schorsch 2.28 getname(void) /* scan an identifier */
597 greg 1.1 {
598 schorsch 2.23 static char str[RMAXWORD+1];
599 greg 2.37 int i, lnext;
600 greg 1.1
601 greg 1.12 lnext = nextc;
602 greg 2.51 for (i = 0; i < RMAXWORD && isid(lnext); i++, lnext = escan())
603 greg 1.12 str[i] = lnext;
604 greg 1.1 str[i] = '\0';
605 greg 1.15 while (isid(lnext)) /* skip rest of name */
606 greg 2.51 lnext = escan();
607 greg 1.1
608     return(str);
609     }
610    
611    
612     int
613 schorsch 2.28 getinum(void) /* scan a positive integer */
614 greg 1.1 {
615 greg 2.37 int n, lnext;
616 greg 1.1
617     n = 0;
618 greg 1.12 lnext = nextc;
619     while (isdigit(lnext)) {
620     n = n * 10 + lnext - '0';
621 greg 2.51 lnext = escan();
622 greg 1.1 }
623     return(n);
624     }
625    
626    
627     double
628 schorsch 2.28 getnum(void) /* scan a positive float */
629 greg 1.1 {
630 greg 2.37 int i, lnext;
631 schorsch 2.23 char str[RMAXWORD+1];
632 greg 1.1
633     i = 0;
634 greg 1.12 lnext = nextc;
635 schorsch 2.23 while (isdigit(lnext) && i < RMAXWORD) {
636 greg 1.12 str[i++] = lnext;
637 greg 2.51 lnext = escan();
638 greg 1.1 }
639 greg 2.42 if ((lnext == '.') & (i < RMAXWORD)) {
640 greg 2.6 str[i++] = lnext;
641 greg 2.51 lnext = escan();
642 gwlarson 2.17 if (i == 1 && !isdigit(lnext))
643 greg 2.51 esyntax("badly formed number");
644 schorsch 2.23 while (isdigit(lnext) && i < RMAXWORD) {
645 greg 1.12 str[i++] = lnext;
646 greg 2.51 lnext = escan();
647 greg 1.1 }
648     }
649 schorsch 2.26 if ((lnext == 'e') | (lnext == 'E') && i < RMAXWORD) {
650 greg 2.6 str[i++] = lnext;
651 greg 2.51 lnext = escan();
652 schorsch 2.26 if ((lnext == '-') | (lnext == '+') && i < RMAXWORD) {
653 greg 1.12 str[i++] = lnext;
654 greg 2.51 lnext = escan();
655 greg 1.1 }
656 gwlarson 2.17 if (!isdigit(lnext))
657 greg 2.51 esyntax("missing exponent");
658 schorsch 2.23 while (isdigit(lnext) && i < RMAXWORD) {
659 greg 1.12 str[i++] = lnext;
660 greg 2.51 lnext = escan();
661 greg 1.1 }
662     }
663     str[i] = '\0';
664    
665     return(atof(str));
666     }
667    
668    
669     EPNODE *
670 greg 2.34 getE1(void) /* E1 -> E1 ADDOP E2 */
671 greg 2.6 /* E2 */
672 greg 1.1 {
673 greg 2.37 EPNODE *ep1, *ep2;
674 greg 1.1
675     ep1 = getE2();
676 greg 2.42 while ((nextc == '+') | (nextc == '-')) {
677 greg 1.1 ep2 = newnode();
678     ep2->type = nextc;
679 greg 2.51 escan();
680 greg 1.1 addekid(ep2, ep1);
681     addekid(ep2, getE2());
682 greg 2.18 if (esupport&E_RCONST &&
683 greg 2.42 (ep1->type == NUM) & (ep1->sibling->type == NUM))
684 greg 1.1 ep2 = rconst(ep2);
685     ep1 = ep2;
686     }
687     return(ep1);
688     }
689    
690    
691     EPNODE *
692 greg 2.34 getE2(void) /* E2 -> E2 MULOP E3 */
693 greg 2.6 /* E3 */
694 greg 1.1 {
695 greg 2.37 EPNODE *ep1, *ep2;
696 greg 1.1
697     ep1 = getE3();
698 greg 2.42 while ((nextc == '*') | (nextc == '/')) {
699 greg 1.1 ep2 = newnode();
700     ep2->type = nextc;
701 greg 2.51 escan();
702 greg 1.1 addekid(ep2, ep1);
703     addekid(ep2, getE3());
704 greg 2.34 if (esupport&E_RCONST) {
705 greg 2.52 EPNODE *ep3 = ep1->sibling;
706     if ((ep1->type == NUM) & (ep3->type == NUM)) {
707     ep2 = rconst(ep2);
708     } else if (ep3->type == NUM) {
709     if (ep2->type == '/') {
710     if (ep3->v.num == 0)
711     esyntax("divide by zero constant");
712     ep2->type = '*'; /* for speed */
713     ep3->v.num = 1./ep3->v.num;
714     } else if (ep3->v.num == 0) {
715     ep1->sibling = NULL; /* (E2 * 0) */
716     epfree(ep2,1);
717     ep2 = ep3;
718 greg 2.34 }
719 greg 2.52 } else if (ep1->type == NUM && ep1->v.num == 0) {
720     epfree(ep3,1); /* (0 * E3) or (0 / E3) */
721     ep1->sibling = NULL;
722     efree(ep2);
723     ep2 = ep1;
724     }
725 greg 2.34 }
726 greg 1.1 ep1 = ep2;
727     }
728     return(ep1);
729     }
730    
731    
732     EPNODE *
733 greg 2.34 getE3(void) /* E3 -> E4 ^ E3 */
734 greg 2.6 /* E4 */
735 greg 1.1 {
736 greg 2.37 EPNODE *ep1, *ep2;
737 greg 1.1
738 greg 2.34 ep1 = getE4();
739     if (nextc != '^')
740     return(ep1);
741 greg 1.1 ep2 = newnode();
742     ep2->type = nextc;
743 greg 2.51 escan();
744 greg 1.1 addekid(ep2, ep1);
745 greg 1.8 addekid(ep2, getE3());
746 greg 2.34 if (esupport&E_RCONST) {
747 greg 2.52 EPNODE *ep3 = ep1->sibling;
748     if ((ep1->type == NUM) & (ep3->type == NUM)) {
749     ep2 = rconst(ep2);
750     } else if (ep1->type == NUM && ep1->v.num == 0) {
751     epfree(ep3,1); /* (0 ^ E3) */
752     ep1->sibling = NULL;
753     efree(ep2);
754     ep2 = ep1;
755     } else if ((ep3->type == NUM && ep3->v.num == 0) |
756 greg 2.34 (ep1->type == NUM && ep1->v.num == 1)) {
757 greg 2.52 epfree(ep2,0); /* (E4 ^ 0) or (1 ^ E3) */
758     ep2->type = NUM;
759     ep2->v.num = 1;
760     } else if (ep3->type == NUM && ep3->v.num == 1) {
761     efree(ep3); /* (E4 ^ 1) */
762     ep1->sibling = NULL;
763     efree(ep2);
764     ep2 = ep1;
765     }
766 greg 2.34 }
767 greg 1.8 return(ep2);
768 greg 1.1 }
769    
770    
771     EPNODE *
772 greg 2.34 getE4(void) /* E4 -> ADDOP E5 */
773 greg 2.6 /* E5 */
774 greg 1.1 {
775 greg 2.37 EPNODE *ep1, *ep2;
776 greg 1.1
777     if (nextc == '-') {
778 greg 2.51 escan();
779 greg 1.3 ep2 = getE5();
780     if (ep2->type == NUM) {
781 greg 2.52 ep2->v.num = -ep2->v.num;
782     return(ep2);
783 greg 1.3 }
784 greg 1.16 if (ep2->type == UMINUS) { /* don't generate -(-E5) */
785 greg 2.33 ep1 = ep2->v.kid;
786 greg 2.41 efree(ep2);
787 greg 2.33 return(ep1);
788 greg 1.16 }
789 greg 1.1 ep1 = newnode();
790     ep1->type = UMINUS;
791 greg 1.3 addekid(ep1, ep2);
792 greg 1.1 return(ep1);
793     }
794     if (nextc == '+')
795 greg 2.51 escan();
796 greg 1.1 return(getE5());
797     }
798    
799    
800     EPNODE *
801 schorsch 2.28 getE5(void) /* E5 -> (E1) */
802 greg 2.6 /* VAR */
803     /* NUM */
804     /* $N */
805     /* FUNC(E1,..) */
806     /* ARG */
807 greg 1.1 {
808 schorsch 2.22 int i;
809     char *nam;
810 greg 2.37 EPNODE *ep1, *ep2;
811 greg 1.1
812 schorsch 2.22 if (nextc == '(') {
813 greg 2.52 escan();
814     ep1 = getE1();
815     if (nextc != ')')
816     esyntax("')' expected");
817     escan();
818     return(ep1);
819 schorsch 2.22 }
820     if (esupport&E_INCHAN && nextc == '$') {
821 greg 2.52 escan();
822     ep1 = newnode();
823     ep1->type = CHAN;
824     ep1->v.chan = getinum();
825     return(ep1);
826 schorsch 2.22 }
827     if (esupport&(E_VARIABLE|E_FUNCTION) &&
828 greg 2.42 (isalpha(nextc) | (nextc == CNTXMARK))) {
829 greg 2.52 nam = getname();
830     ep1 = NULL;
831     if ((esupport&(E_VARIABLE|E_FUNCTION)) == (E_VARIABLE|E_FUNCTION)
832 greg 2.51 && ecurfunc != NULL)
833 greg 2.52 for (i = 1, ep2 = ecurfunc->v.kid->sibling;
834     ep2 != NULL; i++, ep2 = ep2->sibling)
835     if (!strcmp(ep2->v.name, nam)) {
836 schorsch 2.22 ep1 = newnode();
837 greg 2.52 ep1->type = ARG;
838     ep1->v.chan = i;
839     break;
840     }
841     if (ep1 == NULL) {
842     ep1 = newnode();
843     ep1->type = VAR;
844     ep1->v.ln = varinsert(nam);
845     }
846     if (esupport&E_FUNCTION && nextc == '(') {
847     ep2 = newnode();
848     ep2->type = FUNC;
849     addekid(ep2, ep1);
850     ep1 = ep2;
851     do {
852     escan();
853     addekid(ep1, getE1());
854     } while (nextc == ',');
855     if (nextc != ')')
856     esyntax("')' expected");
857     escan();
858     } else if (!(esupport&E_VARIABLE))
859     esyntax("'(' expected");
860     if (esupport&E_RCONST && isconstvar(ep1))
861     ep1 = rconst(ep1);
862     return(ep1);
863 schorsch 2.22 }
864     if (isdecimal(nextc)) {
865 greg 2.52 ep1 = newnode();
866     ep1->type = NUM;
867     ep1->v.num = getnum();
868     return(ep1);
869 schorsch 2.22 }
870 greg 2.51 esyntax("unexpected character");
871 schorsch 2.22 return NULL; /* pro forma return */
872 greg 1.1 }
873    
874    
875     EPNODE *
876 schorsch 2.28 rconst( /* reduce a constant expression */
877 greg 2.37 EPNODE *epar
878 schorsch 2.28 )
879 greg 1.1 {
880 greg 2.37 EPNODE *ep;
881 greg 1.1
882     ep = newnode();
883     ep->type = NUM;
884     errno = 0;
885     ep->v.num = evalue(epar);
886 greg 2.42 if ((errno == EDOM) | (errno == ERANGE))
887 greg 2.51 esyntax("bad constant expression");
888 greg 2.43 epfree(epar,1);
889 greg 1.1
890     return(ep);
891 greg 1.9 }
892    
893    
894 greg 2.18 int
895 schorsch 2.28 isconstvar( /* is ep linked to a constant expression? */
896 greg 2.37 EPNODE *ep
897 schorsch 2.28 )
898 greg 1.9 {
899 greg 2.37 EPNODE *ep1;
900 greg 1.10
901 greg 2.18 if (esupport&E_FUNCTION && ep->type == FUNC) {
902 greg 1.11 if (!isconstfun(ep->v.kid))
903     return(0);
904 greg 1.9 for (ep1 = ep->v.kid->sibling; ep1 != NULL; ep1 = ep1->sibling)
905 greg 1.11 if (ep1->type != NUM && !isconstfun(ep1))
906 greg 1.9 return(0);
907     return(1);
908     }
909     if (ep->type != VAR)
910     return(0);
911     ep1 = ep->v.ln->def;
912     if (ep1 == NULL || ep1->type != ':')
913     return(0);
914 greg 2.18 if (esupport&E_FUNCTION && ep1->v.kid->type != SYM)
915 greg 1.9 return(0);
916     return(1);
917 greg 1.1 }
918 greg 1.11
919    
920 greg 2.18 int
921 schorsch 2.28 isconstfun( /* is ep linked to a constant function? */
922 greg 2.37 EPNODE *ep
923 schorsch 2.28 )
924 greg 1.11 {
925 greg 2.37 EPNODE *dp;
926 greg 2.51 ELIBR *lp;
927 greg 1.11
928     if (ep->type != VAR)
929     return(0);
930 schorsch 2.25 if ((dp = ep->v.ln->def) != NULL) {
931 greg 2.18 if (dp->v.kid->type == FUNC)
932     return(dp->type == ':');
933     else
934     return(0); /* don't identify masked library functions */
935 schorsch 2.25 }
936 greg 2.4 if ((lp = ep->v.ln->lib) != NULL)
937 greg 2.3 return(lp->atyp == ':');
938     return(0);
939 greg 1.11 }