//FloatParser.cpp #include "FloatParser.h" #include #include #include using namespace std; //Makros, um Funktionen einfacher parser zu können #define CASE_1(var) if (!strcmp(SWITCH,var)) #define CASE(var) else if (!strcmp(SWITCH,var)) #define CASE_ELSE else #define PARSE_BLANKS while (*reading_stream == ' ') ++reading_stream; //static enumerations and variables static enum binary_operator { b_plus, b_minus, mal, durch, modulo, hoch, undef, oder, und, gleich, b_nicht, kleiner, groesser, ungleich, kleinergleich, groessergleich}; static enum unary_operator { u_plus, u_minus, u_nicht }; static binary_operator op; static char* reading_stream; static bool parse_float_failed = false; //static funtions static double parse_expr_1(); static double parse_expr_2(); static double parse_expr_3(); static double parse_expr_4(); static double parse_expr_5(); static double parse_expr_6(); static double parse_expr_7(); static double parse_expr_8(); static inline char* parse_word(char* str); static inline binary_operator parse_binary_operator(); static inline unary_operator parse_unary_operator(); static double parse_argument(); static double parse_last_argument(); //Public functions: /******************/ bool parse_float(char* const string, char **endptr, double* result) { parse_float_failed = false; reading_stream = string; double value = parse_expr_8(); if ( !parse_float_failed && ( *reading_stream == ')' || \ *reading_stream == '}' || \ *reading_stream == ']' || \ *reading_stream == ',' || \ *reading_stream == ';' || \ *reading_stream == '_' || \ *reading_stream == '\0' || \ *reading_stream > 64 && *reading_stream < 91 || \ *reading_stream > 96 && *reading_stream < 123)) { endptr = &reading_stream; *result = value; return true; } else { *result = 0; return false; } } bool parse_float(char* const string, char** endptr, char delimiter, double* result) { parse_float_failed = false; reading_stream = string; double value = parse_expr_8(); if (*reading_stream == delimiter && !parse_float_failed) { endptr = &reading_stream; *result = value; return true; } else { *result = 0; return false; } } bool parse_vector_float(char* const string, char** endptr, bool last_float, double* result) { parse_float_failed = false; reading_stream = string; double value = parse_expr_4(); if (last_float) { if (*reading_stream == '>') { endptr = &reading_stream; *result = value; } else parse_float_failed = true; } else { if (*reading_stream == ',') { *endptr = reading_stream; *result = value; } else parse_float_failed = true; } if (parse_float_failed) { *result = 0; return false; } else return true; } //Private functions: /******************/ static double parse_argument() { double value = parse_expr_8(); if (*reading_stream == ',') { ++reading_stream; return value; } else { parse_float_failed = true; return 0; } } static double parse_last_argument() { double value = parse_expr_8(); if (*reading_stream == ')') { ++reading_stream; return value; } else { parse_float_failed = true; return 0; } } static double parse_expr_8() { double value = parse_expr_7(); for(;;) { switch (op) { case oder: value = parse_expr_7() || value; break; default: return value; } }; } static double parse_expr_7() { double value = parse_expr_6(); for(;;) { switch (op) { case und: value = value && parse_expr_6(); break; default: return value; } }; } static double parse_expr_6() { double value = parse_expr_5(); for(;;) { switch (op) { case gleich: value = (value == parse_expr_5()); break; case ungleich: value = (value != parse_expr_5()); break; default: return value; } }; } static double parse_expr_5() { double value = parse_expr_4(); for(;;) { switch (op) { case kleiner: value = (value < parse_expr_4()); break; case kleinergleich: value = (value <= parse_expr_4()); break; case groesser: value = (value > parse_expr_4()); break; case groessergleich: value = (value >= parse_expr_4()); break; default: return value; } }; } static double parse_expr_4() { double value = parse_expr_3(); for(;;) { switch (op) { case b_plus: value += parse_expr_3(); break; case b_minus: value -= parse_expr_3(); break; default: return value; } }; } static double parse_expr_3() { double value = parse_expr_2(); for(;;) { switch (op) { case mal: value *= parse_expr_2(); break; case durch: value /= parse_expr_2(); break; case modulo: { double temp = parse_expr_2(); value = value - floor(value/temp)*temp; break; } default: return value; } }; } static double parse_expr_2() { double value = parse_expr_1(); while (*reading_stream != '\0') { op = parse_binary_operator(); switch (op) { case hoch: value = pow(value,parse_expr_1()); break; default: return value; } }; op = undef; return value; } static double parse_expr_1() { PARSE_BLANKS double value; unary_operator op = parse_unary_operator(); PARSE_BLANKS if (*reading_stream == '\0') { // end of string parse_float_failed = true; return 0; } else if (*reading_stream > 47 && *reading_stream < 59 || *reading_stream == 46) { //Zahl value = strtod(reading_stream,&reading_stream); } else if (*reading_stream > 64 && *reading_stream < 91 || *reading_stream > 96 && *reading_stream < 123 || *reading_stream == 46) { //Variable oder Funktion char* word = new char[256]; parse_word(word); PARSE_BLANKS if (*reading_stream == '(') { ++reading_stream; #define SWITCH word CASE_1("sin") value = sin(parse_last_argument()); CASE("asin") value = asin(parse_last_argument()); CASE("sinh") value = sinh(parse_last_argument()); CASE("asinh") { value = parse_last_argument(); value = log(sqrt(pow(value, 2) + 1) + value); } CASE("cos") value = cos(parse_last_argument()); CASE("acos") value = acos(parse_last_argument()); CASE("cosh") value = cosh(parse_last_argument()); CASE("acosh") { value = parse_last_argument(); value = log(sqrt(pow(value, 2) - 1) + value); } CASE("tan") value = tan(parse_last_argument()); CASE("atan") value = atan(parse_last_argument()); CASE("atan2") value = atan2(parse_argument(),parse_last_argument()); CASE("tanh") value = tanh(parse_last_argument()); CASE("atanh") { value = parse_last_argument(); value = 0.5*log((value + 1)/(value - 1)); } CASE("int") value = floor(parse_last_argument()); CASE("floor") value = floor(parse_last_argument()); CASE("ceil") value = ceil(parse_last_argument()); CASE("abs") value = abs(parse_last_argument()); CASE("exp") value = exp(parse_last_argument()); CASE("log") value = log10(parse_last_argument()); CASE("ln") value = log(parse_last_argument()); CASE("sign") { value = parse_last_argument(); value = (value>0 ? 1 : (value<0 ? -1 : 0)); } CASE("sqrt") value = sqrt(parse_last_argument()); CASE("degrees") value = parse_last_argument()*180/3.1415926535897932; CASE("radians") value = parse_last_argument()*3.1415926535897932/180; CASE("mod") { value = parse_argument(); double value2 = parse_last_argument(); value = value - floor(value/value2)*value2; } CASE("pow") value = pow(parse_argument(),parse_last_argument()); CASE("div") value = floor(parse_argument()/parse_last_argument()); CASE("max") value = max(parse_argument(),parse_last_argument()); CASE("min") value = min(parse_argument(),parse_last_argument()); CASE_ELSE { parse_float_failed = true; return 0; } } else { //TODO: Variablen-Liste durchsuchen //Momentaner Ersatzwert für jede Variable: //value = 0; parse_float_failed = true; return 0; } delete[] word; } else if (*reading_stream == 40) { //Audruck in Klammern ++reading_stream; value = parse_last_argument(); } else { parse_float_failed = true; return 0; } PARSE_BLANKS switch (op) { case u_nicht: return !value; case u_plus: return value; case u_minus: return -value; default: { parse_float_failed = true; return 0; } } } static inline char* parse_word(char* str) { char* word = str; int counter = 0; while (*reading_stream > 47 && *reading_stream < 58 || *reading_stream > 64 && *reading_stream < 91 || *reading_stream > 96 && *reading_stream < 123 || *reading_stream == 46) { *word++ = *reading_stream++; counter++; if (counter > 255) { parse_float_failed = true; return '\0'; } }; *word = '\0'; return str; } static inline binary_operator parse_binary_operator() { binary_operator op; switch (*reading_stream) { case '+': op = b_plus; break; case '-': op = b_minus; break; case '*': op = mal; break; case '/': op = durch; break; case '^': op = hoch; break; case '%': op = modulo; break; case '&': op = und; break; case '|': op = oder; break; case '=': op = gleich; break; case '!': op = b_nicht; break; case '<': op = kleiner; break; case '>': op = groesser; break; default: return undef; } if (*++reading_stream == '=') { if (op > 9) { ++reading_stream; return (binary_operator)(op + 3); } else { --reading_stream; return undef; } } else return op; } static inline unary_operator parse_unary_operator() { switch (*reading_stream) { case '!': ++reading_stream; return u_nicht; case '+': ++reading_stream; return u_plus; case '-': ++reading_stream; return u_minus; default : return u_plus; } }