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, 4 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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: calexpr.c,v 2.52 2025/11/25 02:59:53 greg Exp $";
3 #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 *
17 * 2/19/03 Eliminated conditional compiles in favor of esupport extern.
18 */
19
20 #include "copyright.h"
21
22 #include <ctype.h>
23 #include <errno.h>
24 #include <math.h>
25 #include <stdlib.h>
26
27 #include "rtmisc.h"
28 #include "rtio.h"
29 #include "rterror.h"
30 #include "calcomp.h"
31
32 #define MAXLINE 256 /* maximum line length */
33
34 #define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE))
35
36 #define isdecimal(c) (isdigit(c) | ((c) == '.'))
37
38 #define envalue(ep) ((ep)->type==NUM ? (ep)->v.num : evalue(ep))
39
40 static double euminus(EPNODE *), enumber(EPNODE *);
41 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
47 unsigned int esupport = /* what to support */
48 E_VARIABLE | E_FUNCTION ;
49
50 int eofc = 0; /* optional end-of-file character */
51 int nextc; /* lookahead character */
52
53 double (*eoper[])(EPNODE *) = { /* expression operations */
54 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 0,0,0,0,0,0,0,0,0,0,
72 ebotch,
73 0,0,
74 ebotch,
75 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 static char *infile; /* input file name */
83 static int lineno; /* input line number */
84 static int linepos; /* position in buffer */
85
86
87 EPNODE *
88 eparse( /* parse an expression string */
89 char *expr
90 )
91 {
92 EPNODE *ep;
93
94 initstr(expr, NULL, 0);
95 ecurfunc = NULL;
96 ep = getE1();
97 if (nextc != EOF)
98 esyntax("unexpected character");
99 return(ep);
100 }
101
102
103 double
104 eval( /* evaluate an expression string */
105 char *expr
106 )
107 {
108 int prev_support = esupport;
109 EPNODE *ep;
110 double rval;
111
112 esupport &= ~E_RCONST; /* don't bother reducing constant expr */
113 ep = eparse(expr);
114 esupport = prev_support; /* as you were */
115 rval = evalue(ep);
116 epfree(ep,1);
117 return(rval);
118 }
119
120
121 int
122 epcmp( /* compare two expressions for equivalence */
123 EPNODE *ep1,
124 EPNODE *ep2
125 )
126 {
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 return((d > 1.000000000001) | (d < 0.999999999999));
142
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 case CLKT:
152 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 void
172 epfree( /* free a parse tree */
173 EPNODE *epar,
174 int frep
175 )
176 {
177 EPNODE *ep;
178
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 case CLKT:
193 break;
194
195 default:
196 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 break;
207
208 }
209 if (frep)
210 efree(epar);
211 else
212 memset(epar, 0, sizeof(EPNODE));
213 }
214
215
216 static void
217 epflatten( /* flatten hierarchies for '+', '*' */
218 EPNODE *epar
219 )
220 {
221 EPNODE *ep, *ep1, *ep2;
222 double combined;
223
224 if (epar->nkids <= 0) /* can't handle array allocations */
225 return;
226
227 for (ep = epar->v.kid; ep != NULL; ep = ep->sibling)
228 while ((ep->type == epar->type) & (ep->nkids > 0)) {
229 ep1 = ep->v.kid;
230 while (ep1->sibling != NULL)
231 ep1 = ep1->sibling;
232 ep1->sibling = ep->sibling;
233 epar->nkids += ep->nkids - 1;
234 ep1 = ep->v.kid;
235 *ep = *ep1;
236 efree(ep1); /* not epfree()! */
237 }
238 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 }
260
261
262 void
263 epoptimize( /* flatten operations, lists -> arrays */
264 EPNODE *epar
265 )
266 {
267 EPNODE *ep;
268
269 if ((epar->type == '+') | (epar->type == '*'))
270 epflatten(epar); /* flatten associative operations */
271
272 if (epar->nkids) /* do children if any */
273 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 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 epar->nkids = -n;
288 }
289 }
290
291 /* the following used to be a switch */
292 static double
293 enumber(
294 EPNODE *ep
295 )
296 {
297 return(ep->v.num);
298 }
299
300 static double
301 euminus(
302 EPNODE *ep
303 )
304 {
305 EPNODE *ep1 = ep->v.kid;
306
307 return(-evalue(ep1));
308 }
309
310 static double
311 echannel(
312 EPNODE *ep
313 )
314 {
315 return(chanvalue(ep->v.chan));
316 }
317
318 static double
319 eadd(
320 EPNODE *ep
321 )
322 {
323 double sum = 0;
324 EPNODE *ep1 = ep->v.kid;
325
326 do
327 sum += envalue(ep1);
328 while ((ep1 = ep1->sibling) != NULL);
329
330 return(sum);
331 }
332
333 static double
334 esubtr(
335 EPNODE *ep
336 )
337 {
338 EPNODE *ep1 = ep->v.kid;
339 EPNODE *ep2 = ep1->sibling;
340
341 return(envalue(ep1) - envalue(ep2));
342 }
343
344 static double
345 emult(
346 EPNODE *ep
347 )
348 {
349 double prod = 1;
350 EPNODE *ep1 = ep->v.kid;
351
352 do
353 prod *= envalue(ep1);
354 while ((ep1 = ep1->sibling) != NULL);
355
356 return(prod);
357 }
358
359 static double
360 edivi(
361 EPNODE *ep
362 )
363 {
364 EPNODE *ep1 = ep->v.kid;
365 double den = evalue(ep1->sibling);
366
367 if (den == 0.0) {
368 wputs("Division by zero\n");
369 errno = ERANGE;
370 return(0.0);
371 }
372 return(envalue(ep1) / den);
373 }
374
375 static double
376 epow(
377 EPNODE *ep
378 )
379 {
380 EPNODE *ep1 = ep->v.kid;
381 double d;
382 int lasterrno;
383
384 lasterrno = errno;
385 errno = 0;
386 d = pow(evalue(ep1), evalue(ep1->sibling));
387 #ifdef isnan
388 if (errno == 0) {
389 if (isnan(d))
390 errno = EDOM;
391 else if (isinf(d))
392 errno = ERANGE;
393 }
394 #endif
395 if ((errno == EDOM) | (errno == ERANGE)) {
396 wputs("Illegal power\n");
397 return(0.0);
398 }
399 errno = lasterrno;
400 return(d);
401 }
402
403 static double
404 ebotch(
405 EPNODE *ep
406 )
407 {
408 eputs("Bad expression!\n");
409 quit(1);
410 return 0.0; /* pro forma return */
411 }
412
413
414 EPNODE *
415 ekid( /* return pointer to a node's nth kid */
416 EPNODE *ep,
417 int n
418 )
419 {
420 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 return(ep);
430 }
431
432
433 void
434 initfile( /* prepare input file */
435 FILE *fp,
436 char *fn,
437 int ln
438 )
439 {
440 static char inpbuf[MAXLINE];
441
442 infp = fp;
443 linbuf = inpbuf;
444 infile = fn;
445 lineno = ln;
446 linepos = 0;
447 inpbuf[0] = '\0';
448 escan();
449 }
450
451
452 void
453 initstr( /* prepare input string */
454 char *s,
455 char *fn,
456 int ln
457 )
458 {
459 infp = NULL;
460 infile = fn;
461 lineno = ln;
462 linbuf = s;
463 linepos = 0;
464 escan();
465 }
466
467
468 void
469 getscanpos( /* return current scan position */
470 char **fnp,
471 int *lnp,
472 char **spp,
473 FILE **fpp
474 )
475 {
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 int
484 escan(void) /* scan next character, return literal next */
485 {
486 int lnext = 0;
487
488 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 lineno++;
495 linepos = 1;
496 }
497 else
498 nextc = linbuf[linepos++];
499 if (!lnext)
500 lnext = nextc;
501 if (nextc == eofc) {
502 nextc = EOF;
503 break;
504 }
505 if (nextc == '{') {
506 escan();
507 while (nextc != '}')
508 if (nextc == EOF)
509 esyntax("'}' expected");
510 else
511 escan();
512 escan();
513 }
514 } while (isspace(nextc));
515 return(lnext);
516 }
517
518
519 char *
520 long2ascii( /* convert long to ascii */
521 long l
522 )
523 {
524 static char buf[16];
525 char *cp;
526 int neg = 0;
527
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 void
547 esyntax( /* report syntax error and quit */
548 char *err
549 )
550 {
551 int i;
552
553 if ((infile != NULL) | (lineno != 0)) {
554 if (infile != NULL) eputs(infile);
555 if (lineno != 0) {
556 eputs(infile != NULL ? ", line " : "line ");
557 eputs(long2ascii((long)lineno));
558 }
559 eputs(":\n");
560 }
561 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 eputs(err);
568 eputs("\n");
569 quit(1);
570 }
571
572
573 void
574 addekid( /* add a child to ep */
575 EPNODE *ep,
576 EPNODE *ek
577 )
578 {
579 if (ep->nkids < 0) {
580 eputs("Cannot add kid to EPNODE array\n");
581 quit(1);
582 }
583 ep->nkids++;
584 if (ep->v.kid == NULL)
585 ep->v.kid = ek;
586 else {
587 for (ep = ep->v.kid; ep->sibling != NULL; ep = ep->sibling)
588 ;
589 ep->sibling = ek;
590 }
591 ek->sibling = NULL; /* shouldn't be necessary */
592 }
593
594
595 char *
596 getname(void) /* scan an identifier */
597 {
598 static char str[RMAXWORD+1];
599 int i, lnext;
600
601 lnext = nextc;
602 for (i = 0; i < RMAXWORD && isid(lnext); i++, lnext = escan())
603 str[i] = lnext;
604 str[i] = '\0';
605 while (isid(lnext)) /* skip rest of name */
606 lnext = escan();
607
608 return(str);
609 }
610
611
612 int
613 getinum(void) /* scan a positive integer */
614 {
615 int n, lnext;
616
617 n = 0;
618 lnext = nextc;
619 while (isdigit(lnext)) {
620 n = n * 10 + lnext - '0';
621 lnext = escan();
622 }
623 return(n);
624 }
625
626
627 double
628 getnum(void) /* scan a positive float */
629 {
630 int i, lnext;
631 char str[RMAXWORD+1];
632
633 i = 0;
634 lnext = nextc;
635 while (isdigit(lnext) && i < RMAXWORD) {
636 str[i++] = lnext;
637 lnext = escan();
638 }
639 if ((lnext == '.') & (i < RMAXWORD)) {
640 str[i++] = lnext;
641 lnext = escan();
642 if (i == 1 && !isdigit(lnext))
643 esyntax("badly formed number");
644 while (isdigit(lnext) && i < RMAXWORD) {
645 str[i++] = lnext;
646 lnext = escan();
647 }
648 }
649 if ((lnext == 'e') | (lnext == 'E') && i < RMAXWORD) {
650 str[i++] = lnext;
651 lnext = escan();
652 if ((lnext == '-') | (lnext == '+') && i < RMAXWORD) {
653 str[i++] = lnext;
654 lnext = escan();
655 }
656 if (!isdigit(lnext))
657 esyntax("missing exponent");
658 while (isdigit(lnext) && i < RMAXWORD) {
659 str[i++] = lnext;
660 lnext = escan();
661 }
662 }
663 str[i] = '\0';
664
665 return(atof(str));
666 }
667
668
669 EPNODE *
670 getE1(void) /* E1 -> E1 ADDOP E2 */
671 /* E2 */
672 {
673 EPNODE *ep1, *ep2;
674
675 ep1 = getE2();
676 while ((nextc == '+') | (nextc == '-')) {
677 ep2 = newnode();
678 ep2->type = nextc;
679 escan();
680 addekid(ep2, ep1);
681 addekid(ep2, getE2());
682 if (esupport&E_RCONST &&
683 (ep1->type == NUM) & (ep1->sibling->type == NUM))
684 ep2 = rconst(ep2);
685 ep1 = ep2;
686 }
687 return(ep1);
688 }
689
690
691 EPNODE *
692 getE2(void) /* E2 -> E2 MULOP E3 */
693 /* E3 */
694 {
695 EPNODE *ep1, *ep2;
696
697 ep1 = getE3();
698 while ((nextc == '*') | (nextc == '/')) {
699 ep2 = newnode();
700 ep2->type = nextc;
701 escan();
702 addekid(ep2, ep1);
703 addekid(ep2, getE3());
704 if (esupport&E_RCONST) {
705 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 }
719 } 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 }
726 ep1 = ep2;
727 }
728 return(ep1);
729 }
730
731
732 EPNODE *
733 getE3(void) /* E3 -> E4 ^ E3 */
734 /* E4 */
735 {
736 EPNODE *ep1, *ep2;
737
738 ep1 = getE4();
739 if (nextc != '^')
740 return(ep1);
741 ep2 = newnode();
742 ep2->type = nextc;
743 escan();
744 addekid(ep2, ep1);
745 addekid(ep2, getE3());
746 if (esupport&E_RCONST) {
747 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 (ep1->type == NUM && ep1->v.num == 1)) {
757 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 }
767 return(ep2);
768 }
769
770
771 EPNODE *
772 getE4(void) /* E4 -> ADDOP E5 */
773 /* E5 */
774 {
775 EPNODE *ep1, *ep2;
776
777 if (nextc == '-') {
778 escan();
779 ep2 = getE5();
780 if (ep2->type == NUM) {
781 ep2->v.num = -ep2->v.num;
782 return(ep2);
783 }
784 if (ep2->type == UMINUS) { /* don't generate -(-E5) */
785 ep1 = ep2->v.kid;
786 efree(ep2);
787 return(ep1);
788 }
789 ep1 = newnode();
790 ep1->type = UMINUS;
791 addekid(ep1, ep2);
792 return(ep1);
793 }
794 if (nextc == '+')
795 escan();
796 return(getE5());
797 }
798
799
800 EPNODE *
801 getE5(void) /* E5 -> (E1) */
802 /* VAR */
803 /* NUM */
804 /* $N */
805 /* FUNC(E1,..) */
806 /* ARG */
807 {
808 int i;
809 char *nam;
810 EPNODE *ep1, *ep2;
811
812 if (nextc == '(') {
813 escan();
814 ep1 = getE1();
815 if (nextc != ')')
816 esyntax("')' expected");
817 escan();
818 return(ep1);
819 }
820 if (esupport&E_INCHAN && nextc == '$') {
821 escan();
822 ep1 = newnode();
823 ep1->type = CHAN;
824 ep1->v.chan = getinum();
825 return(ep1);
826 }
827 if (esupport&(E_VARIABLE|E_FUNCTION) &&
828 (isalpha(nextc) | (nextc == CNTXMARK))) {
829 nam = getname();
830 ep1 = NULL;
831 if ((esupport&(E_VARIABLE|E_FUNCTION)) == (E_VARIABLE|E_FUNCTION)
832 && ecurfunc != NULL)
833 for (i = 1, ep2 = ecurfunc->v.kid->sibling;
834 ep2 != NULL; i++, ep2 = ep2->sibling)
835 if (!strcmp(ep2->v.name, nam)) {
836 ep1 = newnode();
837 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 }
864 if (isdecimal(nextc)) {
865 ep1 = newnode();
866 ep1->type = NUM;
867 ep1->v.num = getnum();
868 return(ep1);
869 }
870 esyntax("unexpected character");
871 return NULL; /* pro forma return */
872 }
873
874
875 EPNODE *
876 rconst( /* reduce a constant expression */
877 EPNODE *epar
878 )
879 {
880 EPNODE *ep;
881
882 ep = newnode();
883 ep->type = NUM;
884 errno = 0;
885 ep->v.num = evalue(epar);
886 if ((errno == EDOM) | (errno == ERANGE))
887 esyntax("bad constant expression");
888 epfree(epar,1);
889
890 return(ep);
891 }
892
893
894 int
895 isconstvar( /* is ep linked to a constant expression? */
896 EPNODE *ep
897 )
898 {
899 EPNODE *ep1;
900
901 if (esupport&E_FUNCTION && ep->type == FUNC) {
902 if (!isconstfun(ep->v.kid))
903 return(0);
904 for (ep1 = ep->v.kid->sibling; ep1 != NULL; ep1 = ep1->sibling)
905 if (ep1->type != NUM && !isconstfun(ep1))
906 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 if (esupport&E_FUNCTION && ep1->v.kid->type != SYM)
915 return(0);
916 return(1);
917 }
918
919
920 int
921 isconstfun( /* is ep linked to a constant function? */
922 EPNODE *ep
923 )
924 {
925 EPNODE *dp;
926 ELIBR *lp;
927
928 if (ep->type != VAR)
929 return(0);
930 if ((dp = ep->v.ln->def) != NULL) {
931 if (dp->v.kid->type == FUNC)
932 return(dp->type == ':');
933 else
934 return(0); /* don't identify masked library functions */
935 }
936 if ((lp = ep->v.ln->lib) != NULL)
937 return(lp->atyp == ':');
938 return(0);
939 }