ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/calexpr.c
Revision: 2.43
Committed: Fri Feb 23 03:47:57 2024 UTC (2 months, 3 weeks ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.42: +65 -37 lines
Log Message:
perf: Added array index optimization to calcomp routines

File Contents

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