diff --git a/commandline.cpp b/commandline.cpp index e29dda53..bb9fb609 100644 --- a/commandline.cpp +++ b/commandline.cpp @@ -79,7 +79,15 @@ EX namespace arg { EX const char* argcs() { return args().c_str(); } EX int argi() { return atoi(argcs()); } EX unsigned arghex() { return strtoll(argcs(), NULL, 16); } - EX ld argf() { return parseld(args()); } + EX ld argf() { + try { + return parseld(args()); + } + catch(hr_parse_exception& ex) { + println(hlog, "error parsing commandline parameters: ", ex.s); + exit(1); + } + } EX bool argis(const string& s) { if(args()[0] == '-' && args()[1] == '-') return args().substr(1) == s; return args() == s; } EX void shift_arg_formula(ld& x, const reaction_t& r IS(reaction_t())) { diff --git a/dialogs.cpp b/dialogs.cpp index 26510b7b..43444ed9 100644 --- a/dialogs.cpp +++ b/dialogs.cpp @@ -743,17 +743,20 @@ EX namespace dialog { } EX void apply_edit() { - exp_parser ep; - ep.s = ne.s; - ld x = real(ep.parse()); - if(!ep.ok()) return; - if(ne.sc.positive && x <= 0) return; - *ne.editwhat = x; - if(ne.intval) *ne.intval = ldtoint(*ne.editwhat); - #if CAP_ANIMATIONS - if(ne.animatable) anims::animate_parameter(*ne.editwhat, ne.s, reaction ? reaction : reaction_final); - #endif - if(reaction) reaction(); + try { + exp_parser ep; + ep.s = ne.s; + ld x = ep.rparse(); + if(ne.sc.positive && x <= 0) return; + *ne.editwhat = x; + if(ne.intval) *ne.intval = ldtoint(*ne.editwhat); + #if CAP_ANIMATIONS + if(ne.animatable) anims::animate_parameter(*ne.editwhat, ne.s, reaction ? reaction : reaction_final); + #endif + if(reaction) reaction(); + } + catch(hr_parse_exception&) { + } } EX void bound_low(ld val) { diff --git a/hypgraph.cpp b/hypgraph.cpp index b23cb6f0..6961cde6 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -833,7 +833,13 @@ EX void applymodel(hyperpoint H, hyperpoint& ret) { ep.extra_params["uy"] = H[1]; ep.extra_params["uz"] = H[2]; ep.s = models::formula; - cld res = ep.parse(); + cld res; + try { + res = ep.parse(); + } + catch(hr_parse_exception&) { + res = 0; + } ret[0] = real(res); ret[1] = imag(res); ret[2] = 0; diff --git a/pattern2.cpp b/pattern2.cpp index cae7d71c..e575a34d 100644 --- a/pattern2.cpp +++ b/pattern2.cpp @@ -1577,7 +1577,12 @@ EX namespace patterns { } ep.s = formula; - return ep.parse(); + try { + return ep.parse(); + } + catch(hr_parse_exception& ex) { + return 0; + } } EX hookset *hooks_generate_canvas; diff --git a/screenshot.cpp b/screenshot.cpp index 4cca797e..67705fd6 100644 --- a/screenshot.cpp +++ b/screenshot.cpp @@ -575,7 +575,12 @@ void apply_animated_parameters() { ap_changes = 0; for(auto &ap: aps) { if(*ap.value != ap.last) continue; - *ap.value = parseld(ap.formula); + try { + *ap.value = parseld(ap.formula); + } + catch(hr_parse_exception&) { + continue; + } if(*ap.value != ap.last) { if(ap.reaction) ap.reaction(); ap_changes++; diff --git a/util.cpp b/util.cpp index 01052335..ffabf845 100644 --- a/util.cpp +++ b/util.cpp @@ -121,6 +121,11 @@ EX bool appears(const string& haystack, const string& needle) { } #if HDR +struct hr_parse_exception : hr_exception { + string s; + hr_parse_exception(const string& z) : s(z) {} + }; + struct exp_parser { string s; int at; @@ -129,7 +134,7 @@ struct exp_parser { map extra_params; bool ok() { return at == isize(s); } - char next(int step=0) { if(at >= isize(s)-step || at == -1) return 0; else return s[at+step]; } + char next(int step=0) { if(at >= isize(s)-step) return 0; else return s[at+step]; } bool eat(const char *c) { int orig_at = at; @@ -150,10 +155,14 @@ struct exp_parser { cld parsepar() { cld res = parse(); - if(next() != ')') { at = -1; return res; } - at++; + force_eat(")"); return res; } + + void force_eat(const char *c) { + skip_white(); + if(!eat(c)) throw hr_parse_exception("expected: " + string(c)); + } }; #endif @@ -188,24 +197,24 @@ cld exp_parser::parse(int prio) { else if(eat("to01(")) { res = parsepar(); return atan(res) / ld(M_PI) + ld(0.5); } else if(eat("ifp(")) { cld cond = parse(0); - if(snext() != ',') {at = -1; return 0; } at++; + force_eat(","); cld yes = parse(0); - if(snext() != ',') {at = -1; return 0; } at++; + force_eat(","); cld no = parsepar(); return real(cond) > 0 ? yes : no; } else if(eat("wallif(")) { cld val0 = parse(0); - if(snext() != ',') {at = -1; return 0; } at++; + force_eat(","); cld val1 = parsepar(); if(real(extra_params["p"]) >= 3.5) return val0; else return val1; } else if(eat("rgb(")) { cld val0 = parse(0); - if(snext() != ',') {at = -1; return 0; } at++; + force_eat(","); cld val1 = parse(0); - if(snext() != ',') {at = -1; return 0; } at++; + force_eat(","); cld val2 = parsepar(); switch(int(real(extra_params["p"]) + .5)) { case 1: return val0; @@ -223,11 +232,9 @@ cld exp_parser::parse(int prio) { name += c, at++; else break; } - if(snext() != '=') { at = -1; return 0; } - at++; + force_eat("="); cld val = parse(0); - if(snext() != ',') { at = -1; return 0; } - at++; + force_eat(","); dynamicval d(extra_params[name], val); return parsepar(); } @@ -250,7 +257,7 @@ cld exp_parser::parse(int prio) { else if(number == "i") res = cld(0, 1); else if(number == "p" || number == "pi") res = M_PI; else if(number == "" && next() == '-') { at++; res = -parse(prio); } - else if(number == "") at = -1; + else if(number == "") throw hr_parse_exception("number missing"); else if(number == "s") res = ticks / 1000.; else if(number == "ms") res = ticks; else if(number[0] == '0' && number[1] == 'x') res = strtoll(number.c_str()+2, NULL, 16); @@ -262,7 +269,7 @@ cld exp_parser::parse(int prio) { else if(number == "shot") res = inHighQual ? 1 : 0; else if(extra_params.count(number)) res = extra_params[number]; else if(params.count(number)) res = params.at(number); - else if(number[0] >= 'a' && number[0] <= 'z') at = -1; + else if(number[0] >= 'a' && number[0] <= 'z') throw hr_parse_exception("unknown value: " + number); else { std::stringstream ss; res = 0; ss << number; ss >> res; } } while(true) {