ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/Development/ray/src/common/calexpr.c
(Generate patch)

Comparing ray/src/common/calexpr.c (file contents):
Revision 2.44 by greg, Sat Feb 24 19:00:23 2024 UTC vs.
Revision 2.55 by greg, Sat Dec 6 04:07:05 2025 UTC

# Line 37 | Line 37 | static const char      RCSid[] = "$Id$";
37  
38   #define  envalue(ep)    ((ep)->type==NUM ? (ep)->v.num : evalue(ep))
39  
40 < static double  euminus(EPNODE *), eargument(EPNODE *), enumber(EPNODE *);
40 > static double  euminus(EPNODE *), enumber(EPNODE *);
41   static double  echannel(EPNODE *);
42   static double  eadd(EPNODE *), esubtr(EPNODE *),
43                 emult(EPNODE *), edivi(EPNODE *),
# Line 92 | Line 92 | eparse(                        /* parse an expression string */
92      EPNODE  *ep;
93  
94      initstr(expr, NULL, 0);
95 <    curfunc = NULL;
95 >    ecurfunc = NULL;
96      ep = getE1();
97      if (nextc != EOF)
98 <        syntax("unexpected character");
98 >        esyntax("unexpected character");
99      return(ep);
100   }
101  
# Line 208 | Line 208 | epfree(                        /* free a parse tree */
208      }
209      if (frep)
210          efree(epar);
211 +    else
212 +        memset(epar, 0, sizeof(EPNODE));
213   }
214  
215  
216 < void
216 > static void
217   epflatten(                      /* flatten hierarchies for '+', '*' */
218          EPNODE *epar
219   )
220   {
221 <    EPNODE      *ep;
221 >    EPNODE      *ep, *ep1;
222 >    double      combined;
223  
224 <    if (epar->nkids < 0)        /* don't really handle this properly */
225 <        epar->nkids *= -1;
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) {
229 <            EPNODE      *ep1 = ep->v.kid;
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 += nekids(ep) - 1;
233 >            epar->nkids += ep->nkids - 1;
234              ep1 = ep->v.kid;
235              *ep = *ep1;
236              efree(ep1);         /* not epfree()! */
237          }
238 +    if (!(esupport & E_RCONST))
239 +        return;
240 +    ep1 = NULL;                 /* combine constants 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 /* epar->type=='*' */ combined *= ep->v.num;
246 +        }
247 +    if (ep1 == NULL)
248 +        return;
249 +    ep1->v.num = combined;      /* assumes commutative property, also */
250 +    while (ep1->sibling != NULL)
251 +        if (ep1->sibling->type == NUM) {
252 +            ep = ep1->sibling;
253 +            ep1->sibling = ep->sibling;
254 +            epar->nkids--;
255 +            efree(ep);          /* drop subsumed constant */
256 +        } else
257 +            ep1 = ep1->sibling;
258 +
259 +    if (epar->nkids == 1) {     /* late constant expression? */
260 +        ep = epar->v.kid;
261 +        *epar = *ep;
262 +        efree(ep);
263 +    }
264   }
265  
266  
267   void
268 < epoptimize(                     /* flatten operations and lists -> arrays */
268 > epoptimize(                     /* flatten operations, lists -> arrays */
269          EPNODE  *epar
270   )
271   {
272      EPNODE      *ep;
273  
274 <   if ((epar->type == '+') | (epar->type == '*'))
275 <        epflatten(epar);        /* commutative & associative */
274 >    if ((epar->type == '+') | (epar->type == '*'))
275 >        epflatten(epar);        /* flatten associative operations */
276  
277 <   if (epar->nkids)             /* do children if any */
277 >    if (epar->nkids)            /* do children if any */
278          for (ep = epar->v.kid; ep != NULL; ep = ep->sibling)
279              epoptimize(ep);
280  
# Line 266 | Line 295 | epoptimize(                    /* flatten operations and lists -> array
295  
296                                  /* the following used to be a switch */
297   static double
269 eargument(
270    EPNODE      *ep
271 )
272 {
273    return(argument(ep->v.chan));
274 }
275
276 static double
298   enumber(
299      EPNODE      *ep
300   )
# Line 346 | Line 367 | edivi(
367   )
368   {
369      EPNODE  *ep1 = ep->v.kid;
370 <    EPNODE  *ep2 = ep1->sibling;
350 <    double  d;
370 >    double  den = evalue(ep1->sibling);
371  
372 <    d = envalue(ep2);
353 <    if (d == 0.0) {
372 >    if (den == 0.0) {
373          wputs("Division by zero\n");
374          errno = ERANGE;
375          return(0.0);
376      }
377 <    return(envalue(ep1) / d);
377 >    return(envalue(ep1) / den);
378   }
379  
380   static double
# Line 431 | Line 450 | initfile(              /* prepare input file */
450      lineno = ln;
451      linepos = 0;
452      inpbuf[0] = '\0';
453 <    scan();
453 >    escan();
454   }
455  
456  
# Line 447 | Line 466 | initstr(               /* prepare input string */
466      lineno = ln;
467      linbuf = s;
468      linepos = 0;
469 <    scan();
469 >    escan();
470   }
471  
472  
# Line 467 | Line 486 | getscanpos(    /* return current scan position */
486  
487  
488   int
489 < scan(void)              /* scan next character, return literal next */
489 > escan(void)             /* scan next character, return literal next */
490   {
491      int  lnext = 0;
492  
# Line 489 | Line 508 | scan(void)             /* scan next character, return literal nex
508                  break;
509          }
510          if (nextc == '{') {
511 <            scan();
511 >            escan();
512              while (nextc != '}')
513                  if (nextc == EOF)
514 <                    syntax("'}' expected");
514 >                    esyntax("'}' expected");
515                  else
516 <                    scan();
517 <            scan();
516 >                    escan();
517 >            escan();
518          }
519      } while (isspace(nextc));
520      return(lnext);
# Line 530 | Line 549 | long2ascii(                          /* convert long to ascii */
549  
550  
551   void
552 < syntax(                 /* report syntax error and quit */
552 > esyntax(                        /* report syntax error and quit */
553      char  *err
554   )
555   {
# Line 562 | Line 581 | addekid(                       /* add a child to ep */
581      EPNODE      *ek
582   )
583   {
584 <    if (ep->nkids < 0)          /* we don't really handle this properly */
585 <        ep->nkids *= -1;
584 >    if (ep->nkids < 0) {
585 >        eputs("Cannot add kid to EPNODE array\n");
586 >        quit(1);
587 >    }
588      ep->nkids++;
589      if (ep->v.kid == NULL)
590          ep->v.kid = ek;
# Line 583 | Line 604 | getname(void)                  /* scan an identifier */
604      int  i, lnext;
605  
606      lnext = nextc;
607 <    for (i = 0; i < RMAXWORD && isid(lnext); i++, lnext = scan())
607 >    for (i = 0; i < RMAXWORD && isid(lnext); i++, lnext = escan())
608          str[i] = lnext;
609      str[i] = '\0';
610      while (isid(lnext))         /* skip rest of name */
611 <        lnext = scan();
611 >        lnext = escan();
612  
613      return(str);
614   }
# Line 602 | Line 623 | getinum(void)                  /* scan a positive integer */
623      lnext = nextc;
624      while (isdigit(lnext)) {
625          n = n * 10 + lnext - '0';
626 <        lnext = scan();
626 >        lnext = escan();
627      }
628      return(n);
629   }
# Line 618 | Line 639 | getnum(void)                   /* scan a positive float */
639      lnext = nextc;
640      while (isdigit(lnext) && i < RMAXWORD) {
641          str[i++] = lnext;
642 <        lnext = scan();
642 >        lnext = escan();
643      }
644      if ((lnext == '.') & (i < RMAXWORD)) {
645          str[i++] = lnext;
646 <        lnext = scan();
646 >        lnext = escan();
647          if (i == 1 && !isdigit(lnext))
648 <            syntax("badly formed number");
648 >            esyntax("badly formed number");
649          while (isdigit(lnext) && i < RMAXWORD) {
650              str[i++] = lnext;
651 <            lnext = scan();
651 >            lnext = escan();
652          }
653      }
654      if ((lnext == 'e') | (lnext == 'E') && i < RMAXWORD) {
655          str[i++] = lnext;
656 <        lnext = scan();
656 >        lnext = escan();
657          if ((lnext == '-') | (lnext == '+') && i < RMAXWORD) {
658              str[i++] = lnext;
659 <            lnext = scan();
659 >            lnext = escan();
660          }
661          if (!isdigit(lnext))
662 <            syntax("missing exponent");
662 >            esyntax("missing exponent");
663          while (isdigit(lnext) && i < RMAXWORD) {
664              str[i++] = lnext;
665 <            lnext = scan();
665 >            lnext = escan();
666          }
667      }
668      str[i] = '\0';
# Line 660 | Line 681 | getE1(void)                    /* E1 -> E1 ADDOP E2 */
681      while ((nextc == '+') | (nextc == '-')) {
682          ep2 = newnode();
683          ep2->type = nextc;
684 <        scan();
684 >        escan();
685          addekid(ep2, ep1);
686          addekid(ep2, getE2());
687          if (esupport&E_RCONST &&
# Line 682 | Line 703 | getE2(void)                    /* E2 -> E2 MULOP E3 */
703      while ((nextc == '*') | (nextc == '/')) {
704          ep2 = newnode();
705          ep2->type = nextc;
706 <        scan();
706 >        escan();
707          addekid(ep2, ep1);
708          addekid(ep2, getE3());
709          if (esupport&E_RCONST) {
710 <                EPNODE  *ep3 = ep1->sibling;
711 <                if ((ep1->type == NUM) & (ep3->type == NUM)) {
712 <                        ep2 = rconst(ep2);
713 <                } else if (ep3->type == NUM) {
714 <                        if (ep2->type == '/') {
715 <                                if (ep3->v.num == 0)
716 <                                        syntax("divide by zero constant");
717 <                                ep2->type = '*';        /* for speed */
718 <                                ep3->v.num = 1./ep3->v.num;
719 <                        } else if (ep3->v.num == 0) {
720 <                                ep1->sibling = NULL;    /* (E2 * 0) */
721 <                                epfree(ep2,1);
722 <                                ep2 = ep3;
702 <                        }
703 <                } else if (ep1->type == NUM && ep1->v.num == 0) {
704 <                        epfree(ep3,1);          /* (0 * E3) or (0 / E3) */
705 <                        ep1->sibling = NULL;
706 <                        efree(ep2);
707 <                        ep2 = ep1;
710 >            EPNODE      *ep3 = ep1->sibling;
711 >            if ((ep1->type == NUM) & (ep3->type == NUM)) {
712 >                ep2 = rconst(ep2);
713 >            } else if (ep3->type == NUM) {
714 >                if (ep2->type == '/') {
715 >                    if (ep3->v.num == 0)
716 >                        esyntax("divide by zero constant");
717 >                    ep2->type = '*';            /* for speed */
718 >                    ep3->v.num = 1./ep3->v.num;
719 >                } else if (ep3->v.num == 0) {
720 >                    ep1->sibling = NULL;        /* (E2 * 0) */
721 >                    epfree(ep2,1);
722 >                    ep2 = ep3;
723                  }
724 +            } else if (ep1->type == NUM && ep1->v.num == 0) {
725 +                epfree(ep3,1);                  /* (0 * E3) or (0 / E3) */
726 +                ep1->sibling = NULL;
727 +                efree(ep2);
728 +                ep2 = ep1;
729 +            }
730          }
731          ep1 = ep2;
732      }
# Line 724 | Line 745 | getE3(void)                    /* E3 -> E4 ^ E3 */
745                  return(ep1);
746          ep2 = newnode();
747          ep2->type = nextc;
748 <        scan();
748 >        escan();
749          addekid(ep2, ep1);
750          addekid(ep2, getE3());
751          if (esupport&E_RCONST) {
752 <                EPNODE  *ep3 = ep1->sibling;
753 <                if ((ep1->type == NUM) & (ep3->type == NUM)) {
754 <                        ep2 = rconst(ep2);
755 <                } else if (ep1->type == NUM && ep1->v.num == 0) {
756 <                        epfree(ep3,1);          /* (0 ^ E3) */
757 <                        ep1->sibling = NULL;
758 <                        efree(ep2);
759 <                        ep2 = ep1;
760 <                } else if ((ep3->type == NUM && ep3->v.num == 0) |
752 >            EPNODE      *ep3 = ep1->sibling;
753 >            if ((ep1->type == NUM) & (ep3->type == NUM)) {
754 >                ep2 = rconst(ep2);
755 >            } else if (ep1->type == NUM && ep1->v.num == 0) {
756 >                epfree(ep3,1);          /* (0 ^ E3) */
757 >                ep1->sibling = NULL;
758 >                efree(ep2);
759 >                ep2 = ep1;
760 >            } else if ((ep3->type == NUM && ep3->v.num == 0) |
761                                  (ep1->type == NUM && ep1->v.num == 1)) {
762 <                        epfree(ep2,1);          /* (E4 ^ 0) or (1 ^ E3) */
763 <                        ep2 = newnode();
764 <                        ep2->type = NUM;
765 <                        ep2->v.num = 1;
766 <                } else if (ep3->type == NUM && ep3->v.num == 1) {
767 <                        efree(ep3);     /* (E4 ^ 1) */
768 <                        ep1->sibling = NULL;
769 <                        efree(ep2);
770 <                        ep2 = ep1;
750 <                }
762 >                epfree(ep2,0);          /* (E4 ^ 0) or (1 ^ E3) */
763 >                ep2->type = NUM;
764 >                ep2->v.num = 1;
765 >            } else if (ep3->type == NUM && ep3->v.num == 1) {
766 >                efree(ep3);             /* (E4 ^ 1) */
767 >                ep1->sibling = NULL;
768 >                efree(ep2);
769 >                ep2 = ep1;
770 >            }
771          }
772          return(ep2);
773   }
# Line 760 | Line 780 | getE4(void)                    /* E4 -> ADDOP E5 */
780      EPNODE  *ep1, *ep2;
781  
782      if (nextc == '-') {
783 <        scan();
783 >        escan();
784          ep2 = getE5();
785          if (ep2->type == NUM) {
786 <                ep2->v.num = -ep2->v.num;
787 <                return(ep2);
786 >            ep2->v.num = -ep2->v.num;
787 >            return(ep2);
788          }
789          if (ep2->type == UMINUS) {      /* don't generate -(-E5) */
790              ep1 = ep2->v.kid;
# Line 777 | Line 797 | getE4(void)                    /* E4 -> ADDOP E5 */
797          return(ep1);
798      }
799      if (nextc == '+')
800 <        scan();
800 >        escan();
801      return(getE5());
802   }
803  
# Line 795 | Line 815 | getE5(void)                    /* E5 -> (E1) */
815          EPNODE  *ep1, *ep2;
816  
817          if (nextc == '(') {
818 <                scan();
819 <                ep1 = getE1();
820 <                if (nextc != ')')
821 <                        syntax("')' expected");
822 <                scan();
823 <                return(ep1);
818 >            escan();
819 >            ep1 = getE1();
820 >            if (nextc != ')')
821 >                esyntax("')' expected");
822 >            escan();
823 >            return(ep1);
824          }
825          if (esupport&E_INCHAN && nextc == '$') {
826 <                scan();
827 <                ep1 = newnode();
828 <                ep1->type = CHAN;
829 <                ep1->v.chan = getinum();
830 <                return(ep1);
826 >            escan();
827 >            ep1 = newnode();
828 >            ep1->type = CHAN;
829 >            ep1->v.chan = getinum();
830 >            return(ep1);
831          }
832          if (esupport&(E_VARIABLE|E_FUNCTION) &&
833                          (isalpha(nextc) | (nextc == CNTXMARK))) {
834 <                nam = getname();
835 <                ep1 = NULL;
836 <                if ((esupport&(E_VARIABLE|E_FUNCTION)) == (E_VARIABLE|E_FUNCTION)
837 <                                && curfunc != NULL)
838 <                        for (i = 1, ep2 = curfunc->v.kid->sibling;
839 <                                        ep2 != NULL; i++, ep2 = ep2->sibling)
840 <                                if (!strcmp(ep2->v.name, nam)) {
821 <                                        ep1 = newnode();
822 <                                        ep1->type = ARG;
823 <                                        ep1->v.chan = i;
824 <                                        break;
825 <                                }
826 <                if (ep1 == NULL) {
834 >            nam = getname();
835 >            ep1 = NULL;
836 >            if ((esupport&(E_VARIABLE|E_FUNCTION)) == (E_VARIABLE|E_FUNCTION)
837 >                                && ecurfunc != NULL)
838 >                for (i = 1, ep2 = ecurfunc->v.kid->sibling;
839 >                                ep2 != NULL; i++, ep2 = ep2->sibling)
840 >                    if (!strcmp(ep2->v.name, nam)) {
841                          ep1 = newnode();
842 <                        ep1->type = VAR;
843 <                        ep1->v.ln = varinsert(nam);
844 <                }
845 <                if (esupport&E_FUNCTION && nextc == '(') {
846 <                        ep2 = newnode();
847 <                        ep2->type = FUNC;
848 <                        addekid(ep2, ep1);
849 <                        ep1 = ep2;
850 <                        do {
851 <                                scan();
852 <                                addekid(ep1, getE1());
853 <                        } while (nextc == ',');
854 <                        if (nextc != ')')
855 <                                syntax("')' expected");
856 <                        scan();
857 <                } else if (!(esupport&E_VARIABLE))
858 <                        syntax("'(' expected");
859 <                if (esupport&E_RCONST && isconstvar(ep1))
860 <                        ep1 = rconst(ep1);
861 <                return(ep1);
842 >                        ep1->type = ARG;
843 >                        ep1->v.chan = i;
844 >                        break;
845 >                    }
846 >            if (ep1 == NULL) {
847 >                ep1 = newnode();
848 >                ep1->type = VAR;
849 >                ep1->v.ln = varinsert(nam);
850 >            }
851 >            if (esupport&E_FUNCTION && nextc == '(') {
852 >                ep2 = newnode();
853 >                ep2->type = FUNC;
854 >                addekid(ep2, ep1);
855 >                ep1 = ep2;
856 >                do {
857 >                    escan();
858 >                    addekid(ep1, getE1());
859 >                } while (nextc == ',');
860 >                if (nextc != ')')
861 >                    esyntax("')' expected");
862 >                escan();
863 >            } else if (!(esupport&E_VARIABLE))
864 >                esyntax("'(' expected");
865 >            if (esupport&E_RCONST && isconstvar(ep1))
866 >                ep1 = rconst(ep1);
867 >            return(ep1);
868          }
869          if (isdecimal(nextc)) {
870 <                ep1 = newnode();
871 <                ep1->type = NUM;
872 <                ep1->v.num = getnum();
873 <                return(ep1);
870 >            ep1 = newnode();
871 >            ep1->type = NUM;
872 >            ep1->v.num = getnum();
873 >            return(ep1);
874          }
875 <        syntax("unexpected character");
875 >        esyntax("unexpected character");
876          return NULL; /* pro forma return */
877   }
878  
# Line 869 | Line 889 | rconst(                        /* reduce a constant expression */
889      errno = 0;
890      ep->v.num = evalue(epar);
891      if ((errno == EDOM) | (errno == ERANGE))
892 <        syntax("bad constant expression");
892 >        esyntax("bad constant expression");
893      epfree(epar,1);
894  
895      return(ep);
# Line 908 | Line 928 | isconstfun(                    /* is ep linked to a constant function?
928   )
929   {
930      EPNODE  *dp;
931 <    LIBR  *lp;
931 >    ELIBR  *lp;
932  
933      if (ep->type != VAR)
934          return(0);

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)