"I am a person who works hard and plays hard."

Yuan Wei
Second Year Graduate Student Department of Computer Science
University of Virginia Charlottesville, VA 22903
Email: yw3f@cs.virginia.edu


Source Code Analysis

Main Page   Compound List   File List   Compound Members   File Members  

eval.c

Go to the documentation of this file.
00001 /*
00002  * expr.c - expression evaluator routines
00003  *
00004  * This file is a part of the SimpleScalar tool suite written by
00005  * Todd M. Austin as a part of the Multiscalar Research Project.
00006  *  
00007  * The tool suite is currently maintained by Doug Burger and Todd M. Austin.
00008  * 
00009  * Copyright (C) 1994, 1995, 1996, 1997, 1998 by Todd M. Austin
00010  *
00011  * This source file is distributed "as is" in the hope that it will be
00012  * useful.  The tool set comes with no warranty, and no author or
00013  * distributor accepts any responsibility for the consequences of its
00014  * use. 
00015  * 
00016  * Everyone is granted permission to copy, modify and redistribute
00017  * this tool set under the following conditions:
00018  * 
00019  *    This source code is distributed for non-commercial use only. 
00020  *    Please contact the maintainer for restrictions applying to 
00021  *    commercial use.
00022  *
00023  *    Permission is granted to anyone to make or distribute copies
00024  *    of this source code, either as received or modified, in any
00025  *    medium, provided that all copyright notices, permission and
00026  *    nonwarranty notices are preserved, and that the distributor
00027  *    grants the recipient permission for further redistribution as
00028  *    permitted by this document.
00029  *
00030  *    Permission is granted to distribute this file in compiled
00031  *    or executable form under the same conditions that apply for
00032  *    source code, provided that either:
00033  *
00034  *    A. it is accompanied by the corresponding machine-readable
00035  *       source code,
00036  *    B. it is accompanied by a written offer, with no time limit,
00037  *       to give anyone a machine-readable copy of the corresponding
00038  *       source code in return for reimbursement of the cost of
00039  *       distribution.  This written offer must permit verbatim
00040  *       duplication by anyone, or
00041  *    C. it is distributed by someone who received only the
00042  *       executable form, and is accompanied by a copy of the
00043  *       written offer of source code that they received concurrently.
00044  *
00045  * In other words, you are welcome to use, share and improve this
00046  * source file.  You are forbidden to forbid anyone else to use, share
00047  * and improve what you give them.
00048  *
00049  * INTERNET: dburger@cs.wisc.edu
00050  * US Mail:  1210 W. Dayton Street, Madison, WI 53706
00051  *
00052  * $Id: eval.c,v 1.1.1.1 2000/05/26 15:21:52 taustin Exp $
00053  *
00054  * $Log: eval.c,v $
00055  * Revision 1.1.1.1  2000/05/26 15:21:52  taustin
00056  * SimpleScalar Tool Set
00057  *
00058  *
00059  * Revision 1.4  1999/12/31 18:36:02  taustin
00060  * cross-endian execution support added
00061  *
00062  * Revision 1.3  1998/08/31 17:08:31  taustin
00063  * fixed MS VC++ qword to double bugs in Alpha target
00064  *
00065  * Revision 1.2  1998/08/27 08:25:55  taustin
00066  * implemented host interface description in host.h
00067  * added target interface support
00068  * added support for qword's
00069  *
00070  * Revision 1.1  1997/03/11  01:31:26  taustin
00071  * Initial revision
00072  *
00073  *
00074  */
00075 
00076 #include <stdio.h>
00077 #include <stdlib.h>
00078 #include <ctype.h>
00079 #if defined(__CYGWIN32__)
00080 #include <errno.h>
00081 #endif
00082 
00083 #include "host.h"
00084 #include "misc.h"
00085 #include "eval.h"
00086 
00087 #if defined(sparc) && !defined(__svr4__)
00088 #define strtoul strtol
00089 #endif /* sparc */
00090 
00091 /* expression evaluation error, this must be a global */
00092 enum eval_err_t eval_error = ERR_NOERR;
00093 
00094 /* enum eval_err_t -> error description string map */
00095 char *eval_err_str[ERR_NUM] = {
00096   /* ERR_NOERR */       "!! no error!!",
00097   /* ERR_UPAREN */      "unmatched parenthesis",
00098   /* ERR_NOTERM */      "expression term is missing",
00099   /* ERR_DIV0 */        "divide by zero",
00100   /* ERR_BADCONST */    "badly formed constant",
00101   /* ERR_BADEXPR */     "badly formed expression",
00102   /* ERR_UNDEFVAR */    "variable is undefined",
00103   /* ERR_EXTRA */       "extra characters at end of expression"
00104 };
00105 
00106 /* *first* token character -> enum eval_token_t map */
00107 static enum eval_token_t tok_map[256];
00108 static int tok_map_initialized = FALSE;
00109 
00110 /* builds the first token map */
00111 static void
00112 init_tok_map(void)
00113 {
00114   int i;
00115 
00116   for (i=0; i<256; i++)
00117     tok_map[i] = tok_invalid;
00118 
00119   /* identifier characters */
00120   for (i='a'; i<='z'; i++)
00121     tok_map[i] = tok_ident;
00122   for (i='A'; i<='Z'; i++)
00123     tok_map[i] = tok_ident;
00124   tok_map[(int)'_'] = tok_ident;
00125   tok_map[(int)'$'] = tok_ident;
00126 
00127   /* numeric characters */
00128   for (i='0'; i<='9'; i++)
00129     tok_map[i] = tok_const;
00130   tok_map[(int)'.'] = tok_const;
00131 
00132   /* operator characters */
00133   tok_map[(int)'+'] = tok_plus;
00134   tok_map[(int)'-'] = tok_minus;
00135   tok_map[(int)'*'] = tok_mult;
00136   tok_map[(int)'/'] = tok_div;
00137   tok_map[(int)'('] = tok_oparen;
00138   tok_map[(int)')'] = tok_cparen;
00139 
00140   /* whitespace characers */
00141   tok_map[(int)' '] = tok_whitespace;
00142   tok_map[(int)'\t'] = tok_whitespace;
00143 }
00144 
00145 /* get next token from the expression string */
00146 static enum eval_token_t                /* token parsed */
00147 get_next_token(struct eval_state_t *es) /* expression evaluator */
00148 {
00149   int allow_hex;
00150   enum eval_token_t tok;
00151   char *ptok_buf, last_char;
00152 
00153   /* initialize the token map, if needed */
00154   if (!tok_map_initialized)
00155     {
00156       init_tok_map();
00157       tok_map_initialized = TRUE;
00158     }
00159 
00160   /* use the peek'ed token, if available, tok_buf should still be valid */
00161   if (es->peek_tok != tok_invalid)
00162     {
00163       tok = es->peek_tok;
00164       es->peek_tok = tok_invalid;
00165       return tok;
00166     }
00167 
00168   /* set up the token string space */
00169   ptok_buf = es->tok_buf;
00170   *ptok_buf = '\0';
00171 
00172   /* skip whitespace */
00173   while (*es->p && tok_map[(int)*es->p] == tok_whitespace)
00174     es->p++;
00175 
00176   /* end of token stream? */
00177   if (*es->p == '\0')
00178     return tok_eof;
00179 
00180   *ptok_buf++ = *es->p;
00181   tok = tok_map[(int)*es->p++];
00182   switch (tok)
00183     {
00184     case tok_ident:
00185       /* parse off next identifier */
00186       while (*es->p
00187              && (tok_map[(int)*es->p] == tok_ident
00188                  || tok_map[(int)*es->p] == tok_const))
00189         {
00190           *ptok_buf++ = *es->p++;
00191         }
00192       break;
00193     case tok_const:
00194       /* parse off next numeric literal */
00195       last_char = '\0';
00196       allow_hex = FALSE;
00197       while (*es->p &&
00198              (tok_map[(int)*es->p] == tok_const
00199               || (*es->p == '-' && last_char == 'e')
00200               || (*es->p == '+' && last_char == 'e')
00201               || tolower(*es->p) == 'e'
00202               || tolower(*es->p) == 'x'
00203               || (tolower(*es->p) == 'a' && allow_hex)
00204               || (tolower(*es->p) == 'b' && allow_hex)
00205               || (tolower(*es->p) == 'c' && allow_hex)
00206               || (tolower(*es->p) == 'd' && allow_hex)
00207               || (tolower(*es->p) == 'e' && allow_hex)
00208               || (tolower(*es->p) == 'f' && allow_hex)))
00209         {
00210           last_char = tolower(*es->p);
00211           if (*es->p == 'x' || *es->p == 'X')
00212             allow_hex = TRUE;
00213           *ptok_buf++ = *es->p++;
00214         }
00215       break;
00216     case tok_plus:
00217     case tok_minus:
00218     case tok_mult:
00219     case tok_div:
00220     case tok_oparen:
00221     case tok_cparen:
00222       /* just pass on the token */
00223       break;
00224     default:
00225       tok = tok_invalid;
00226       break;
00227     }
00228 
00229   /* terminate the token string buffer */
00230   *ptok_buf = '\0';
00231 
00232   return tok;
00233 }
00234 
00235 /* peek ahead at the next token from the expression stream, currently
00236    only the next token can be peek'ed at */
00237 static enum eval_token_t                 /* next token in expression */
00238 peek_next_token(struct eval_state_t *es) /* expression evalutor */
00239 {
00240   /* if there is no peek ahead token, get one */
00241   if (es->peek_tok == tok_invalid)
00242     {
00243       es->lastp = es->p;
00244       es->peek_tok = get_next_token(es);
00245     }
00246 
00247   /* return peek ahead token */
00248   return es->peek_tok;
00249 }
00250 
00251 /* forward declaration */
00252 static struct eval_value_t expr(struct eval_state_t *es);
00253 
00254 /* default expression error value, eval_err is also set */
00255 static struct eval_value_t err_value = { et_int, { 0 } };
00256 
00257 /* expression type strings */
00258 char *eval_type_str[et_NUM] = {
00259   /* et_int */          "int",
00260   /* et_uint */         "unsigned int",
00261   /* et_addr */         "md_addr_t",
00262 #ifdef HOST_HAS_QWORD
00263   /* et_qword */        "qword_t",
00264   /* et_sqword */       "sqword_t",
00265 #endif /* HOST_HAS_QWORD */
00266   /* et_float */        "float",
00267   /* et_double */       "double",
00268   /* et_symbol */       "symbol"
00269 };
00270 
00271 /* determine necessary arithmetic conversion on T1 <op> T2 */
00272 static enum eval_type_t                 /* type of expression result */
00273 result_type(enum eval_type_t t1,        /* left operand type */
00274             enum eval_type_t t2)        /* right operand type */
00275 {
00276   /* sanity check, symbols should not show up in arithmetic exprs */
00277   if (t1 == et_symbol || t2 == et_symbol)
00278     panic("symbol used in expression");
00279 
00280   /* using C rules, i.e., A6.5 */
00281   if (t1 == et_double || t2 == et_double)
00282     return et_double;
00283   else if (t1 == et_float || t2 == et_float)
00284     return et_float;
00285 #ifdef HOST_HAS_QWORD
00286   else if (t1 == et_qword || t2 == et_qword)
00287     return et_qword;
00288   else if (t1 == et_sqword || t2 == et_sqword)
00289     return et_sqword;
00290 #endif /* HOST_HAS_QWORD */
00291   else if (t1 == et_addr || t2 == et_addr)
00292     return et_addr;
00293   else if (t1 == et_uint || t2 == et_uint)
00294     return et_uint;
00295   else
00296     return et_int;
00297 }
00298 
00299 /*
00300  * expression value arithmetic conversions
00301  */
00302 
00303 /* eval_value_t (any numeric type) -> double */
00304 double
00305 eval_as_double(struct eval_value_t val)
00306 {
00307   switch (val.type)
00308     {
00309     case et_double:
00310       return val.value.as_double;
00311     case et_float:
00312       return (double)val.value.as_float;
00313 #ifdef HOST_HAS_QWORD
00314     case et_qword:
00315 #ifdef _MSC_VER /* FIXME: MSC does not implement qword_t to dbl conversion */
00316       return (double)(sqword_t)val.value.as_qword;
00317 #else /* !_MSC_VER */
00318       return (double)val.value.as_qword;
00319 #endif /* _MSC_VER */
00320     case et_sqword:
00321       return (double)val.value.as_sqword;
00322 #endif /* HOST_HAS_QWORD */
00323     case et_addr:
00324 #if defined(_MSC_VER) && defined(TARGET_ALPHA)
00325       /* FIXME: MSC does not implement qword_t to double conversion */
00326       return (double)(sqword_t)val.value.as_addr;
00327 #else
00328       return (double)val.value.as_addr;
00329 #endif
00330     case et_uint:
00331       return (double)val.value.as_uint;
00332     case et_int:
00333       return (double)val.value.as_int;
00334     case et_symbol:
00335       panic("symbol used in expression");
00336     default:
00337       panic("illegal arithmetic expression conversion");
00338     }
00339 }
00340 
00341 /* eval_value_t (any numeric type) -> float */
00342 float
00343 eval_as_float(struct eval_value_t val)
00344 {
00345   switch (val.type)
00346     {
00347     case et_double:
00348       return (float)val.value.as_double;
00349     case et_float:
00350       return val.value.as_float;
00351 #ifdef HOST_HAS_QWORD
00352     case et_qword:
00353 #ifdef _MSC_VER /* FIXME: MSC does not implement qword_t to dbl conversion */
00354       return (float)(sqword_t)val.value.as_qword;
00355 #else /* !_MSC_VER */
00356       return (float)val.value.as_qword;
00357 #endif /* _MSC_VER */
00358     case et_sqword:
00359       return (float)val.value.as_sqword;
00360 #endif /* HOST_HAS_QWORD */
00361     case et_addr:
00362 #if defined(_MSC_VER) && defined(TARGET_ALPHA)
00363       /* FIXME: MSC does not implement qword_t to double conversion */
00364       return (float)(sqword_t)val.value.as_addr;
00365 #else
00366       return (float)val.value.as_addr;
00367 #endif
00368     case et_uint:
00369       return (float)val.value.as_uint;
00370     case et_int:
00371       return (float)val.value.as_int;
00372     case et_symbol:
00373       panic("symbol used in expression");
00374     default:
00375       panic("illegal arithmetic expression conversion");
00376     }
00377 }
00378 
00379 #ifdef HOST_HAS_QWORD
00380 /* eval_value_t (any numeric type) -> qword_t */
00381 qword_t
00382 eval_as_qword(struct eval_value_t val)
00383 {
00384   switch (val.type)
00385     {
00386     case et_double:
00387       return (qword_t)val.value.as_double;
00388     case et_float:
00389       return (qword_t)val.value.as_float;
00390     case et_qword:
00391       return val.value.as_qword;
00392     case et_sqword:
00393       return (qword_t)val.value.as_sqword;
00394     case et_addr:
00395       return (qword_t)val.value.as_addr;
00396     case et_uint:
00397       return (qword_t)val.value.as_uint;
00398     case et_int:
00399       return (qword_t)val.value.as_int;
00400     case et_symbol:
00401       panic("symbol used in expression");
00402     default:
00403       panic("illegal arithmetic expression conversion");
00404     }
00405 }
00406 
00407 /* eval_value_t (any numeric type) -> sqword_t */
00408 sqword_t
00409 eval_as_sqword(struct eval_value_t val)
00410 {
00411   switch (val.type)
00412     {
00413     case et_double:
00414       return (sqword_t)val.value.as_double;
00415     case et_float:
00416       return (sqword_t)val.value.as_float;
00417     case et_qword:
00418       return (sqword_t)val.value.as_qword;
00419     case et_sqword:
00420       return val.value.as_sqword;
00421     case et_addr:
00422       return (sqword_t)val.value.as_addr;
00423     case et_uint:
00424       return (sqword_t)val.value.as_uint;
00425     case et_int:
00426       return (sqword_t)val.value.as_int;
00427     case et_symbol:
00428       panic("symbol used in expression");
00429     default:
00430       panic("illegal arithmetic expression conversion");
00431     }
00432 }
00433 #endif /* HOST_HAS_QWORD */
00434 
00435 /* eval_value_t (any numeric type) -> unsigned int */
00436 md_addr_t
00437 eval_as_addr(struct eval_value_t val)
00438 {
00439   switch (val.type)
00440     {
00441     case et_double:
00442       return (md_addr_t)val.value.as_double;
00443     case et_float:
00444       return (md_addr_t)val.value.as_float;
00445 #ifdef HOST_HAS_QWORD
00446     case et_qword:
00447       return (md_addr_t)val.value.as_qword;
00448     case et_sqword:
00449       return (md_addr_t)val.value.as_sqword;
00450 #endif /* HOST_HAS_QWORD */
00451     case et_addr:
00452       return val.value.as_addr;
00453     case et_uint:
00454       return (md_addr_t)val.value.as_uint;
00455     case et_int:
00456       return (md_addr_t)val.value.as_int;
00457     case et_symbol:
00458       panic("symbol used in expression");
00459     default:
00460       panic("illegal arithmetic expression conversion");
00461     }
00462 }
00463 
00464 /* eval_value_t (any numeric type) -> unsigned int */
00465 unsigned int
00466 eval_as_uint(struct eval_value_t val)
00467 {
00468   switch (val.type)
00469     {
00470     case et_double:
00471       return (unsigned int)val.value.as_double;
00472     case et_float:
00473       return (unsigned int)val.value.as_float;
00474 #ifdef HOST_HAS_QWORD
00475     case et_qword:
00476       return (unsigned int)val.value.as_qword;
00477     case et_sqword:
00478       return (unsigned int)val.value.as_sqword;
00479 #endif /* HOST_HAS_QWORD */
00480     case et_addr:
00481       return (unsigned int)val.value.as_addr;
00482     case et_uint:
00483       return val.value.as_uint;
00484     case et_int:
00485       return (unsigned int)val.value.as_int;
00486     case et_symbol:
00487       panic("symbol used in expression");
00488     default:
00489       panic("illegal arithmetic expression conversion");
00490     }
00491 }
00492 
00493 /* eval_value_t (any numeric type) -> int */
00494 int
00495 eval_as_int(struct eval_value_t val)
00496 {
00497   switch (val.type)
00498     {
00499     case et_double:
00500       return (int)val.value.as_double;
00501     case et_float:
00502       return (int)val.value.as_float;
00503 #ifdef HOST_HAS_QWORD
00504     case et_qword:
00505       return (int)val.value.as_qword;
00506     case et_sqword:
00507       return (int)val.value.as_sqword;
00508 #endif /* HOST_HAS_QWORD */
00509     case et_addr:
00510       return (int)val.value.as_addr;
00511     case et_uint:
00512       return (int)val.value.as_uint;
00513     case et_int:
00514       return val.value.as_int;
00515     case et_symbol:
00516       panic("symbol used in expression");
00517     default:
00518       panic("illegal arithmetic expression conversion");
00519     }
00520 }
00521 
00522 /*
00523  * arithmetic intrinsics operations, used during expression evaluation
00524  */
00525 
00526 /* compute <val1> + <val2> */
00527 static struct eval_value_t
00528 f_add(struct eval_value_t val1, struct eval_value_t val2)
00529 {
00530   enum eval_type_t et;
00531   struct eval_value_t val;
00532 
00533   /* symbols are not allowed in arithmetic expressions */
00534   if (val1.type == et_symbol || val2.type == et_symbol)
00535     {
00536       eval_error = ERR_BADEXPR;
00537       return err_value;
00538     }
00539 
00540   /* get result type, and perform operation in that type */
00541   et = result_type(val1.type, val2.type);
00542   switch (et)
00543     {
00544     case et_double:
00545       val.type = et_double;
00546       val.value.as_double = eval_as_double(val1) + eval_as_double(val2);
00547       break;
00548     case et_float:
00549       val.type = et_float;
00550       val.value.as_float = eval_as_float(val1) + eval_as_float(val2);
00551       break;
00552 #ifdef HOST_HAS_QWORD
00553     case et_qword:
00554       val.type = et_qword;
00555       val.value.as_qword = eval_as_qword(val1) + eval_as_qword(val2);
00556       break;
00557     case et_sqword:
00558       val.type = et_sqword;
00559       val.value.as_sqword = eval_as_sqword(val1) + eval_as_sqword(val2);
00560       break;
00561 #endif /* HOST_HAS_QWORD */
00562     case et_addr:
00563       val.type = et_addr;
00564       val.value.as_addr = eval_as_addr(val1) + eval_as_addr(val2);
00565       break;
00566     case et_uint:
00567       val.type = et_uint;
00568       val.value.as_uint = eval_as_uint(val1) + eval_as_uint(val2);
00569       break;
00570     case et_int:
00571       val.type = et_int;
00572       val.value.as_int = eval_as_int(val1) + eval_as_int(val2);
00573       break;
00574     default:
00575       panic("bogus expression type");
00576     }
00577 
00578   return val;
00579 }
00580 
00581 /* compute <val1> - <val2> */
00582 static struct eval_value_t
00583 f_sub(struct eval_value_t val1, struct eval_value_t val2)
00584 {
00585   enum eval_type_t et;
00586   struct eval_value_t val;
00587 
00588   /* symbols are not allowed in arithmetic expressions */
00589   if (val1.type == et_symbol || val2.type == et_symbol)
00590     {
00591       eval_error = ERR_BADEXPR;
00592       return err_value;
00593     }
00594 
00595   /* get result type, and perform operation in that type */
00596   et = result_type(val1.type, val2.type);
00597   switch (et)
00598     {
00599     case et_double:
00600       val.type = et_double;
00601       val.value.as_double = eval_as_double(val1) - eval_as_double(val2);
00602       break;
00603     case et_float:
00604       val.type = et_float;
00605       val.value.as_float = eval_as_float(val1) - eval_as_float(val2);
00606       break;
00607 #ifdef HOST_HAS_QWORD
00608     case et_qword:
00609       val.type = et_qword;
00610       val.value.as_qword = eval_as_qword(val1) - eval_as_qword(val2);
00611       break;
00612     case et_sqword:
00613       val.type = et_sqword;
00614       val.value.as_sqword = eval_as_sqword(val1) - eval_as_sqword(val2);
00615       break;
00616 #endif /* HOST_HAS_QWORD */
00617     case et_addr:
00618       val.type = et_addr;
00619       val.value.as_addr = eval_as_addr(val1) - eval_as_addr(val2);
00620       break;
00621     case et_uint:
00622       val.type = et_uint;
00623       val.value.as_uint = eval_as_uint(val1) - eval_as_uint(val2);
00624       break;
00625     case et_int:
00626       val.type = et_int;
00627       val.value.as_int = eval_as_int(val1) - eval_as_int(val2);
00628       break;
00629     default:
00630       panic("bogus expression type");
00631     }
00632 
00633   return val;
00634 }
00635 
00636 /* compute <val1> * <val2> */
00637 static struct eval_value_t
00638 f_mult(struct eval_value_t val1, struct eval_value_t val2)
00639 {
00640   enum eval_type_t et;
00641   struct eval_value_t val;
00642 
00643   /* symbols are not allowed in arithmetic expressions */
00644   if (val1.type == et_symbol || val2.type == et_symbol)
00645     {
00646       eval_error = ERR_BADEXPR;
00647       return err_value;
00648     }
00649 
00650   /* get result type, and perform operation in that type */
00651   et = result_type(val1.type, val2.type);
00652   switch (et)
00653     {
00654     case et_double:
00655       val.type = et_double;
00656       val.value.as_double = eval_as_double(val1) * eval_as_double(val2);
00657       break;
00658     case et_float:
00659       val.type = et_float;
00660       val.value.as_float = eval_as_float(val1) * eval_as_float(val2);
00661       break;
00662 #ifdef HOST_HAS_QWORD
00663     case et_qword:
00664       val.type = et_qword;
00665       val.value.as_qword = eval_as_qword(val1) * eval_as_qword(val2);
00666       break;
00667     case et_sqword:
00668       val.type = et_sqword;
00669       val.value.as_sqword = eval_as_sqword(val1) * eval_as_sqword(val2);
00670       break;
00671 #endif /* HOST_HAS_QWORD */
00672     case et_addr:
00673       val.type = et_addr;
00674       val.value.as_addr = eval_as_addr(val1) * eval_as_addr(val2);
00675       break;
00676     case et_uint:
00677       val.type = et_uint;
00678       val.value.as_uint = eval_as_uint(val1) * eval_as_uint(val2);
00679       break;
00680     case et_int:
00681       val.type = et_int;
00682       val.value.as_int = eval_as_int(val1) * eval_as_int(val2);
00683       break;
00684     default:
00685       panic("bogus expression type");
00686     }
00687 
00688   return val;
00689 }
00690 
00691 /* compute <val1> / <val2> */
00692 static struct eval_value_t
00693 f_div(struct eval_value_t val1, struct eval_value_t val2)
00694 {
00695   enum eval_type_t et;
00696   struct eval_value_t val;
00697 
00698   /* symbols are not allowed in arithmetic expressions */
00699   if (val1.type == et_symbol || val2.type == et_symbol)
00700     {
00701       eval_error = ERR_BADEXPR;
00702       return err_value;
00703     }
00704 
00705   /* get result type, and perform operation in that type */
00706   et = result_type(val1.type, val2.type);
00707   switch (et)
00708     {
00709     case et_double:
00710       val.type = et_double;
00711       val.value.as_double = eval_as_double(val1) / eval_as_double(val2);
00712       break;
00713     case et_float:
00714       val.type = et_float;
00715       val.value.as_float = eval_as_float(val1) / eval_as_float(val2);
00716       break;
00717 #ifdef HOST_HAS_QWORD
00718     case et_qword:
00719       val.type = et_qword;
00720       val.value.as_qword = eval_as_qword(val1) / eval_as_qword(val2);
00721       break;
00722     case et_sqword:
00723       val.type = et_sqword;
00724       val.value.as_sqword = eval_as_sqword(val1) / eval_as_sqword(val2);
00725       break;
00726 #endif /* HOST_HAS_QWORD */
00727     case et_addr:
00728       val.type = et_addr;
00729       val.value.as_addr = eval_as_addr(val1) / eval_as_addr(val2);
00730       break;
00731     case et_uint:
00732       val.type = et_uint;
00733       val.value.as_uint = eval_as_uint(val1) / eval_as_uint(val2);
00734       break;
00735     case et_int:
00736       val.type = et_int;
00737       val.value.as_int = eval_as_int(val1) / eval_as_int(val2);
00738       break;
00739     default:
00740       panic("bogus expression type");
00741     }
00742 
00743   return val;
00744 }
00745 
00746 /* compute - <val1> */
00747 static struct eval_value_t
00748 f_neg(struct eval_value_t val1)
00749 {
00750   struct eval_value_t val;
00751 
00752   /* symbols are not allowed in arithmetic expressions */
00753   if (val1.type == et_symbol)
00754     {
00755       eval_error = ERR_BADEXPR;
00756       return err_value;
00757     }
00758 
00759   /* result type is the same as the operand type */
00760   switch (val1.type)
00761     {
00762     case et_double:
00763       val.type = et_double;
00764       val.value.as_double = - val1.value.as_double;
00765       break;
00766     case et_float:
00767       val.type = et_float;
00768       val.value.as_float = - val1.value.as_float;
00769       break;
00770 #ifdef HOST_HAS_QWORD
00771     case et_qword:
00772       val.type = et_sqword;
00773       val.value.as_qword = - (sqword_t)val1.value.as_qword;
00774       break;
00775     case et_sqword:
00776       val.type = et_sqword;
00777       val.value.as_sqword = - val1.value.as_sqword;
00778       break;
00779 #endif /* HOST_HAS_QWORD */
00780     case et_addr:
00781       val.type = et_addr;
00782       val.value.as_addr = - val1.value.as_addr;
00783       break;
00784     case et_uint:
00785       if ((unsigned int)val1.value.as_uint > 2147483648U)
00786         {
00787           /* promote type */
00788 #ifdef HOST_HAS_QWORD
00789           val.type = et_sqword;
00790           val.value.as_sqword = - ((sqword_t)val1.value.as_uint);
00791 #else /* !HOST_HAS_QWORD */
00792           val.type = et_double;
00793           val.value.as_double = - ((double)val1.value.as_uint);
00794 #endif /* HOST_HAS_QWORD */
00795         }
00796       else
00797         {
00798           /* don't promote type */
00799           val.type = et_int;
00800           val.value.as_int = - ((int)val1.value.as_uint);
00801         }
00802       break;
00803     case et_int:
00804       if ((unsigned int)val1.value.as_int == 0x80000000U)
00805         {
00806           /* promote type */
00807           val.type = et_uint;
00808           val.value.as_uint = 2147483648U;
00809         }
00810       else
00811         {
00812           /* don't promote type */
00813           val.type = et_int;
00814           val.value.as_int = - val1.value.as_int;
00815         }
00816       break;
00817     default:
00818       panic("bogus expression type");
00819     }
00820 
00821   return val;
00822 }
00823 
00824 /* compute val1 == 0 */
00825 static int
00826 f_eq_zero(struct eval_value_t val1)
00827 {
00828   int val;
00829 
00830   /* symbols are not allowed in arithmetic expressions */
00831   if (val1.type == et_symbol)
00832     {
00833       eval_error = ERR_BADEXPR;
00834       return FALSE;
00835     }
00836 
00837   switch (val1.type)
00838     {
00839     case et_double:
00840       val = val1.value.as_double == 0.0;
00841       break;
00842     case et_float:
00843       val = val1.value.as_float == 0.0;
00844       break;
00845 #ifdef HOST_HAS_QWORD
00846     case et_qword:
00847       val = val1.value.as_qword == 0;
00848       break;
00849     case et_sqword:
00850       val = val1.value.as_sqword == 0;
00851       break;
00852 #endif /* HOST_HAS_QWORD */
00853     case et_addr:
00854       val = val1.value.as_addr == 0;
00855       break;
00856     case et_uint:
00857       val = val1.value.as_uint == 0;
00858       break;
00859     case et_int:
00860       val = val1.value.as_int == 0;
00861       break;
00862     default:
00863       panic("bogus expression type");
00864     }
00865 
00866   return val;
00867 }
00868 
00869 /* evaluate the value of the numeric literal constant in ES->TOK_BUF,
00870    eval_err is set to a value other than ERR_NOERR if the constant cannot
00871    be parsed and converted to an expression value */
00872 static struct eval_value_t              /* value of the literal constant */
00873 constant(struct eval_state_t *es)       /* expression evaluator */
00874 {
00875   struct eval_value_t val;
00876   int int_val;
00877   unsigned int uint_val;
00878   double double_val;
00879   char *endp;
00880 #ifdef HOST_HAS_QWORD
00881   sqword_t sqword_val;
00882   qword_t qword_val;
00883 #endif /* HOST_HAS_QWORD */
00884 
00885 #if !defined(__CYGWIN32__)
00886   extern int errno;
00887 #endif
00888 #if 0 /* no longer needed... */
00889 #if defined(sparc) && !defined(__svr4__)
00890   extern long strtol(char *, char **, int);
00891   extern double strtod(char *, char **);
00892 #endif /* sparc */
00893 #endif
00894 
00895   /*
00896    * attempt multiple conversions, from least to most precise, using
00897    * the value returned when the conversion is successful
00898    */
00899 
00900   /* attempt integer conversion */
00901   errno = 0;
00902   int_val = strtol(es->tok_buf, &endp, /* parse base */0);
00903   if (!errno && !*endp)
00904     {
00905       /* good conversion */
00906       val.type = et_int;
00907       val.value.as_int = int_val;
00908       return val;
00909     }
00910 
00911   /* else, not an integer, attempt unsigned int conversion */
00912   errno = 0;
00913   uint_val = strtoul(es->tok_buf, &endp, /* parse base */0);
00914   if (!errno && !*endp)
00915     {
00916       /* good conversion */
00917       val.type = et_uint;
00918       val.value.as_uint = uint_val;
00919       return val;
00920     }
00921 
00922 #ifdef HOST_HAS_QWORD
00923   /* else, not an int/uint, attempt sqword_t conversion */
00924   errno = 0;
00925   sqword_val = myatosq(es->tok_buf, &endp, /* parse base */0);
00926   if (!errno && !*endp)
00927     {
00928       /* good conversion */
00929       val.type = et_sqword;
00930       val.value.as_sqword = sqword_val;
00931       return val;
00932     }
00933 
00934   /* else, not an sqword_t, attempt qword_t conversion */
00935   errno = 0;
00936   qword_val = myatoq(es->tok_buf, &endp, /* parse base */0);
00937   if (!errno && !*endp)
00938     {
00939       /* good conversion */
00940       val.type = et_qword;
00941       val.value.as_qword = qword_val;
00942       return val;
00943     }
00944 #endif /* HOST_HAS_QWORD */
00945 
00946   /* else, not any type of integer, attempt double conversion (NOTE: no
00947      reliable float conversion is available on all machines) */
00948   errno = 0;
00949   double_val = strtod(es->tok_buf, &endp);
00950   if (!errno && !*endp)
00951     {
00952       /* good conversion */
00953       val.type = et_double;
00954       val.value.as_double = double_val;
00955       return val;
00956     }
00957 
00958   /* else, not a double value, therefore, could not convert constant,
00959      declare an error */
00960   eval_error = ERR_BADCONST;
00961   return err_value;
00962 }
00963 
00964 /* evaluate an expression factor, eval_err will indicate it any
00965    expression evaluation occurs */
00966 static struct eval_value_t              /* value of factor */
00967 factor(struct eval_state_t *es)         /* expression evaluator */
00968 {
00969   enum eval_token_t tok;
00970   struct eval_value_t val;
00971 
00972   tok = peek_next_token(es);
00973   switch (tok)
00974     {
00975     case tok_oparen:
00976       (void)get_next_token(es);
00977       val = expr(es);
00978       if (eval_error)
00979         return err_value;
00980 
00981       tok = peek_next_token(es);
00982       if (tok != tok_cparen)
00983         {
00984           eval_error = ERR_UPAREN;
00985           return err_value;
00986         }
00987       (void)get_next_token(es);
00988       break;
00989 
00990     case tok_minus:
00991       /* negation operator */
00992       (void)get_next_token(es);
00993       val = factor(es);
00994       if (eval_error)
00995         return err_value;
00996       val = f_neg(val);
00997       break;
00998 
00999     case tok_ident:
01000       (void)get_next_token(es);
01001       /* evaluate the identifier in TOK_BUF */
01002       val = es->f_eval_ident(es);
01003       if (eval_error)
01004         return err_value;
01005       break;
01006 
01007     case tok_const:
01008       (void)get_next_token(es);
01009       val = constant(es);
01010       if (eval_error)
01011         return err_value;
01012       break;
01013 
01014     default:
01015       eval_error = ERR_NOTERM;
01016       return err_value;
01017     }
01018 
01019   return val;
01020 }
01021 
01022 /* evaluate an expression term, eval_err will indicate it any
01023    expression evaluation occurs */
01024 static struct eval_value_t              /* value to expression term */
01025 term(struct eval_state_t *es)           /* expression evaluator */
01026 {
01027   enum eval_token_t tok;
01028   struct eval_value_t val, val1;
01029 
01030   val = factor(es);
01031   if (eval_error)
01032     return err_value;
01033 
01034   tok = peek_next_token(es);
01035   switch (tok)
01036     {
01037     case tok_mult:
01038       (void)get_next_token(es);
01039       val = f_mult(val, term(es));
01040       if (eval_error)
01041         return err_value;
01042       break;
01043 
01044     case tok_div:
01045       (void)get_next_token(es);
01046       val1 = term(es);
01047       if (eval_error)
01048         return err_value;
01049       if (f_eq_zero(val1))
01050         {
01051           eval_error = ERR_DIV0;
01052           return err_value;
01053         }
01054       val = f_div(val, val1);
01055       break;
01056 
01057     default:;
01058     }
01059 
01060   return val;
01061 }
01062 
01063 /* evaluate an expression, eval_err will indicate it any expression
01064    evaluation occurs */
01065 static struct eval_value_t              /* value of the expression */
01066 expr(struct eval_state_t *es)           /* expression evaluator */
01067 {
01068   enum eval_token_t tok;
01069   struct eval_value_t val;
01070 
01071   val = term(es);
01072   if (eval_error)
01073     return err_value;
01074 
01075   tok = peek_next_token(es);
01076   switch (tok)
01077     {
01078     case tok_plus:
01079       (void)get_next_token(es);
01080       val = f_add(val, expr(es));
01081       if (eval_error)
01082         return err_value;
01083       break;
01084 
01085     case tok_minus:
01086       (void)get_next_token(es);
01087       val = f_sub(val, expr(es));
01088       if (eval_error)
01089         return err_value;
01090       break;
01091 
01092     default:;
01093     }
01094 
01095   return val;
01096 }
01097 
01098 /* create an evaluator */
01099 struct eval_state_t *                   /* expression evaluator */
01100 eval_new(eval_ident_t f_eval_ident,     /* user ident evaluator */
01101          void *user_ptr)                /* user ptr passed to ident fn */
01102 {
01103   struct eval_state_t *es;
01104 
01105   es = calloc(1, sizeof(struct eval_state_t));
01106   if (!es)
01107     fatal("out of virtual memory");
01108 
01109   es->f_eval_ident = f_eval_ident;
01110   es->user_ptr = user_ptr;
01111 
01112   return es;
01113 }
01114 
01115 /* delete an evaluator */
01116 void
01117 eval_delete(struct eval_state_t *es)    /* evaluator to delete */
01118 {
01119   free(es);
01120 }
01121 
01122 /* evaluate an expression, if an error occurs during evaluation, the
01123    global variable eval_error will be set to a value other than ERR_NOERR */
01124 struct eval_value_t                     /* value of the expression */
01125 eval_expr(struct eval_state_t *es,      /* expression evaluator */
01126           char *p,                      /* ptr to expression string */
01127           char **endp)                  /* returns ptr to 1st unused char */
01128 {
01129   struct eval_value_t val;
01130 
01131   /* initialize the evaluator state */
01132   eval_error = ERR_NOERR;
01133   es->p = p;
01134   *es->tok_buf = '\0';
01135   es->peek_tok = tok_invalid;
01136 
01137   /* evaluate the expression */
01138   val = expr(es);
01139 
01140   /* return a pointer to the first character not used in the expression */
01141   if (endp)
01142     {
01143       if (es->peek_tok != tok_invalid)
01144         {
01145           /* did not consume peek'ed token, so return last p */
01146           *endp = es->lastp;
01147         }
01148       else
01149         *endp = es->p;
01150     }
01151 
01152   return val;
01153 }
01154 
01155 /* print an expression value */
01156 void
01157 eval_print(FILE *stream,                /* output stream */
01158            struct eval_value_t val)     /* expression value to print */
01159 {
01160   switch (val.type)
01161     {
01162     case et_double:
01163       fprintf(stream, "%f [double]", val.value.as_double);
01164       break;
01165     case et_float:
01166       fprintf(stream, "%f [float]", (double)val.value.as_float);
01167       break;
01168 #ifdef HOST_HAS_QWORD
01169     case et_qword:
01170       myfprintf(stream, "%lu [qword_t]", val.value.as_qword);
01171       break;
01172     case et_sqword:
01173       myfprintf(stream, "%ld [sqword_t]", val.value.as_sqword);
01174       break;
01175 #endif /* HOST_HAS_QWORD */
01176     case et_addr:
01177       myfprintf(stream, "0x%p [md_addr_t]", val.value.as_addr);
01178       break;
01179     case et_uint:
01180       fprintf(stream, "%u [uint]", val.value.as_uint);
01181       break;
01182     case et_int:
01183       fprintf(stream, "%d [int]", val.value.as_int);
01184       break;
01185     case et_symbol:
01186       fprintf(stream, "\"%s\" [symbol]", val.value.as_symbol);
01187       break;
01188     default:
01189       panic("bogus expression type");
01190     }
01191 }
01192 
01193 
01194 #ifdef TEST
01195 
01196 static struct eval_value_t an_int;
01197 static struct eval_value_t a_uint;
01198 static struct eval_value_t a_float;
01199 static struct eval_value_t a_double;
01200 static struct eval_value_t a_symbol;
01201 
01202 struct sym_map_t {
01203   char *symbol;
01204   struct eval_value_t *value;
01205 };
01206 
01207 static struct sym_map_t sym_map[] = {
01208   { "an_int", &an_int },
01209   { "a_uint", &a_uint },
01210   { "a_float", &a_float },
01211   { "a_double", &a_double },
01212   { "a_symbol", &a_symbol },
01213   { NULL, NULL },
01214 };
01215 
01216 struct eval_value_t
01217 my_eval_ident(struct eval_state_t *es)
01218 {
01219   struct sym_map_t *sym;
01220 
01221   for (sym=sym_map; sym->symbol != NULL; sym++)
01222     {
01223       if (!strcmp(sym->symbol, es->tok_buf))
01224         return *sym->value;
01225     }
01226 
01227   eval_error = ERR_UNDEFVAR;
01228   return err_value;
01229 }
01230 
01231 void
01232 main(void)
01233 {
01234   struct eval_state_t *es;
01235 
01236   /* set up test variables */
01237   an_int.type = et_int; an_int.value.as_int = 1;
01238   a_uint.type = et_uint; a_uint.value.as_uint = 2;
01239   a_float.type = et_float; a_float.value.as_float = 3.0f;
01240   a_double.type = et_double; a_double.value.as_double = 4.0;
01241   a_symbol.type = et_symbol; a_symbol.value.as_symbol = "testing 1 2 3...";
01242 
01243   /* instantiate an evaluator */
01244   es = eval_new(my_eval_ident, NULL);
01245 
01246   while (1)
01247     {
01248       struct eval_value_t val;
01249       char expr_buf[1024];
01250 
01251       fgets(expr_buf, 1024, stdin);
01252 
01253       /* chop */
01254       if (expr_buf[strlen(expr_buf)-1] == '\n')
01255         expr_buf[strlen(expr_buf)-1] = '\0';
01256 
01257       if (expr_buf[0] == '\0')
01258         exit(0);
01259 
01260       val = eval_expr(es, expr_buf, NULL);
01261       if (eval_error)
01262         fprintf(stdout, "eval error: %s\n", eval_err_str[eval_error]);
01263       else
01264         {
01265           fprintf(stdout, "%s == ", expr_buf);
01266           eval_print(stdout, val);
01267           fprintf(stdout, "\n");
01268         }
01269     }
01270 }
01271 
01272 #endif /* TEST */


UVa CS Department of Computer Science
School of Engineering, University of Virginia
151 Engineer's Way, P.O. Box 400740
Charlottesville, Virginia 22904-4740

(434) 982-2200  Fax: (434) 982-2214