diff --git a/dialogs.cpp b/dialogs.cpp index c2334704..7e434ca0 100644 --- a/dialogs.cpp +++ b/dialogs.cpp @@ -599,6 +599,68 @@ namespace dialog { reaction_t extra_options; + struct exp_parser { + string s; + int at; + exp_parser() { at = 0; } + + bool ok() { return at == isize(s); } + char next() { if(at == isize(s) || at == -1) return 0; else return s[at]; } + + bool eat(const char *c) { + int orig_at = at; + while(*c && *c == next()) at++, c++; + if(*c == 0) return true; + else at = orig_at; + return false; + } + + ld parse(int prio = 0) { + ld res; + if(eat("sin(")) res = sin(parsepar()); + else if(eat("cos(")) res = cos(parsepar()); + else if(eat("sinh(")) res = sinh(parsepar()); + else if(eat("cosh(")) res = cosh(parsepar()); + else if(eat("asin(")) res = asin(parsepar()); + else if(eat("acos(")) res = acos(parsepar()); + else if(eat("asinh(")) res = asinh(parsepar()); + else if(eat("acosh(")) res = acosh(parsepar()); + else if(eat("exp(")) res = exp(parsepar()); + else if(eat("log(")) res = log(parsepar()); + else if(next() == '(') at++, res = parsepar(); + else { + string number; + while(true) { + char c = next(); + if((c >= '0' && c <= '9') || among(c, 'e', 'p', '.')) + number += c, at++; + else break; + } + if(number == "e") res = exp(1); + else if(number == "p") res = M_PI; + else if(number == "") at = -1; + else if(number[0] >= 'a' && number[0] <= 'z') at = -1; + else { std::stringstream ss; res = 0; ss << number; ss >> res; } + } + while(true) { + if(next() == '+' && prio == 0) at++, res = res + parse(1); + else if(next() == '-' && prio == 0) at++, res = res - parse(1); + else if(next() == '*' && prio <= 1) at++, res = res * parse(2); + else if(next() == '/' && prio <= 1) at++, res = res / parse(2); + else if(next() == '^') at++, res = pow(res, parse(3)); + else break; + } + return res; + } + + ld parsepar() { + ld res = parse(); + if(next() != ')') { at = -1; return res; } + at++; + return res; + } + }; + void affect(char kind) { if(ne.intval) { @@ -607,8 +669,10 @@ namespace dialog { } else { if(kind == 's') { - ld x; - sscanf(ne.s.c_str(), LDF, &x); + exp_parser ep; + ep.s = ne.s; + ld x = ep.parse(); + if(!ep.ok()) return; if(ne.sc.positive && x <= 0) return; *ne.editwhat = x; } @@ -730,7 +794,7 @@ namespace dialog { keyhandler = [] (int sym, int uni) { handleNavigation(sym, uni); - if((uni >= '0' && uni <= '9') || (uni == '.' && !ne.intval) || (uni == '-' && !ne.sc.positive)) { + if((uni >= '0' && uni <= '9') || (uni == '.' && !ne.intval) || among(uni, '+', '-', '*', '/', '^', '(', ')') || (uni >= 'a' && uni <= 'z')) { ne.s += uni; affect('s'); }