#include #include #include #include #include #include "util.h" #include #include using namespace std; enum TOKEN { TOK_END, TOK_INVAL, TOK_PLUS, TOK_MINUS, TOK_MULT, TOK_DIV, TOK_MODULO, TOK_OPNPAR, TOK_CLSPAR, TOK_VAR, TOK_NUM, TOK_FUNC, }; struct ELM{ TOKEN tok; string val; double res; ELM(TOKEN _tok, const string &_val, double _res){ tok = _tok; val = _val; res = _res; } ELM(TOKEN _tok, const char *_val){ tok = _tok; val = _val; res = 0; } ELM(TOKEN _tok, const char _val){ tok = _tok; val = _val; res = 0; } void inval(){ tok = TOK_INVAL; val = ""; res = 0; } }; struct PARSER{ string expr; const char *pt; map vars; PARSER (const string &_expr){ expr = _expr; pt = expr.c_str(); } void setvar(const char *name, double val){ vars[name] = val; } ELM get(){ pt = str_skip(pt); if (*pt == '$' || *pt == '\0'){ return ELM(TOK_END,'\0'); }else if (*pt == '('){ pt++; return ELM(TOK_OPNPAR,'('); }else if (*pt == ')'){ pt++; return ELM(TOK_CLSPAR,')'); }else if (*pt == '+'){ pt++; return ELM(TOK_PLUS,'+'); }else if (*pt == '-'){ pt++; return ELM(TOK_MINUS,'-'); }else if (*pt == '/'){ pt++; return ELM(TOK_DIV,'/'); }else if (*pt == '*'){ pt++; return ELM(TOK_MULT,'*'); }else if (*pt == '%'){ pt++; return ELM(TOK_MODULO,'%'); }else if (isalpha(*pt)){ const char *start = pt; while (isalpha(*pt) || isdigit(*pt)) pt++; string tmp(start,pt-start); if (tmp == "sin"){ return ELM(TOK_FUNC,"sin"); }else if (tmp == "cos"){ return ELM(TOK_FUNC,"cos"); }else if (tmp == "tan"){ return ELM(TOK_FUNC,"tan"); } return ELM(TOK_VAR,tmp,vars[tmp]); }else if (isdigit(*pt) || *pt == '-'){ const char *start = pt; pt++; while (isdigit(*pt) || *pt == '.') pt++; string tmp(start,pt-start); return ELM(TOK_NUM,tmp,atof(tmp.c_str())); } return ELM(TOK_INVAL,*pt); } }; static ELM math_expr (PARSER &p, double &res); static ELM math_item (PARSER &p, double &res) { ELM e = p.get(); res = 0; if (e.tok == TOK_OPNPAR){ e = math_expr(p,res); if (e.tok == TOK_CLSPAR){ e = p.get(); }else{ e.inval(); } }else if (e.tok == TOK_NUM || e.tok == TOK_VAR){ res = e.res; e = p.get(); }else if (e.tok == TOK_FUNC){ string func = e.val; e = p.get(); if (e.tok == TOK_OPNPAR){ e = math_expr(p,res); if (e.tok == TOK_CLSPAR){ e = p.get(); if (func == "sin"){ res = sin(res); }else if (func == "cos"){ res = cos(res); }else if (func == "tan"){ res = tan(res); } }else{ e.inval(); } }else{ e.inval(); } }else{ e.inval(); } return e; } static ELM math_mult (PARSER &p, double &res) { ELM e = math_item(p,res); while (1){ if (e.tok == TOK_MULT || e.tok == TOK_DIV || e.tok == TOK_MODULO){ TOKEN tok = e.tok; double res2; e = math_item(p,res2); if (tok == TOK_MULT){ res *= res2; }else if (tok == TOK_DIV){ res /= res2; }else if (tok == TOK_MODULO){ res = ((int)res % (int)res2); } }else{ break; } } return e; } static ELM math_plus (PARSER &p, double &res) { ELM e = math_mult(p,res); while (1){ if (e.tok == TOK_PLUS || e.tok == TOK_MINUS){ TOKEN tok = e.tok; double res2; e = math_mult(p,res2); if (tok == TOK_PLUS){ res += res2; }else if (tok == TOK_MINUS){ res -= res2; } }else{ break; } } return e; } static ELM math_expr (PARSER &p, double &res) { return math_plus (p,res); } static double math_expr ( const string &line, int x, int y, int w, int h) { PARSER p (line); p.setvar ("x",x); p.setvar ("y",y); p.setvar ("w",w); p.setvar ("h",h); double res = 0; ELM e = math_expr(p,res); if (e.tok != TOK_END){ const char *start = p.expr.c_str(); fprintf (stderr,"Invalid expression %s\n" " %*s\n" ,start,(int)(p.pt-start),"^"); } return res; } string math_patch (const string &line, double x, double y, double w, double h) { string ret; size_t pos = 0; while (1){ size_t newpos = line.find("$",pos); if (newpos == string::npos){ ret += line.substr(pos); break; }else{ ret += line.substr(pos,newpos-pos); newpos++; size_t endpos = line.find("$",newpos); if (endpos == string::npos){ // No end $ break; } double res = math_expr (line.substr(newpos,endpos-newpos),x,y,w,h); char tmp[100]; snprintf (tmp,sizeof(tmp),"%lf",res); ret += tmp; pos = endpos + 1; } } return ret; } #ifdef TEST int main (int argc, char *argv[]) { for (int i=1; i