Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

Expr.cc

Go to the documentation of this file.
00001 /*
00002     File:       Expr.cc
00003  
00004     Function:   
00005  
00006     Authors:    Paul Heckbert, Andrew Willmott
00007  
00008     Notes:      
00009 */
00010 
00011 #include "cl/Expr.h"
00012 
00013 /*
00014  * expr_eval: expression evaluator - converts ascii string to floating point
00015  * Works by top-down predictive parsing.
00016  * Most of the routines gobble characters and advance global string pointer s.
00017  * Sets global expr_err if an error occurs.
00018  *
00019  * supports: parentheses, % for mod, ^ for pow, elementary functions,
00020  * constants pi and e, variable base constants
00021  *
00022  * Paul Heckbert    18 April 1988
00023  * converted to ANSI C, ajw 1999
00024  */
00025 
00026 
00027 #include <ctype.h>
00028 #include <math.h>
00029 #include <limits.h>
00030 
00031 inline Double DegsToRads(Double degrees)    
00032 { return(degrees * (M_PI / 180.0)); }
00033 inline Double RadsToDegs(Double rads)       
00034 { return(rads * (180.0 / M_PI)); }
00035 
00036 static Double expr();
00037 static Double term();
00038 static Double factor();
00039 static Double signednumber();
00040 static Double number();
00041 static Double paren();
00042 static Double posconst();
00043 static Double expt(Int a, Int n);
00044 static void paren2(Double *x, Double *y);
00045 static Int eq(Int n, const Char *a, const Char *b);
00046 static void error(const Char *s, Int len, const Char *err);
00047 static void prints(Int n, const Char *s);
00048 static Int digit(Int c);
00049 
00050 static const Char *s0, *s;
00051 Int expr_error;
00052 
00053 inline space()
00054 { for (; isspace(*s); s++); };
00055 
00056 #ifdef MAIN
00057 main(Int ac, Char **av)
00058 {
00059     Double x;
00060 
00061     if (ac != 2) exit(1);
00062     x = expr_eval(av[1]);
00063     printf("%g\n", x);
00064 }
00065 #endif
00066 
00067 Int expr_eval_int(StrConst str)
00068 {
00069     Double x;
00070 
00071     x = expr_eval(str);
00072     /* do unsigned Double to signed Int conversion: */
00073 
00074     if (x > INT_MAX)
00075         return(Int(x + 2.0 * INT_MIN));
00076     else
00077         return(Int(x));
00078 }
00079 
00080 Long expr_eval_long(StrConst str)
00081 {
00082     Double x;
00083 
00084     x = expr_eval(str);
00085     /* do unsigned Double to signed Long conversion: */
00086     if (x > LONG_MAX)
00087         return(Long(x + 2.0 * LONG_MIN));
00088     else
00089         return(Long(x));
00090 }
00091 
00092 Double expr_eval(StrConst str)
00093 {
00094     Double x;
00095 
00096     s0 = s = str;
00097     expr_error = EXPR_GOOD;
00098     x = expr();
00099     if (*s)
00100     {
00101         error(s, 1, "garbage in expression");
00102         expr_error = s == s0 ? EXPR_BAD : EXPR_SOSO;
00103     }
00104     return x;
00105 }
00106 
00107 static Double expr()
00108 {
00109     Double x;
00110 
00111     for (x = term(); ; )
00112     {
00113         space();
00114         switch (*s)
00115         {
00116         case '+':
00117             s++;
00118             x += term(); break;
00119         case '-': s++; x -= term(); break;
00120         default: return x;
00121         }
00122     }
00123 }
00124 
00125 static Double term()
00126 {
00127     Double x, y;
00128 
00129     for (x = factor(); ; )
00130     {
00131         space();
00132         switch (*s)
00133         {
00134         case '*':
00135             s++;
00136             x *= factor(); break;
00137         case '/': s++; x /= factor(); break;
00138         case '%': s++; y = factor(); x = x - floor(x / y) * y; break;
00139         default: return x;
00140         }
00141     }
00142 }
00143 
00144 static Double factor()
00145 {
00146     Double x;
00147 
00148     for (x = signednumber(); ; )
00149     {
00150         space();
00151         switch (*s)
00152         {
00153         case '^':
00154             s++;
00155             return pow(x, factor());    /* right-associative */
00156         default: return x;
00157         }
00158     }
00159 }
00160 
00161 static Double signednumber()
00162 {
00163     space();
00164     switch (*s)
00165     {
00166     case '-':
00167         s++;
00168         return - signednumber();
00169     case '+': s++; return signednumber();
00170     default: return number();
00171     }
00172 }
00173 
00174 static Double number()
00175 {
00176     const Char *func;
00177     Int n;
00178     Double x, y;
00179 
00180     space();
00181     if (isdigit(*s) || *s == '.') return posconst();
00182     if (*s == '(') return paren();
00183 
00184     if (isalpha(*s))
00185     {
00186         func = s;
00187         for (s++; isalpha(*s) || isdigit(*s); s++);
00188         n = s - func;   /* length of funcname */
00189 
00190         if (eq(n, func, "pi"))  return M_PI;
00191         if (eq(n, func, "e"))   return exp(1.);
00192 
00193         if (eq(n, func, "sqrt"))    return sqrt(paren());
00194         if (eq(n, func, "exp")) return exp(paren());
00195         if (eq(n, func, "log")) return log(paren());
00196         if (eq(n, func, "pow"))
00197         {
00198             paren2(&x, &y);
00199             return pow(x, y);
00200         }
00201 
00202         if (eq(n, func, "sin")) return sin(paren());
00203         if (eq(n, func, "cos")) return cos(paren());
00204         if (eq(n, func, "tan")) return tan(paren());
00205         if (eq(n, func, "asin"))    return asin(paren());
00206         if (eq(n, func, "acos"))    return acos(paren());
00207         if (eq(n, func, "atan"))    return atan(paren());
00208         if (eq(n, func, "atan2"))
00209         {
00210             paren2(&x, &y);
00211             return atan2(x, y);
00212         }
00213 
00214         if (eq(n, func, "sind"))    return sin(DegsToRads(paren()));
00215         if (eq(n, func, "cosd"))    return cos(DegsToRads(paren()));
00216         if (eq(n, func, "tand"))    return tan(DegsToRads(paren()));
00217         if (eq(n, func, "dasin"))   return RadsToDegs(asin(paren()));
00218         if (eq(n, func, "dacos"))   return RadsToDegs(acos(paren()));
00219         if (eq(n, func, "datan"))   return RadsToDegs(atan(paren()));
00220         if (eq(n, func, "datan2"))
00221         {
00222             paren2(&x, &y);
00223             return RadsToDegs(atan2(x, y));
00224         }
00225 
00226         if (eq(n, func, "floor"))   return floor(paren());
00227         if (eq(n, func, "ceil"))    return ceil(paren());
00228 
00229         error(func, n, "bad numerical expression");
00230         return 0.;
00231     }
00232 
00233     error(s, 1, "syntax error");
00234     return 0.;
00235 }
00236 
00237 /* paren: '(' expr ')' */
00238 
00239 static Double paren()
00240 {
00241     Double x;
00242 
00243     space();
00244     if (*s != '(') error(s, 1, "expected '('");
00245     s++;
00246     x = expr();
00247     space();
00248     if (*s != ')') error(s, 1, "expected ')'");
00249     s++;
00250     return x;
00251 }
00252 
00253 /* paren2: '(' expr ',' expr ')' */
00254 
00255 static void paren2(Double *x, Double *y)
00256 {
00257     space();
00258     if (*s != '(') error(s, 1, "expected '('");
00259     s++;
00260     *x = expr();
00261     space();
00262     if (*s != ',') error(s, 1, "expected ','");
00263     s++;
00264     *y = expr();
00265     space();
00266     if (*s != ')') error(s, 1, "expected ')'");
00267     s++;
00268 }
00269 
00270 /*
00271  * posconst: given a string beginning at s, return floating point value.
00272  * like atof but it uses and modifies the global ptr s
00273  */
00274 
00275 static Double posconst()
00276 {
00277     Int base, exp, pos, d;
00278     Double x, y;
00279 
00280     space();
00281     if (*s == '0')
00282     {       /* change base: 10 = 012 = 0xa = 0b2:1010 */
00283         s++;
00284         switch (*s)
00285         {
00286         case 'b':
00287             s++;
00288             for (base = 0; isdigit(*s); s++)
00289                 base = base * 10 + *s - '0';    /* base is in base 10! */
00290             if (*s != ':') error(s, 1, "expecting ':'");
00291             s++;
00292             break;
00293         case 'x':
00294             s++;
00295             base = 16;
00296             break;
00297         case 't':
00298             s++;
00299             base = 10;
00300             break;
00301         case '.':
00302             base = 10;
00303             break;          /* a float, e.g.: 0.123 */
00304         default:
00305             base = 8;
00306             break;
00307         }
00308     }
00309     else base = 10;
00310 
00311     x = 0.;
00312     for (; d = digit(*s), d >= 0 && d < base; s++)
00313         x = x * base + d;
00314     if (*s == '.')
00315     {
00316         s++;
00317         for (y = 1.; d = digit(*s), d >= 0 && d < base; s++)
00318         {
00319             x = x * base + d;       /* fraction is in variable base */
00320             y *= base;
00321         }
00322         x /= y;
00323     }
00324     if (*s == 'e' || *s == 'E')
00325     {
00326         s++;
00327         if (*s == '-')
00328         {
00329             s++;
00330             pos = 0;
00331         }
00332         else if (*s == '+')
00333         {
00334             s++;
00335             pos = 1;
00336         }
00337         else pos = 1;
00338         for (exp = 0; isdigit(*s); s++)
00339             exp = exp * 10 + *s - '0';      /* exponent is in base 10 */
00340         y = expt(base, exp);
00341         if (pos) x *= y;
00342         else x /= y;
00343     }
00344     return x;
00345 }
00346 
00347 static Int digit(Int c)
00348 {
00349     return isdigit(c) ? c - '0' :
00350            c >= 'a' && c <= 'z' ? c - 'a' + 10 : c >= 'A' && c <= 'Z' ? c - 'A' + 10 : -1;
00351 }
00352 
00353 /* expt: a^n for n>=0 */
00354 
00355 static Double expt(Int a, Int n)
00356 {
00357     Double t, x;
00358 
00359     if (n < 0)
00360     {
00361         fprintf(stderr, "expt: can't do negative exponents\n");
00362         return 1.;
00363     }
00364     if (n == 0) return 1.;
00365     for (t = a, x = 1.; n > 0; n >>= 1)
00366     {
00367         if (n&1) x *= t;
00368         t *= t;
00369     }
00370     return x;
00371 }
00372 
00373 /* eq: test equality of string a, of length n, with null-terminated string b */
00374 
00375 static Int eq(Int n, const Char *a, const Char *b)
00376 {
00377     Char c, *nca = (Char *) a;
00378     Int ret;
00379 
00380     c = a[n];
00381     nca[n] = 0;
00382     ret = (strcmp(a, b) == 0);
00383     nca[n] = c;
00384     return ret;
00385 }
00386 
00387 static void error(const Char *s, Int len, const Char *err)
00388 {
00389 //    if (*s == 0) s[len] = 0;      /* just in case */
00390     printf("expr: %s: ", err);
00391     prints(s - s0, s0);
00392     printf("[");
00393     prints(len, s);
00394     printf("]");
00395     prints(s + strlen(s) - s0 - len, s + len);
00396     printf("\n");
00397     if (expr_error != EXPR_BAD)
00398         expr_error = s == s0 ? EXPR_BAD : EXPR_SOSO;
00399 }
00400 
00401 /* prints: print string s of length n */
00402 
00403 static void prints(Int n, const Char *s)
00404 {
00405     Char c, *ncs = (Char *) s;
00406 
00407     c = s[n];
00408     ncs[n] = 0;
00409     printf("%s", s);
00410     ncs[n] = c;
00411 }

Generated at Sat Aug 5 00:16:31 2000 for Class Library by doxygen 1.1.0 written by Dimitri van Heesch, © 1997-2000