--- ray/src/common/calexpr.c 1990/08/18 16:28:52 1.7
+++ ray/src/common/calexpr.c 2003/02/22 02:07:21 2.18
@@ -1,9 +1,6 @@
-/* Copyright (c) 1986 Regents of the University of California */
-
#ifndef lint
-static char SCCSid[] = "$SunId$ LBL";
+static const char RCSid[] = "$Id: calexpr.c,v 2.18 2003/02/22 02:07:21 greg Exp $";
#endif
-
/*
* Compute data values using expression parser
*
@@ -16,60 +13,105 @@ static char SCCSid[] = "$SunId$ LBL";
* 1/29/87 Made variables conditional (VARIABLE)
*
* 5/19/88 Added constant subexpression elimination (RCONST)
+ *
+ * 2/19/03 Eliminated conditional compiles in favor of esupport extern.
*/
+/* ====================================================================
+ * The Radiance Software License, Version 1.0
+ *
+ * Copyright (c) 1990 - 2002 The Regents of the University of California,
+ * through Lawrence Berkeley National Laboratory. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes Radiance software
+ * (http://radsite.lbl.gov/)
+ * developed by the Lawrence Berkeley National Laboratory
+ * (http://www.lbl.gov/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Radiance," "Lawrence Berkeley National Laboratory"
+ * and "The Regents of the University of California" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact radiance@radsite.lbl.gov.
+ *
+ * 5. Products derived from this software may not be called "Radiance",
+ * nor may "Radiance" appear in their name, without prior written
+ * permission of Lawrence Berkeley National Laboratory.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Lawrence Berkeley National Laboratory OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of Lawrence Berkeley National Laboratory. For more
+ * information on Lawrence Berkeley National Laboratory, please see
+ * .
+ */
+
#include
#include
#include
-#include "calcomp.h"
+#include
-#define MAXLINE 256 /* maximum line length */
-#define MAXWORD 64 /* maximum word length */
+#include
-#define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE))
+#include "calcomp.h"
-#define isid(c) (isalnum(c) || (c) == '_' || (c) == '.')
+#define MAXLINE 256 /* maximum line length */
-#define isdecimal(c) (isdigit(c) || (c) == '.')
+#define newnode() (EPNODE *)ecalloc(1, sizeof(EPNODE))
-extern double atof(), pow();
-extern char *fgets(), *savestr();
-extern char *emalloc(), *ecalloc();
-extern EPNODE *curfunc;
-extern double efunc(), evariable();
-static double euminus(), echannel(), eargument(), enumber();
+#define isdecimal(c) (isdigit(c) || (c) == '.')
+
+static double euminus(), eargument(), enumber();
+static double echannel();
static double eadd(), esubtr(), emult(), edivi(), epow();
static double ebotch();
-extern int errno;
+unsigned int esupport = /* what to support */
+ E_VARIABLE | E_FUNCTION | E_REDEFW;
+
int nextc; /* lookahead character */
-double (*eoper[])() = { /* expression operations */
+double (*eoper[])() = { /* expression operations */
ebotch,
-#ifdef VARIABLE
evariable,
-#else
- ebotch,
-#endif
enumber,
euminus,
-#ifdef INCHAN
echannel,
-#else
- ebotch,
-#endif
-#ifdef FUNCTION
efunc,
eargument,
-#else
ebotch,
ebotch,
-#endif
- ebotch,
- ebotch,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
emult,
@@ -78,8 +120,10 @@ double (*eoper[])() = { /* expression operations */
esubtr,
0,
edivi,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,
ebotch,
+ 0,0,
+ ebotch,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
epow,
@@ -99,9 +143,7 @@ char *expr;
EPNODE *ep;
initstr(expr, NULL, 0);
-#if defined(VARIABLE) && defined(FUNCTION)
curfunc = NULL;
-#endif
ep = getE1();
if (nextc != EOF)
syntax("unexpected character");
@@ -123,18 +165,65 @@ char *expr;
}
+int
+epcmp(ep1, ep2) /* compare two expressions for equivalence */
+register EPNODE *ep1, *ep2;
+{
+ double d;
+
+ if (ep1->type != ep2->type)
+ return(1);
+
+ switch (ep1->type) {
+
+ case VAR:
+ return(ep1->v.ln != ep2->v.ln);
+
+ case NUM:
+ if (ep2->v.num == 0)
+ return(ep1->v.num != 0);
+ d = ep1->v.num / ep2->v.num;
+ return(d > 1.000000000001 | d < 0.999999999999);
+
+ case CHAN:
+ case ARG:
+ return(ep1->v.chan != ep2->v.chan);
+
+ case '=':
+ case ':':
+ return(epcmp(ep1->v.kid->sibling, ep2->v.kid->sibling));
+
+ case TICK:
+ case SYM: /* should never get this one */
+ return(0);
+
+ default:
+ ep1 = ep1->v.kid;
+ ep2 = ep2->v.kid;
+ while (ep1 != NULL) {
+ if (ep2 == NULL)
+ return(1);
+ if (epcmp(ep1, ep2))
+ return(1);
+ ep1 = ep1->sibling;
+ ep2 = ep2->sibling;
+ }
+ return(ep2 != NULL);
+ }
+}
+
+
+void
epfree(epar) /* free a parse tree */
-register EPNODE *epar;
+register EPNODE *epar;
{
register EPNODE *ep;
switch (epar->type) {
-#if defined(VARIABLE) || defined(FUNCTION)
case VAR:
varfree(epar->v.ln);
break;
-#endif
case SYM:
freestr(epar->v.name);
@@ -147,8 +236,10 @@ register EPNODE *epar;
break;
default:
- for (ep = epar->v.kid; ep != NULL; ep = ep->sibling)
+ while ((ep = epar->v.kid) != NULL) {
+ epar->v.kid = ep->sibling;
epfree(ep);
+ }
break;
}
@@ -157,43 +248,39 @@ register EPNODE *epar;
}
/* the following used to be a switch */
-#ifdef FUNCTION
static double
eargument(ep)
-EPNODE *ep;
+EPNODE *ep;
{
return(argument(ep->v.chan));
}
-#endif
static double
enumber(ep)
-EPNODE *ep;
+EPNODE *ep;
{
return(ep->v.num);
}
static double
euminus(ep)
-EPNODE *ep;
+EPNODE *ep;
{
register EPNODE *ep1 = ep->v.kid;
return(-evalue(ep1));
}
-#ifdef INCHAN
static double
echannel(ep)
-EPNODE *ep;
+EPNODE *ep;
{
return(chanvalue(ep->v.chan));
}
-#endif
static double
eadd(ep)
-EPNODE *ep;
+EPNODE *ep;
{
register EPNODE *ep1 = ep->v.kid;
@@ -202,7 +289,7 @@ EPNODE *ep;
static double
esubtr(ep)
-EPNODE *ep;
+EPNODE *ep;
{
register EPNODE *ep1 = ep->v.kid;
@@ -211,7 +298,7 @@ EPNODE *ep;
static double
emult(ep)
-EPNODE *ep;
+EPNODE *ep;
{
register EPNODE *ep1 = ep->v.kid;
@@ -220,7 +307,7 @@ EPNODE *ep;
static double
edivi(ep)
-EPNODE *ep;
+EPNODE *ep;
{
register EPNODE *ep1 = ep->v.kid;
double d;
@@ -236,16 +323,16 @@ EPNODE *ep;
static double
epow(ep)
-EPNODE *ep;
+EPNODE *ep;
{
register EPNODE *ep1 = ep->v.kid;
double d;
- int lasterrno;
+ int lasterrno;
lasterrno = errno;
errno = 0;
d = pow(evalue(ep1), evalue(ep1->sibling));
-#ifdef IEEE
+#ifdef IEEE
if (!finite(d))
errno = EDOM;
#endif
@@ -259,7 +346,7 @@ EPNODE *ep;
static double
ebotch(ep)
-EPNODE *ep;
+EPNODE *ep;
{
eputs("Bad expression!\n");
quit(1);
@@ -268,7 +355,7 @@ EPNODE *ep;
EPNODE *
ekid(ep, n) /* return pointer to a node's nth kid */
-register EPNODE *ep;
+register EPNODE *ep;
register int n;
{
@@ -282,7 +369,7 @@ register int n;
int
nekids(ep) /* return # of kids for node ep */
-register EPNODE *ep;
+register EPNODE *ep;
{
register int n = 0;
@@ -293,12 +380,13 @@ register EPNODE *ep;
}
+void
initfile(fp, fn, ln) /* prepare input file */
FILE *fp;
char *fn;
int ln;
{
- static char inpbuf[MAXLINE];
+ static char inpbuf[MAXLINE];
infp = fp;
linbuf = inpbuf;
@@ -310,6 +398,7 @@ int ln;
}
+void
initstr(s, fn, ln) /* prepare input string */
char *s;
char *fn;
@@ -324,8 +413,25 @@ int ln;
}
-scan() /* scan next character */
+void
+getscanpos(fnp, lnp, spp, fpp) /* return current scan position */
+char **fnp;
+int *lnp;
+char **spp;
+FILE **fpp;
{
+ if (fnp != NULL) *fnp = infile;
+ if (lnp != NULL) *lnp = lineno;
+ if (spp != NULL) *spp = linbuf+linepos;
+ if (fpp != NULL) *fpp = infp;
+}
+
+
+int
+scan() /* scan next character, return literal next */
+{
+ register int lnext = 0;
+
do {
if (linbuf[linepos] == '\0')
if (infp == NULL || fgets(linbuf, MAXLINE, infp) == NULL)
@@ -337,6 +443,8 @@ scan() /* scan next character */
}
else
nextc = linbuf[linepos++];
+ if (!lnext)
+ lnext = nextc;
if (nextc == '{') {
scan();
while (nextc != '}')
@@ -347,16 +455,17 @@ scan() /* scan next character */
scan();
}
} while (isspace(nextc));
+ return(lnext);
}
char *
-ltoa(l) /* convert long to ascii */
+long2ascii(l) /* convert long to ascii */
long l;
{
- static char buf[16];
+ static char buf[16];
register char *cp;
- int neg = 0;
+ int neg = 0;
if (l == 0)
return("0");
@@ -376,6 +485,7 @@ long l;
}
+void
syntax(err) /* report syntax error and quit */
char *err;
{
@@ -385,9 +495,9 @@ char *err;
if (infile != NULL) eputs(infile);
if (lineno != 0) {
eputs(infile != NULL ? ", line " : "line ");
- eputs(ltoa((long)lineno));
+ eputs(long2ascii((long)lineno));
}
- eputs(": syntax error:\n");
+ eputs(":\n");
}
eputs(linbuf);
if (linbuf[strlen(linbuf)-1] != '\n')
@@ -401,9 +511,10 @@ char *err;
}
+void
addekid(ep, ekid) /* add a child to ep */
-register EPNODE *ep;
-EPNODE *ekid;
+register EPNODE *ep;
+EPNODE *ekid;
{
if (ep->v.kid == NULL)
ep->v.kid = ekid;
@@ -419,12 +530,15 @@ EPNODE *ekid;
char *
getname() /* scan an identifier */
{
- static char str[MAXWORD+1];
- register int i;
+ static char str[MAXWORD+1];
+ register int i, lnext;
- for (i = 0; i < MAXWORD && isid(nextc); i++, scan())
- str[i] = nextc;
+ lnext = nextc;
+ for (i = 0; i < MAXWORD && isid(lnext); i++, lnext = scan())
+ str[i] = lnext;
str[i] = '\0';
+ while (isid(lnext)) /* skip rest of name */
+ lnext = scan();
return(str);
}
@@ -433,12 +547,13 @@ getname() /* scan an identifier */
int
getinum() /* scan a positive integer */
{
- register int n;
+ register int n, lnext;
n = 0;
- while (isdigit(nextc)) {
- n = n * 10 + nextc - '0';
- scan();
+ lnext = nextc;
+ while (isdigit(lnext)) {
+ n = n * 10 + lnext - '0';
+ lnext = scan();
}
return(n);
}
@@ -447,32 +562,37 @@ getinum() /* scan a positive integer */
double
getnum() /* scan a positive float */
{
- register int i;
+ register int i, lnext;
char str[MAXWORD+1];
i = 0;
- while (isdigit(nextc) && i < MAXWORD) {
- str[i++] = nextc;
- scan();
+ lnext = nextc;
+ while (isdigit(lnext) && i < MAXWORD) {
+ str[i++] = lnext;
+ lnext = scan();
}
- if (nextc == '.' && i < MAXWORD) {
- str[i++] = nextc;
- scan();
- while (isdigit(nextc) && i < MAXWORD) {
- str[i++] = nextc;
- scan();
+ if (lnext == '.' && i < MAXWORD) {
+ str[i++] = lnext;
+ lnext = scan();
+ if (i == 1 && !isdigit(lnext))
+ syntax("badly formed number");
+ while (isdigit(lnext) && i < MAXWORD) {
+ str[i++] = lnext;
+ lnext = scan();
}
}
- if ((nextc == 'e' || nextc == 'E') && i < MAXWORD) {
- str[i++] = nextc;
- scan();
- if ((nextc == '-' || nextc == '+') && i < MAXWORD) {
- str[i++] = nextc;
- scan();
+ if ((lnext == 'e' | lnext == 'E') && i < MAXWORD) {
+ str[i++] = lnext;
+ lnext = scan();
+ if ((lnext == '-' | lnext == '+') && i < MAXWORD) {
+ str[i++] = lnext;
+ lnext = scan();
}
- while (isdigit(nextc) && i < MAXWORD) {
- str[i++] = nextc;
- scan();
+ if (!isdigit(lnext))
+ syntax("missing exponent");
+ while (isdigit(lnext) && i < MAXWORD) {
+ str[i++] = lnext;
+ lnext = scan();
}
}
str[i] = '\0';
@@ -483,7 +603,7 @@ getnum() /* scan a positive float */
EPNODE *
getE1() /* E1 -> E1 ADDOP E2 */
- /* E2 */
+ /* E2 */
{
register EPNODE *ep1, *ep2;
@@ -494,10 +614,9 @@ getE1() /* E1 -> E1 ADDOP E2 */
scan();
addekid(ep2, ep1);
addekid(ep2, getE2());
-#ifdef RCONST
- if (ep1->type == NUM && ep1->sibling->type == NUM)
+ if (esupport&E_RCONST &&
+ ep1->type == NUM && ep1->sibling->type == NUM)
ep2 = rconst(ep2);
-#endif
ep1 = ep2;
}
return(ep1);
@@ -506,7 +625,7 @@ getE1() /* E1 -> E1 ADDOP E2 */
EPNODE *
getE2() /* E2 -> E2 MULOP E3 */
- /* E3 */
+ /* E3 */
{
register EPNODE *ep1, *ep2;
@@ -517,10 +636,9 @@ getE2() /* E2 -> E2 MULOP E3 */
scan();
addekid(ep2, ep1);
addekid(ep2, getE3());
-#ifdef RCONST
- if (ep1->type == NUM && ep1->sibling->type == NUM)
+ if (esupport&E_RCONST &&
+ ep1->type == NUM && ep1->sibling->type == NUM)
ep2 = rconst(ep2);
-#endif
ep1 = ep2;
}
return(ep1);
@@ -528,23 +646,22 @@ getE2() /* E2 -> E2 MULOP E3 */
EPNODE *
-getE3() /* E3 -> E3 ^ E4 */
- /* E4 */
+getE3() /* E3 -> E4 ^ E3 */
+ /* E4 */
{
register EPNODE *ep1, *ep2;
ep1 = getE4();
- while (nextc == '^') {
+ if (nextc == '^') {
ep2 = newnode();
ep2->type = nextc;
scan();
addekid(ep2, ep1);
- addekid(ep2, getE4());
-#ifdef RCONST
- if (ep1->type == NUM && ep1->sibling->type == NUM)
+ addekid(ep2, getE3());
+ if (esupport&E_RCONST &&
+ ep1->type == NUM && ep1->sibling->type == NUM)
ep2 = rconst(ep2);
-#endif
- ep1 = ep2;
+ return(ep2);
}
return(ep1);
}
@@ -552,7 +669,7 @@ getE3() /* E3 -> E3 ^ E4 */
EPNODE *
getE4() /* E4 -> ADDOP E5 */
- /* E5 */
+ /* E5 */
{
register EPNODE *ep1, *ep2;
@@ -563,6 +680,10 @@ getE4() /* E4 -> ADDOP E5 */
ep2->v.num = -ep2->v.num;
return(ep2);
}
+ if (ep2->type == UMINUS) { /* don't generate -(-E5) */
+ efree((char *)ep2);
+ return(ep2->v.kid);
+ }
ep1 = newnode();
ep1->type = UMINUS;
addekid(ep1, ep2);
@@ -576,13 +697,14 @@ getE4() /* E4 -> ADDOP E5 */
EPNODE *
getE5() /* E5 -> (E1) */
- /* VAR */
- /* NUM */
- /* $N */
- /* FUNC(E1,..) */
- /* ARG */
+ /* VAR */
+ /* NUM */
+ /* $N */
+ /* FUNC(E1,..) */
+ /* ARG */
{
- int i;
+ int i;
+ char *nam;
register EPNODE *ep1, *ep2;
if (nextc == '(') {
@@ -594,36 +716,34 @@ getE5() /* E5 -> (E1) */
return(ep1);
}
-#ifdef INCHAN
- if (nextc == '$') {
+ if (esupport&E_INCHAN && nextc == '$') {
scan();
ep1 = newnode();
ep1->type = CHAN;
ep1->v.chan = getinum();
return(ep1);
}
-#endif
-#if defined(VARIABLE) || defined(FUNCTION)
- if (isalpha(nextc)) {
- ep1 = newnode();
- ep1->type = VAR;
- ep1->v.ln = varinsert(getname());
-
-#if defined(VARIABLE) && defined(FUNCTION)
- if (curfunc != NULL)
+ if (esupport&(E_VARIABLE|E_FUNCTION) &&
+ (isalpha(nextc) || nextc == CNTXMARK)) {
+ nam = getname();
+ ep1 = NULL;
+ if ((esupport&(E_VARIABLE|E_FUNCTION)) == (E_VARIABLE|E_FUNCTION)
+ && curfunc != NULL)
for (i = 1, ep2 = curfunc->v.kid->sibling;
- ep2 != NULL; i++, ep2 = ep2->sibling)
- if (!strcmp(ep2->v.name, ep1->v.ln->name)) {
- epfree(ep1);
+ ep2 != NULL; i++, ep2 = ep2->sibling)
+ if (!strcmp(ep2->v.name, nam)) {
ep1 = newnode();
ep1->type = ARG;
ep1->v.chan = i;
break;
}
-#endif
-#ifdef FUNCTION
- if (nextc == '(') {
+ if (ep1 == NULL) {
+ ep1 = newnode();
+ ep1->type = VAR;
+ ep1->v.ln = varinsert(nam);
+ }
+ if (esupport&E_FUNCTION && nextc == '(') {
ep2 = newnode();
ep2->type = FUNC;
addekid(ep2, ep1);
@@ -635,15 +755,12 @@ getE5() /* E5 -> (E1) */
if (nextc != ')')
syntax("')' expected");
scan();
- }
-#ifndef VARIABLE
- else
+ } else if (!(esupport&E_VARIABLE))
syntax("'(' expected");
-#endif
-#endif
+ if (esupport&E_RCONST && isconstvar(ep1))
+ ep1 = rconst(ep1);
return(ep1);
}
-#endif
if (isdecimal(nextc)) {
ep1 = newnode();
@@ -655,10 +772,9 @@ getE5() /* E5 -> (E1) */
}
-#ifdef RCONST
EPNODE *
rconst(epar) /* reduce a constant expression */
-register EPNODE *epar;
+register EPNODE *epar;
{
register EPNODE *ep;
@@ -667,9 +783,53 @@ register EPNODE *epar;
errno = 0;
ep->v.num = evalue(epar);
if (errno)
- syntax("bad constant expression");
+ syntax("bad constant expression");
epfree(epar);
return(ep);
}
-#endif
+
+
+int
+isconstvar(ep) /* is ep linked to a constant expression? */
+register EPNODE *ep;
+{
+ register EPNODE *ep1;
+
+ if (esupport&E_FUNCTION && ep->type == FUNC) {
+ if (!isconstfun(ep->v.kid))
+ return(0);
+ for (ep1 = ep->v.kid->sibling; ep1 != NULL; ep1 = ep1->sibling)
+ if (ep1->type != NUM && !isconstfun(ep1))
+ return(0);
+ return(1);
+ }
+ if (ep->type != VAR)
+ return(0);
+ ep1 = ep->v.ln->def;
+ if (ep1 == NULL || ep1->type != ':')
+ return(0);
+ if (esupport&E_FUNCTION && ep1->v.kid->type != SYM)
+ return(0);
+ return(1);
+}
+
+
+int
+isconstfun(ep) /* is ep linked to a constant function? */
+register EPNODE *ep;
+{
+ register EPNODE *dp;
+ register LIBR *lp;
+
+ if (ep->type != VAR)
+ return(0);
+ if ((dp = ep->v.ln->def) != NULL)
+ if (dp->v.kid->type == FUNC)
+ return(dp->type == ':');
+ else
+ return(0); /* don't identify masked library functions */
+ if ((lp = ep->v.ln->lib) != NULL)
+ return(lp->atyp == ':');
+ return(0);
+}