123 lines
3.1 KiB
C
123 lines
3.1 KiB
C
|
// vim: set ts=4 sw=4 et tw=80:
|
||
|
|
||
|
#include "bexp.h"
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
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);
|
||
|
|
||
|
// handle overflow
|
||
|
if (l1 == l2 && l1 > 0 &&
|
||
|
*(ex->value1.end - 1) == '1' &&
|
||
|
*(ex->value2.end - 1) == '1') {
|
||
|
return l1 + 1;
|
||
|
} else {
|
||
|
return l1 > l2 ? l1 : l2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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));
|
||
|
}
|
||
|
|