// vim: set ts=4 sw=4 et tw=80: #include "bexp.h" #include static int value_length(const value* val); inline int value_length(const value* val) { return val->end - val->begin; } typedef int(*compute_func)(char*, int, int, int*); int bexp_loop(value* result, const expression* ex, compute_func compute) { const char* end1 = ex->value1.end; const char* end2 = ex->value2.end; char* l1 = ex->value1.begin; char* l2 = (ex->op == NOT || ex->op == COMPLEMENT) ? NULL : ex->value2.begin; int acc = 0; char* r = result->begin; while (l1 < end1 || (l2 != NULL && l2 < end2)) { if (r == result->end) { return 0; } const int a = l1 < end1 ? *l1 - '0' : 0; const int b = l2 != NULL && l2 < end2 ? *l2 - '0' : 0; *r = '0'; if (compute(r, a, b, &acc)) { return 1; } if (ex->op != GREATER_THAN && ex->op != LESS_THAN && ex->op != NOT) r++; l1++; if (l2 != NULL) l2++; } if (acc == 1) { if (r == result->end) { return 0; } else { *r = '1'; } } return 1; } int compute_and(char* r, int a, int b, int* _) { *r += a && b; return 0; } int compute_or(char* r, int a, int b, int* _) { *r += a || b; return 0; } int compute_xor(char* r, int a, int b, int* _) { *r += a ^ b; return 0; } int compute_gt(char* r, int a, int b, int* _) { *r += a > b; return a != b; } int compute_lt(char* r, int a, int b, int* _) { *r += a < b; return a != b; } int compute_plus(char* r, int a, int b, int* c) { *r += a ^ b ^ *c; *c = (a && b) || ((a ^ b) && *c); return 0; } int compute_compl(char* r, int a, int _, int* __) { *r += !a; return 0; } int compute_not(char* r, int a, int _, int* __) { *r += !a; return a; } compute_func bexp_compute(const operator_t op) { switch (op) { case AND: return compute_and; case OR: return compute_or; case XOR: return compute_xor; case PLUS: return compute_plus; case GREATER_THAN: return compute_gt; case LESS_THAN: return compute_lt; case NOT: return compute_not; case COMPLEMENT: return compute_compl; } } int bexp_length(const expression* ex) { switch (ex->op) { case AND: case OR: case XOR: { const int l1 = value_length(&ex->value1); const int l2 = value_length(&ex->value2); return l1 > l2 ? l1 : l2; } case PLUS: { const int l1 = value_length(&ex->value1); const int l2 = value_length(&ex->value2); const int max = l1 > l2 ? l1 : l2; char tmp[max + 1]; tmp[max] = '0'; value result = { tmp, tmp + max + 1 }; if (!bexp_loop(&result, ex, compute_plus)) { return -1; } return tmp[max] == '1' ? max + 1 : max; } case GREATER_THAN: case LESS_THAN: case NOT: return 1; case COMPLEMENT: return value_length(&ex->value1); } } int bexp_evaluate(value* result, expression* ex) { return bexp_loop(result, ex, bexp_compute(ex->op)); }