Back to index

radiance  4R0+20100331
calexpr.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: calexpr.c,v 2.33 2009/06/14 18:21:58 greg Exp $";
00003 #endif
00004 /*
00005  *  Compute data values using expression parser
00006  *
00007  *  7/1/85  Greg Ward
00008  *
00009  *  11/11/85  Made channel input conditional with (INCHAN) compiles.
00010  *
00011  *  4/2/86  Added conditional compiles for function definitions (FUNCTION).
00012  *
00013  *  1/29/87  Made variables conditional (VARIABLE)
00014  *
00015  *  5/19/88  Added constant subexpression elimination (RCONST)
00016  *
00017  *  2/19/03   Eliminated conditional compiles in favor of esupport extern.
00018  */
00019 
00020 #include "copyright.h"
00021 
00022 #include  <stdio.h>
00023 #include  <string.h>
00024 #include  <ctype.h>
00025 #include  <errno.h>
00026 #include  <math.h>
00027 #include  <stdlib.h>
00028 
00029 #include  "rtmisc.h"
00030 #include  "rtio.h"
00031 #include  "rterror.h"
00032 #include  "calcomp.h"
00033 
00034 #define        MAXLINE      256           /* maximum line length */
00035 
00036 #define        newnode()    (EPNODE *)ecalloc(1, sizeof(EPNODE))
00037 
00038 #define        isdecimal(c) (isdigit(c) || (c) == '.')
00039 
00040 static double  euminus(EPNODE *), eargument(EPNODE *), enumber(EPNODE *);
00041 static double  echannel(EPNODE *);
00042 static double  eadd(EPNODE *), esubtr(EPNODE *),
00043                emult(EPNODE *), edivi(EPNODE *),
00044                epow(EPNODE *);
00045 static double  ebotch(EPNODE *);
00046 
00047 unsigned int  esupport =           /* what to support */
00048               E_VARIABLE | E_FUNCTION ;
00049 
00050 int  eofc = 0;                            /* optional end-of-file character */
00051 int  nextc;                        /* lookahead character */
00052 
00053 double (*eoper[])(EPNODE *) = {    /* expression operations */
00054        ebotch,
00055        evariable,
00056        enumber,
00057        euminus,
00058        echannel,
00059        efunc,
00060        eargument,
00061        ebotch,
00062        ebotch,
00063        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00064        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00065        emult,
00066        eadd,
00067        0,
00068        esubtr,
00069        0,
00070        edivi,
00071        0,0,0,0,0,0,0,0,0,0,
00072        ebotch,
00073        0,0,
00074        ebotch,
00075        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00076        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
00077        epow,
00078 };
00079 
00080 static FILE  *infp;                /* input file pointer */
00081 static char  *linbuf;                     /* line buffer */
00082 static char  *infile;                     /* input file name */
00083 static int  lineno;                /* input line number */
00084 static int  linepos;               /* position in buffer */
00085 
00086 
00087 EPNODE *
00088 eparse(                     /* parse an expression string */
00089     char  *expr
00090 )
00091 {
00092     EPNODE  *ep;
00093 
00094     initstr(expr, NULL, 0);
00095     curfunc = NULL;
00096     ep = getE1();
00097     if (nextc != EOF)
00098        syntax("unexpected character");
00099     return(ep);
00100 }
00101 
00102 
00103 double
00104 eval(                /* evaluate an expression string */
00105     char  *expr
00106 )
00107 {
00108     register EPNODE  *ep;
00109     double  rval;
00110 
00111     ep = eparse(expr);
00112     rval = evalue(ep);
00113     epfree(ep);
00114     return(rval);
00115 }
00116 
00117 
00118 int
00119 epcmp(               /* compare two expressions for equivalence */
00120     register EPNODE  *ep1,
00121     register EPNODE  *ep2
00122 )
00123 {
00124        double  d;
00125 
00126        if (ep1->type != ep2->type)
00127               return(1);
00128 
00129        switch (ep1->type) {
00130 
00131        case VAR:
00132               return(ep1->v.ln != ep2->v.ln);
00133 
00134        case NUM:
00135               if (ep2->v.num == 0)
00136                      return(ep1->v.num != 0);
00137               d = ep1->v.num / ep2->v.num;
00138               return((d > 1.000000000001) | (d < 0.999999999999));
00139 
00140        case CHAN:
00141        case ARG:
00142               return(ep1->v.chan != ep2->v.chan);
00143 
00144        case '=':
00145        case ':':
00146               return(epcmp(ep1->v.kid->sibling, ep2->v.kid->sibling));
00147 
00148        case CLKT:
00149        case SYM:                   /* should never get this one */
00150               return(0);
00151 
00152        default:
00153               ep1 = ep1->v.kid;
00154               ep2 = ep2->v.kid;
00155               while (ep1 != NULL) {
00156                      if (ep2 == NULL)
00157                             return(1);
00158                      if (epcmp(ep1, ep2))
00159                             return(1);
00160                      ep1 = ep1->sibling;
00161                      ep2 = ep2->sibling;
00162               }
00163               return(ep2 != NULL);
00164        }
00165 }
00166 
00167 
00168 void
00169 epfree(                     /* free a parse tree */
00170     register EPNODE   *epar
00171 )
00172 {
00173     register EPNODE  *ep;
00174 
00175     switch (epar->type) {
00176 
00177        case VAR:
00178            varfree(epar->v.ln);
00179            break;
00180            
00181        case SYM:
00182            freestr(epar->v.name);
00183            break;
00184 
00185        case NUM:
00186        case CHAN:
00187        case ARG:
00188        case CLKT:
00189            break;
00190 
00191        default:
00192            while ((ep = epar->v.kid) != NULL) {
00193               epar->v.kid = ep->sibling;
00194               epfree(ep);
00195            }
00196            break;
00197 
00198     }
00199 
00200     efree((char *)epar);
00201 }
00202 
00203                             /* the following used to be a switch */
00204 static double
00205 eargument(
00206     EPNODE    *ep
00207 )
00208 {
00209     return(argument(ep->v.chan));
00210 }
00211 
00212 static double
00213 enumber(
00214     EPNODE    *ep
00215 )
00216 {
00217     return(ep->v.num);
00218 }
00219 
00220 static double
00221 euminus(
00222     EPNODE    *ep
00223 )
00224 {
00225     register EPNODE  *ep1 = ep->v.kid;
00226 
00227     return(-evalue(ep1));
00228 }
00229 
00230 static double
00231 echannel(
00232     EPNODE    *ep
00233 )
00234 {
00235     return(chanvalue(ep->v.chan));
00236 }
00237 
00238 static double
00239 eadd(
00240     EPNODE    *ep
00241 )
00242 {
00243     register EPNODE  *ep1 = ep->v.kid;
00244 
00245     return(evalue(ep1) + evalue(ep1->sibling));
00246 }
00247 
00248 static double
00249 esubtr(
00250     EPNODE    *ep
00251 )
00252 {
00253     register EPNODE  *ep1 = ep->v.kid;
00254 
00255     return(evalue(ep1) - evalue(ep1->sibling));
00256 }
00257 
00258 static double
00259 emult(
00260     EPNODE    *ep
00261 )
00262 {
00263     register EPNODE  *ep1 = ep->v.kid;
00264 
00265     return(evalue(ep1) * evalue(ep1->sibling));
00266 }
00267 
00268 static double
00269 edivi(
00270     EPNODE    *ep
00271 )
00272 {
00273     register EPNODE  *ep1 = ep->v.kid;
00274     double  d;
00275 
00276     d = evalue(ep1->sibling);
00277     if (d == 0.0) {
00278        wputs("Division by zero\n");
00279        errno = ERANGE;
00280        return(0.0);
00281     }
00282     return(evalue(ep1) / d);
00283 }
00284 
00285 static double
00286 epow(
00287     EPNODE    *ep
00288 )
00289 {
00290     register EPNODE  *ep1 = ep->v.kid;
00291     double  d;
00292     int        lasterrno;
00293 
00294     lasterrno = errno;
00295     errno = 0;
00296     d = pow(evalue(ep1), evalue(ep1->sibling));
00297 #ifdef  isnan
00298     if (errno == 0)
00299        if (isnan(d))
00300            errno = EDOM;
00301        else if (isinf(d))
00302            errno = ERANGE;
00303 #endif
00304     if (errno == EDOM || errno == ERANGE) {
00305        wputs("Illegal power\n");
00306        return(0.0);
00307     }
00308     errno = lasterrno;
00309     return(d);
00310 }
00311 
00312 static double
00313 ebotch(
00314     EPNODE    *ep
00315 )
00316 {
00317     eputs("Bad expression!\n");
00318     quit(1);
00319        return 0.0; /* pro forma return */
00320 }
00321 
00322 
00323 EPNODE *
00324 ekid(                /* return pointer to a node's nth kid */
00325     register EPNODE   *ep,
00326     register int  n
00327 )
00328 {
00329 
00330     for (ep = ep->v.kid; ep != NULL; ep = ep->sibling)
00331        if (--n < 0)
00332            break;
00333 
00334     return(ep);
00335 }
00336 
00337 
00338 int
00339 nekids(                     /* return # of kids for node ep */
00340     register EPNODE   *ep
00341 )
00342 {
00343     register int  n = 0;
00344 
00345     for (ep = ep->v.kid; ep != NULL; ep = ep->sibling)
00346        n++;
00347 
00348     return(n);
00349 }
00350 
00351 
00352 void
00353 initfile(            /* prepare input file */
00354     FILE  *fp,
00355     char  *fn,
00356     int  ln
00357 )
00358 {
00359     static char       inpbuf[MAXLINE];
00360 
00361     infp = fp;
00362     linbuf = inpbuf;
00363     infile = fn;
00364     lineno = ln;
00365     linepos = 0;
00366     inpbuf[0] = '\0';
00367     scan();
00368 }
00369 
00370 
00371 void
00372 initstr(             /* prepare input string */
00373     char  *s,
00374     char  *fn,
00375     int  ln
00376 )
00377 {
00378     infp = NULL;
00379     infile = fn;
00380     lineno = ln;
00381     linbuf = s;
00382     linepos = 0;
00383     scan();
00384 }
00385 
00386 
00387 void
00388 getscanpos(   /* return current scan position */
00389     char  **fnp,
00390     int  *lnp,
00391     char  **spp,
00392     FILE  **fpp
00393 )
00394 {
00395     if (fnp != NULL) *fnp = infile;
00396     if (lnp != NULL) *lnp = lineno;
00397     if (spp != NULL) *spp = linbuf+linepos;
00398     if (fpp != NULL) *fpp = infp;
00399 }
00400 
00401 
00402 int
00403 scan(void)           /* scan next character, return literal next */
00404 {
00405     register int  lnext = 0;
00406 
00407     do {
00408        if (linbuf[linepos] == '\0')
00409            if (infp == NULL || fgets(linbuf, MAXLINE, infp) == NULL)
00410               nextc = EOF;
00411            else {
00412               nextc = linbuf[0];
00413               lineno++;
00414               linepos = 1;
00415            }
00416        else
00417            nextc = linbuf[linepos++];
00418        if (!lnext)
00419               lnext = nextc;
00420        if (nextc == eofc) {
00421               nextc = EOF;
00422               break;
00423        }
00424        if (nextc == '{') {
00425            scan();
00426            while (nextc != '}')
00427               if (nextc == EOF)
00428                   syntax("'}' expected");
00429               else
00430                   scan();
00431            scan();
00432        }
00433     } while (isspace(nextc));
00434     return(lnext);
00435 }
00436 
00437 
00438 char *
00439 long2ascii(                       /* convert long to ascii */
00440     long  l
00441 )
00442 {
00443     static char       buf[16];
00444     register char  *cp;
00445     int        neg = 0;
00446 
00447     if (l == 0)
00448        return("0");
00449     if (l < 0) {
00450        l = -l;
00451        neg++;
00452     }
00453     cp = buf + sizeof(buf);
00454     *--cp = '\0';
00455     while (l) {
00456        *--cp = l % 10 + '0';
00457        l /= 10;
00458     }
00459     if (neg)
00460        *--cp = '-';
00461     return(cp);
00462 }
00463 
00464 
00465 void
00466 syntax(                     /* report syntax error and quit */
00467     char  *err
00468 )
00469 {
00470     register int  i;
00471 
00472     if (infile != NULL || lineno != 0) {
00473        if (infile != NULL) eputs(infile);
00474        if (lineno != 0) {
00475            eputs(infile != NULL ? ", line " : "line ");
00476            eputs(long2ascii((long)lineno));
00477        }
00478        eputs(":\n");
00479     }
00480     eputs(linbuf);
00481     if (linbuf[strlen(linbuf)-1] != '\n')
00482        eputs("\n");
00483     for (i = 0; i < linepos-1; i++)
00484        eputs(linbuf[i] == '\t' ? "\t" : " ");
00485     eputs("^ ");
00486     eputs(err);
00487     eputs("\n");
00488     quit(1);
00489 }
00490 
00491 
00492 void
00493 addekid(                    /* add a child to ep */
00494     register EPNODE   *ep,
00495     EPNODE    *ekid
00496 )
00497 {
00498     if (ep->v.kid == NULL)
00499        ep->v.kid = ekid;
00500     else {
00501        for (ep = ep->v.kid; ep->sibling != NULL; ep = ep->sibling)
00502            ;
00503        ep->sibling = ekid;
00504     }
00505     ekid->sibling = NULL;
00506 }
00507 
00508 
00509 char *
00510 getname(void)               /* scan an identifier */
00511 {
00512     static char       str[RMAXWORD+1];
00513     register int  i, lnext;
00514 
00515     lnext = nextc;
00516     for (i = 0; i < RMAXWORD && isid(lnext); i++, lnext = scan())
00517        str[i] = lnext;
00518     str[i] = '\0';
00519     while (isid(lnext))            /* skip rest of name */
00520        lnext = scan();
00521 
00522     return(str);
00523 }
00524 
00525 
00526 int
00527 getinum(void)               /* scan a positive integer */
00528 {
00529     register int  n, lnext;
00530 
00531     n = 0;
00532     lnext = nextc;
00533     while (isdigit(lnext)) {
00534        n = n * 10 + lnext - '0';
00535        lnext = scan();
00536     }
00537     return(n);
00538 }
00539 
00540 
00541 double
00542 getnum(void)                /* scan a positive float */
00543 {
00544     register int  i, lnext;
00545     char  str[RMAXWORD+1];
00546 
00547     i = 0;
00548     lnext = nextc;
00549     while (isdigit(lnext) && i < RMAXWORD) {
00550        str[i++] = lnext;
00551        lnext = scan();
00552     }
00553     if (lnext == '.' && i < RMAXWORD) {
00554        str[i++] = lnext;
00555        lnext = scan();
00556        if (i == 1 && !isdigit(lnext))
00557            syntax("badly formed number");
00558        while (isdigit(lnext) && i < RMAXWORD) {
00559            str[i++] = lnext;
00560            lnext = scan();
00561        }
00562     }
00563     if ((lnext == 'e') | (lnext == 'E') && i < RMAXWORD) {
00564        str[i++] = lnext;
00565        lnext = scan();
00566        if ((lnext == '-') | (lnext == '+') && i < RMAXWORD) {
00567            str[i++] = lnext;
00568            lnext = scan();
00569        }
00570        if (!isdigit(lnext))
00571            syntax("missing exponent");
00572        while (isdigit(lnext) && i < RMAXWORD) {
00573            str[i++] = lnext;
00574            lnext = scan();
00575        }
00576     }
00577     str[i] = '\0';
00578 
00579     return(atof(str));
00580 }
00581 
00582 
00583 EPNODE *
00584 getE1(void)                        /* E1 -> E1 ADDOP E2 */
00585                             /*      E2 */
00586 {
00587     register EPNODE  *ep1, *ep2;
00588 
00589     ep1 = getE2();
00590     while (nextc == '+' || nextc == '-') {
00591        ep2 = newnode();
00592        ep2->type = nextc;
00593        scan();
00594        addekid(ep2, ep1);
00595        addekid(ep2, getE2());
00596        if (esupport&E_RCONST &&
00597                      ep1->type == NUM && ep1->sibling->type == NUM)
00598               ep2 = rconst(ep2);
00599        ep1 = ep2;
00600     }
00601     return(ep1);
00602 }
00603 
00604 
00605 EPNODE *
00606 getE2(void)                        /* E2 -> E2 MULOP E3 */
00607                             /*      E3 */
00608 {
00609     register EPNODE  *ep1, *ep2;
00610 
00611     ep1 = getE3();
00612     while (nextc == '*' || nextc == '/') {
00613        ep2 = newnode();
00614        ep2->type = nextc;
00615        scan();
00616        addekid(ep2, ep1);
00617        addekid(ep2, getE3());
00618        if (esupport&E_RCONST &&
00619                      ep1->type == NUM && ep1->sibling->type == NUM)
00620               ep2 = rconst(ep2);
00621        ep1 = ep2;
00622     }
00623     return(ep1);
00624 }
00625 
00626 
00627 EPNODE *
00628 getE3(void)                        /* E3 -> E4 ^ E3 */
00629                             /*      E4 */
00630 {
00631     register EPNODE  *ep1, *ep2;
00632 
00633     ep1 = getE4();
00634     if (nextc == '^') {
00635        ep2 = newnode();
00636        ep2->type = nextc;
00637        scan();
00638        addekid(ep2, ep1);
00639        addekid(ep2, getE3());
00640        if (esupport&E_RCONST &&
00641                      ep1->type == NUM && ep1->sibling->type == NUM)
00642               ep2 = rconst(ep2);
00643        return(ep2);
00644     }
00645     return(ep1);
00646 }
00647 
00648 
00649 EPNODE *
00650 getE4(void)                        /* E4 -> ADDOP E5 */
00651                             /*      E5 */
00652 {
00653     register EPNODE  *ep1, *ep2;
00654 
00655     if (nextc == '-') {
00656        scan();
00657        ep2 = getE5();
00658        if (ep2->type == NUM) {
00659               ep2->v.num = -ep2->v.num;
00660               return(ep2);
00661        }
00662        if (ep2->type == UMINUS) {  /* don't generate -(-E5) */
00663            ep1 = ep2->v.kid;
00664            efree((char *)ep2);
00665            return(ep1);
00666        }
00667        ep1 = newnode();
00668        ep1->type = UMINUS;
00669        addekid(ep1, ep2);
00670        return(ep1);
00671     }
00672     if (nextc == '+')
00673        scan();
00674     return(getE5());
00675 }
00676 
00677 
00678 EPNODE *
00679 getE5(void)                 /* E5 -> (E1) */
00680                             /*      VAR */
00681                             /*      NUM */
00682                             /*      $N */
00683                             /*      FUNC(E1,..) */
00684                             /*      ARG */
00685 {
00686        int     i;
00687        char  *nam;
00688        register EPNODE  *ep1, *ep2;
00689 
00690        if (nextc == '(') {
00691               scan();
00692               ep1 = getE1();
00693               if (nextc != ')')
00694                      syntax("')' expected");
00695               scan();
00696               return(ep1);
00697        }
00698 
00699        if (esupport&E_INCHAN && nextc == '$') {
00700               scan();
00701               ep1 = newnode();
00702               ep1->type = CHAN;
00703               ep1->v.chan = getinum();
00704               return(ep1);
00705        }
00706 
00707        if (esupport&(E_VARIABLE|E_FUNCTION) &&
00708                      (isalpha(nextc) || nextc == CNTXMARK)) {
00709               nam = getname();
00710               ep1 = NULL;
00711               if ((esupport&(E_VARIABLE|E_FUNCTION)) == (E_VARIABLE|E_FUNCTION)
00712                             && curfunc != NULL)
00713                      for (i = 1, ep2 = curfunc->v.kid->sibling;
00714                                    ep2 != NULL; i++, ep2 = ep2->sibling)
00715                             if (!strcmp(ep2->v.name, nam)) {
00716                                    ep1 = newnode();
00717                                    ep1->type = ARG;
00718                                    ep1->v.chan = i;
00719                                    break;
00720                             }
00721               if (ep1 == NULL) {
00722                      ep1 = newnode();
00723                      ep1->type = VAR;
00724                      ep1->v.ln = varinsert(nam);
00725               }
00726               if (esupport&E_FUNCTION && nextc == '(') {
00727                      ep2 = newnode();
00728                      ep2->type = FUNC;
00729                      addekid(ep2, ep1);
00730                      ep1 = ep2;
00731                      do {
00732                             scan();
00733                             addekid(ep1, getE1());
00734                      } while (nextc == ',');
00735                      if (nextc != ')')
00736                             syntax("')' expected");
00737                      scan();
00738               } else if (!(esupport&E_VARIABLE))
00739                      syntax("'(' expected");
00740               if (esupport&E_RCONST && isconstvar(ep1))
00741                      ep1 = rconst(ep1);
00742               return(ep1);
00743        }
00744 
00745        if (isdecimal(nextc)) {
00746               ep1 = newnode();
00747               ep1->type = NUM;
00748               ep1->v.num = getnum();
00749               return(ep1);
00750        }
00751        syntax("unexpected character");
00752        return NULL; /* pro forma return */
00753 }
00754 
00755 
00756 EPNODE *
00757 rconst(                     /* reduce a constant expression */
00758     register EPNODE   *epar
00759 )
00760 {
00761     register EPNODE  *ep;
00762 
00763     ep = newnode();
00764     ep->type = NUM;
00765     errno = 0;
00766     ep->v.num = evalue(epar);
00767     if (errno == EDOM || errno == ERANGE)
00768        syntax("bad constant expression");
00769     epfree(epar);
00770  
00771     return(ep);
00772 }
00773 
00774 
00775 int
00776 isconstvar(                 /* is ep linked to a constant expression? */
00777     register EPNODE   *ep
00778 )
00779 {
00780     register EPNODE  *ep1;
00781 
00782     if (esupport&E_FUNCTION && ep->type == FUNC) {
00783        if (!isconstfun(ep->v.kid))
00784               return(0);
00785        for (ep1 = ep->v.kid->sibling; ep1 != NULL; ep1 = ep1->sibling)
00786            if (ep1->type != NUM && !isconstfun(ep1))
00787               return(0);
00788        return(1);
00789     }
00790     if (ep->type != VAR)
00791        return(0);
00792     ep1 = ep->v.ln->def;
00793     if (ep1 == NULL || ep1->type != ':')
00794        return(0);
00795     if (esupport&E_FUNCTION && ep1->v.kid->type != SYM)
00796        return(0);
00797     return(1);
00798 }
00799 
00800 
00801 int
00802 isconstfun(                 /* is ep linked to a constant function? */
00803     register EPNODE   *ep
00804 )
00805 {
00806     register EPNODE  *dp;
00807     register LIBR  *lp;
00808 
00809     if (ep->type != VAR)
00810        return(0);
00811     if ((dp = ep->v.ln->def) != NULL) {
00812        if (dp->v.kid->type == FUNC)
00813            return(dp->type == ':');
00814        else
00815            return(0);              /* don't identify masked library functions */
00816     }
00817     if ((lp = ep->v.ln->lib) != NULL)
00818        return(lp->atyp == ':');
00819     return(0);
00820 }