00001
00007 #ifndef ___EXPRPARSER_H___
00008 #define ___EXPRPARSER_H___
00009
00010 #include <stdio.h>
00011 #include <string>
00012 using std::string;
00013
00014 #include "../src/msg.h"
00015 #include "../src/polymorph.h"
00016
00017
00018
00038 template <class T=int>
00039 class ExprParser {
00040 public:
00043 ExprParser(const char* expr, Msg::LevelHandler<>** mhp_i=&(Msg::LevelHandler<>::default_instance()))
00044 : remaining(expr) { mhp = mhp_i; };
00045
00046 virtual ~ExprParser() { }
00047
00049
00050
00052 double cmdf() { return (double)read_float(); }
00053
00055 long cmdi() {
00056 exprtype result = read_float();
00057 if (result >= INT_MAX || result <= INT_MIN)
00058 message(Msg::Warning,"Value " + String::stringrep(double(result)) +
00059 " outside the representable range of an integer (" +
00060 String::stringrep(INT_MIN) + "," + String::stringrep(INT_MAX) +
00061 "); may cause overflow or underflow");
00062
00063 return (long)(floor(0.5+result));
00064 }
00065
00067 const char * cmds() { return getstringval(); }
00069
00073 bool consumeifpresent(string s) {
00074 if (strncmp(s.c_str(), remaining, s.length()) == 0) {
00075 remaining += s.length();
00076 return true;
00077 }
00078 return false;
00079 }
00080
00081 string whatsleft() { return string(remaining); }
00082
00084 bool empty() const { return (*remaining==0); }
00085
00086 static void message(Msg::MessageLevel m, const string& s)
00087 { if (mhp && *mhp) (**mhp)(m,s); }
00088
00090 typedef
00091 #ifndef LONG_DOUBLE_UNAVAILABLE
00092 long
00093 #endif
00094 double exprtype;
00095
00096 exprtype getnumericval();
00097
00098 protected:
00099 virtual const Typeless& getval();
00100 const char* remaining;
00101
00102 private:
00103 virtual const char* getstringval();
00104 exprtype read_float(bool warn=true);
00105 exprtype apply_op(exprtype lval, string op, exprtype rval);
00106 exprtype next_term(string previous_op="");
00107 string next_op();
00108 exprtype parse_expr();
00109 int op_has_precedence(const string& previous_op, const string& op);
00110 static Msg::LevelHandler<>** mhp;
00111 };
00112
00113
00114 template <class T>
00115 Msg::LevelHandler<>** ExprParser<T>::mhp=&(Msg::LevelHandler<>::default_instance());
00116
00117
00126 template <class T>
00127 const Typeless& ExprParser<T>::getval()
00128 {
00129 const char* str = remaining;
00130 char *rem;
00131 static Polymorph<double> numval(0.0);
00132 numval = strtod(str,&rem);
00133 remaining = rem;
00134
00135 if (str == remaining) {
00136 while (*remaining && (*remaining != ')'))
00137 remaining++;
00138 message(Msg::Error,"Can't parse expression: `" + string(str) + "'");
00139 numval=-1;
00140 }
00141
00142 return numval;
00143 }
00144
00145
00146
00155 template <class T>
00156 const char *ExprParser<T>::getstringval()
00157 {
00158 const size_t bufsize=65536;
00159 static char buf[bufsize];
00160 const char* maxbufptr=buf+bufsize;
00161
00162 char* bufptr=buf;
00163
00164 while (remaining && *remaining && bufptr<maxbufptr) {
00165
00166 while (*remaining && bufptr<maxbufptr)
00167 *(bufptr++) = *(remaining)++;
00168 }
00169 if (bufptr>=maxbufptr)
00170 message(Msg::Error,"Reached maximum string size; characters may be lost");
00171
00172 *bufptr='\0';
00173
00174 return buf;
00175 }
00176
00177
00178
00184 template <class T>
00185 typename ExprParser<T>::exprtype ExprParser<T>::getnumericval()
00186 {
00187 const char* str = remaining;
00188
00189 if (*remaining == '(') {
00190 exprtype subexpr;
00191 (remaining)++;
00192 subexpr=(parse_expr());
00193
00194 if (*remaining != ')')
00195 message(Msg::Error,"Missing right parenthesis");
00196 else
00197 (remaining)++;
00198 return subexpr;
00199 }
00200
00201 if (*remaining == '-') {
00202 (remaining)++;
00203 return -1.0*next_term();
00204 }
00205
00206 const Typeless& val = getval();
00207 if (val.isnumeric())
00208 return val.numericvalue();
00209 else
00210 message(Msg::Error,"Invalid param type in expression `" + string(str) + "'");
00211
00212 return Uninitialized;
00213 }
00214
00215
00216
00218 template <class T>
00219 typename ExprParser<T>::exprtype ExprParser<T>::apply_op(exprtype lval, string op, exprtype rval)
00220 {
00221 if (op == "+") return lval + rval;
00222 else if (op == "-") return lval - rval;
00223 else if (op == "*") return lval * rval;
00224 else if (op == "<") return lval < rval;
00225 else if (op == ">") return lval > rval;
00226 else if (op == "==") return lval == rval;
00227 else if (op == "!=") return lval != rval;
00228 else if (op == "<=") return lval <= rval;
00229 else if (op == ">=") return lval >= rval;
00230 else if (op == "<?") return std::min(lval,rval);
00231 else if (op == ">?") return std::max(lval,rval);
00232 else if (op == "@;") return lval * sin(rval);
00233 else if (op == "@:") return lval * cos(rval);
00234
00235 else if (op == "%" || op == "/") {
00236 if (rval==0) {
00237 message(Msg::Error,"Division by zero");
00238 return Uninitialized;
00239 }
00240 if (op == "/") return lval / rval;
00241 else return fmod(lval,rval);
00242 }
00243
00244 message(Msg::Error,"Unknown operator " + op);
00245 return Uninitialized;
00246 }
00247
00248
00249
00250 template <class T>
00251 int ExprParser<T>::op_has_precedence(const string& previous_op, const string& op)
00252 {
00253 (void) previous_op;
00254 return (op=="*" || op=="/" | op=="%");
00255 }
00256
00257
00258
00259 template <class T>
00260 string ExprParser<T>::next_op()
00261 {
00262 const char* start=remaining;
00263
00264 while (ispunct(*remaining) && !(*remaining=='(') && !(*remaining==':' && *(remaining+1)==':'))
00265 (remaining)++;
00266
00267 const char* end=remaining;
00268
00269 return string(start,end-start);
00270 }
00271
00272
00273
00274 template <class T>
00275 typename ExprParser<T>::exprtype ExprParser<T>::next_term(string previous_op)
00276 {
00277 exprtype lval = getnumericval();
00278 string op = next_op();
00279
00280
00281 while (op_has_precedence(previous_op, op)) {
00282 if (! *remaining) {
00283 message(Msg::Error,"Missing right value in `" + string(remaining) + "'");
00284 return lval;
00285 }
00286 lval=apply_op(lval,op,getnumericval());
00287 previous_op = op;
00288 op = next_op();
00289 }
00290 remaining -= op.length();
00291
00292 return lval;
00293 }
00294
00295
00296
00297 template <class T>
00298 typename ExprParser<T>::exprtype ExprParser<T>::parse_expr()
00299 {
00300 const char* str = remaining;
00301 exprtype lval = next_term();
00302
00303 while (*remaining && *remaining != ')') {
00304 string op= next_op();
00305
00306 if (! *remaining) {
00307 message(Msg::Error,"Missing right value in `" + string(str) + "'");
00308 return lval;
00309 }
00310
00311 lval = apply_op(lval,op,next_term(op));
00312 }
00313
00314 return lval;
00315 }
00316
00317
00318
00320 template <class T>
00321 typename ExprParser<T>::exprtype ExprParser<T>::read_float(bool warn)
00322 {
00323 const char* str = remaining;
00324 exprtype val = parse_expr();
00325
00326 if (str == remaining) {
00327 message(Msg::Error,"No number found in string: `" + string(str) + "'");
00328 return Uninitialized;
00329 }
00330
00331 if (warn && *remaining)
00332 message(Msg::Warning,"Trailing characters in expression ignored: `" + string(remaining) + "'");
00333 return val;
00334 }
00335
00336
00337
00338 #endif