| 1 | // Coded by Ralf Westram (coder@reallysoft.de) in March 2011 // |
|---|
| 2 | // Institute of Microbiology (Technical University Munich) // |
|---|
| 3 | // http://www.arb-home.de/ // |
|---|
| 4 | |
|---|
| 5 | #ifndef AISC_EVAL_H |
|---|
| 6 | #define AISC_EVAL_H |
|---|
| 7 | |
|---|
| 8 | #ifndef AISC_DEF_H |
|---|
| 9 | #include "aisc_def.h" |
|---|
| 10 | #endif |
|---|
| 11 | #ifndef AISC_LOCATION_H |
|---|
| 12 | #include "aisc_location.h" |
|---|
| 13 | #endif |
|---|
| 14 | #ifndef ARBTOOLS_H |
|---|
| 15 | #include <arbtools.h> |
|---|
| 16 | #endif |
|---|
| 17 | |
|---|
| 18 | class Expression : virtual Noncopyable { |
|---|
| 19 | const Data& data; |
|---|
| 20 | const Location& loc; |
|---|
| 21 | |
|---|
| 22 | int used; // currently used size |
|---|
| 23 | int bufsize; // including zero-byte |
|---|
| 24 | char *ebuffer; |
|---|
| 25 | |
|---|
| 26 | bool allow_missing_ref; |
|---|
| 27 | |
|---|
| 28 | bool was_evaluated; |
|---|
| 29 | int errors_before; |
|---|
| 30 | |
|---|
| 31 | char *eval_math(char *expr, char op_char); |
|---|
| 32 | char *evalPart(int start, int end, int& result_len); |
|---|
| 33 | |
|---|
| 34 | bool evalRest(int offset); |
|---|
| 35 | |
|---|
| 36 | char *evalBehind(int offset) { |
|---|
| 37 | aisc_assert(!was_evaluated); |
|---|
| 38 | char *toEval = strstr(ebuffer+offset, "$("); |
|---|
| 39 | return (!toEval || evalRest(toEval-ebuffer)) ? ebuffer : NULp; |
|---|
| 40 | } |
|---|
| 41 | |
|---|
| 42 | |
|---|
| 43 | char *report_result(char *s, bool& failed) { |
|---|
| 44 | int errors_after = Location::get_error_count(); |
|---|
| 45 | failed = errors_after != errors_before; |
|---|
| 46 | |
|---|
| 47 | aisc_assert(!(failed && s)); |
|---|
| 48 | if (s) { |
|---|
| 49 | aisc_assert(s == ebuffer); |
|---|
| 50 | ebuffer = NULp; // now owned by caller |
|---|
| 51 | } |
|---|
| 52 | |
|---|
| 53 | was_evaluated = true; |
|---|
| 54 | return s; |
|---|
| 55 | } |
|---|
| 56 | |
|---|
| 57 | public: |
|---|
| 58 | Expression(const Data& data_, const Location& loc_, const char *str, bool allow_missing_ref_) |
|---|
| 59 | : data(data_), |
|---|
| 60 | loc(loc_), |
|---|
| 61 | allow_missing_ref(allow_missing_ref_), |
|---|
| 62 | was_evaluated(false), |
|---|
| 63 | errors_before(Location::get_error_count()) |
|---|
| 64 | { |
|---|
| 65 | used = strlen(str); |
|---|
| 66 | bufsize = used*2+1; |
|---|
| 67 | ebuffer = (char*)malloc(bufsize); |
|---|
| 68 | aisc_assert(used<bufsize); |
|---|
| 69 | memcpy(ebuffer, str, used+1); |
|---|
| 70 | } |
|---|
| 71 | ~Expression() { |
|---|
| 72 | aisc_assert(was_evaluated); // useless Expression |
|---|
| 73 | free(ebuffer); |
|---|
| 74 | } |
|---|
| 75 | |
|---|
| 76 | char *evaluate(bool& failed) { |
|---|
| 77 | return report_result(evalBehind(0), failed); |
|---|
| 78 | } |
|---|
| 79 | |
|---|
| 80 | char *evalVarDecl(bool& failed) { |
|---|
| 81 | // dont eval first '$(' |
|---|
| 82 | |
|---|
| 83 | char *res = NULp; |
|---|
| 84 | char *varDecl = strstr(ebuffer, "$("); |
|---|
| 85 | if (varDecl) { |
|---|
| 86 | res = evalBehind((varDecl+2)-ebuffer); |
|---|
| 87 | } |
|---|
| 88 | else { |
|---|
| 89 | print_error(&loc, "Expected identifier, i.e. '$(ident)'"); |
|---|
| 90 | } |
|---|
| 91 | return report_result(res, failed); |
|---|
| 92 | } |
|---|
| 93 | }; |
|---|
| 94 | |
|---|
| 95 | |
|---|
| 96 | |
|---|
| 97 | #else |
|---|
| 98 | #error aisc_eval.h included twice |
|---|
| 99 | #endif // AISC_EVAL_H |
|---|