--- ray/src/common/calexpr.c 1992/10/06 12:29:36 2.9
+++ ray/src/common/calexpr.c 2003/02/22 02:07:21 2.18
@@ -1,9 +1,6 @@
-/* Copyright (c) 1992 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,8 +13,67 @@ 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
@@ -26,6 +82,8 @@ static char SCCSid[] = "$SunId$ LBL";
#include
+#include
+
#include "calcomp.h"
#define MAXLINE 256 /* maximum line length */
@@ -34,42 +92,26 @@ static char SCCSid[] = "$SunId$ LBL";
#define isdecimal(c) (isdigit(c) || (c) == '.')
-#ifndef atof
-extern double atof();
-#endif
-extern char *fgets(), *savestr();
-extern char *emalloc(), *ecalloc();
-extern EPNODE *curfunc;
-extern double efunc(), evariable();
-static double euminus(), echannel(), eargument(), enumber();
+static double euminus(), eargument(), enumber();
+static double echannel();
static double eadd(), esubtr(), emult(), edivi(), epow();
static double ebotch();
+unsigned int esupport = /* what to support */
+ E_VARIABLE | E_FUNCTION | E_REDEFW;
+
int nextc; /* lookahead character */
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,
@@ -101,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");
@@ -125,6 +165,55 @@ 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;
{
@@ -132,7 +221,6 @@ register EPNODE *epar;
switch (epar->type) {
-#if defined(VARIABLE) || defined(FUNCTION)
case VAR:
varfree(epar->v.ln);
break;
@@ -140,7 +228,6 @@ register EPNODE *epar;
case SYM:
freestr(epar->v.name);
break;
-#endif
case NUM:
case CHAN:
@@ -149,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;
}
@@ -159,14 +248,12 @@ register EPNODE *epar;
}
/* the following used to be a switch */
-#ifdef FUNCTION
static double
eargument(ep)
EPNODE *ep;
{
return(argument(ep->v.chan));
}
-#endif
static double
enumber(ep)
@@ -184,14 +271,12 @@ EPNODE *ep;
return(-evalue(ep1));
}
-#ifdef INCHAN
static double
echannel(ep)
EPNODE *ep;
{
return(chanvalue(ep->v.chan));
}
-#endif
static double
eadd(ep)
@@ -295,6 +380,7 @@ register EPNODE *ep;
}
+void
initfile(fp, fn, ln) /* prepare input file */
FILE *fp;
char *fn;
@@ -312,6 +398,7 @@ int ln;
}
+void
initstr(s, fn, ln) /* prepare input string */
char *s;
char *fn;
@@ -326,6 +413,7 @@ int ln;
}
+void
getscanpos(fnp, lnp, spp, fpp) /* return current scan position */
char **fnp;
int *lnp;
@@ -397,6 +485,7 @@ long l;
}
+void
syntax(err) /* report syntax error and quit */
char *err;
{
@@ -422,6 +511,7 @@ char *err;
}
+void
addekid(ep, ekid) /* add a child to ep */
register EPNODE *ep;
EPNODE *ekid;
@@ -437,7 +527,6 @@ EPNODE *ekid;
}
-#if defined(VARIABLE) || defined(FUNCTION)
char *
getname() /* scan an identifier */
{
@@ -453,7 +542,6 @@ getname() /* scan an identifier */
return(str);
}
-#endif
int
@@ -486,18 +574,22 @@ getnum() /* scan a positive float */
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 ((lnext == 'e' || lnext == 'E') && i < MAXWORD) {
+ if ((lnext == 'e' | lnext == 'E') && i < MAXWORD) {
str[i++] = lnext;
lnext = scan();
- if ((lnext == '-' || lnext == '+') && i < MAXWORD) {
+ if ((lnext == '-' | lnext == '+') && i < MAXWORD) {
str[i++] = lnext;
lnext = scan();
}
+ if (!isdigit(lnext))
+ syntax("missing exponent");
while (isdigit(lnext) && i < MAXWORD) {
str[i++] = lnext;
lnext = scan();
@@ -522,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);
@@ -545,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);
@@ -568,10 +658,9 @@ getE3() /* E3 -> E4 ^ 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
return(ep2);
}
return(ep1);
@@ -627,22 +716,20 @@ 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) || nextc == CNTXMARK) {
- nam = getname();
-#if defined(VARIABLE) && defined(FUNCTION)
- ep1 = NULL;
- 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, nam)) {
@@ -651,15 +738,12 @@ getE5() /* E5 -> (E1) */
ep1->v.chan = i;
break;
}
- if (ep1 == NULL)
-#endif
- {
+ if (ep1 == NULL) {
ep1 = newnode();
ep1->type = VAR;
ep1->v.ln = varinsert(nam);
}
-#ifdef FUNCTION
- if (nextc == '(') {
+ if (esupport&E_FUNCTION && nextc == '(') {
ep2 = newnode();
ep2->type = FUNC;
addekid(ep2, ep1);
@@ -671,19 +755,12 @@ getE5() /* E5 -> (E1) */
if (nextc != ')')
syntax("')' expected");
scan();
- }
-#ifndef VARIABLE
- else
+ } else if (!(esupport&E_VARIABLE))
syntax("'(' expected");
-#endif
-#endif
-#ifdef RCONST
- if (isconstvar(ep1))
+ if (esupport&E_RCONST && isconstvar(ep1))
ep1 = rconst(ep1);
-#endif
return(ep1);
}
-#endif
if (isdecimal(nextc)) {
ep1 = newnode();
@@ -695,7 +772,6 @@ getE5() /* E5 -> (E1) */
}
-#ifdef RCONST
EPNODE *
rconst(epar) /* reduce a constant expression */
register EPNODE *epar;
@@ -714,14 +790,13 @@ register EPNODE *epar;
}
+int
isconstvar(ep) /* is ep linked to a constant expression? */
register EPNODE *ep;
{
-#ifdef VARIABLE
register EPNODE *ep1;
-#ifdef FUNCTION
- if (ep->type == FUNC) {
+ 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)
@@ -729,24 +804,18 @@ register EPNODE *ep;
return(0);
return(1);
}
-#endif
if (ep->type != VAR)
return(0);
ep1 = ep->v.ln->def;
if (ep1 == NULL || ep1->type != ':')
return(0);
-#ifdef FUNCTION
- if (ep1->v.kid->type != SYM)
+ if (esupport&E_FUNCTION && ep1->v.kid->type != SYM)
return(0);
-#endif
return(1);
-#else
- return(ep->type == FUNC);
-#endif
}
-#if defined(FUNCTION) && defined(VARIABLE)
+int
isconstfun(ep) /* is ep linked to a constant function? */
register EPNODE *ep;
{
@@ -755,11 +824,12 @@ register EPNODE *ep;
if (ep->type != VAR)
return(0);
- if ((dp = ep->v.ln->def) != NULL && dp->v.kid->type == FUNC)
- return(dp->type == ':');
+ 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);
}
-#endif
-#endif