Mercurial > hg-old > index.cgi
diff lwlib/lw_expr.c @ 335:9f58e3bca6e3
checkpoint
author | lost |
---|---|
date | Thu, 04 Mar 2010 05:13:22 +0000 |
parents | f2173d18c73f |
children | 401587ab6a09 |
line wrap: on
line diff
--- a/lwlib/lw_expr.c Thu Mar 04 02:24:38 2010 +0000 +++ b/lwlib/lw_expr.c Thu Mar 04 05:13:22 2010 +0000 @@ -96,11 +96,11 @@ r = lw_alloc(sizeof(struct lw_expr_priv)); *r = *E; r -> refcount = 1; - + r -> operands = NULL; + if (E -> type == lw_expr_type_var) r -> value2 = lw_strdup(E -> value2); - - for (o = r -> operands; o; o = o -> next) + for (o = E -> operands; o; o = o -> next) { lw_expr_add_operand(r, lw_expr_deref(lw_expr_deepcopy(o -> p))); } @@ -108,9 +108,8 @@ return r; } -lw_expr_t lw_expr_build(int exprtype, ...) +lw_expr_t lw_expr_build_aux(int exprtype, va_list args) { - va_list args; lw_expr_t r; int t; void *p; @@ -118,7 +117,6 @@ lw_expr_t te1, te2; r = lw_expr_create(); - va_start(args, exprtype); switch (exprtype) { @@ -159,6 +157,28 @@ lw_error("Invalid expression type specified to lw_expr_build"); } + return r; +} + +lw_expr_t lw_expr_build(int exprtype, ...) +{ + va_list args; + lw_expr_t r; + + va_start(args, exprtype); + r = lw_expr_build_aux(exprtype, args); + va_end(args); + return r; +} + +lw_expr_t lw_expr_build_noref(int exprtype, ...) +{ + va_list args; + lw_expr_t r; + + va_start(args, exprtype); + r = lw_expr_build_aux(exprtype, args); + r -> refcount--; va_end(args); return r; } @@ -166,9 +186,11 @@ void lw_expr_print(lw_expr_t E) { struct lw_expr_opers *o; - + int c = 0; + for (o = E -> operands; o; o = o -> next) { + c++; lw_expr_print(o -> p); } @@ -177,7 +199,17 @@ case lw_expr_type_int: printf("%d ", E -> value); break; + + case lw_expr_type_var: + printf("V(%s) ", (char *)(E -> value2)); + break; + + case lw_expr_type_special: + printf("S(%d,%p) ", E -> value, E -> value2); + break; + case lw_expr_type_oper: + printf("[%d]", c); switch (E -> value) { case lw_expr_oper_plus: @@ -291,3 +323,190 @@ return 1; return 0; } + + +void lw_expr_simplify_sortconstfirst(lw_expr_t E) +{ + struct lw_expr_opers *o; + + for (o = E -> operands; o; o = o -> next) + lw_expr_simplify_sortconstfirst(o -> p); + + for (o = E -> operands; o; o = o -> next) + { + if (o -> p -> type == lw_expr_type_int && o != E -> operands) + { + struct lw_expr_opers *o2; + for (o2 = E -> operands; o2 -> next != o; o2 = o2 -> next) + /* do nothing */ ; + o2 -> next = o -> next; + o -> next = E -> operands; + E -> operands = o; + o = o2; + } + } +} + +// return 1 if the operand lists match, 0 if not +// may re-order the argument lists +int lw_expr_simplify_compareoperandlist(struct lw_expr_opers **ol1, struct lw_expr_opers **ol2) +{ + struct lw_expr_opers *o1, *o2; + + lw_expr_sortoperandlist(ol1); + lw_expr_sortoperandlist(ol2); + + for (o1 = *ol1, o2 = *ol2; o1 && o2; o1 = o1 -> next, o2 = o2 -> next) + { + if (!lw_expr_compare(o1 -> p, o2 -> p)) + return 0; + } + if (o1 || o2) + return 0; + return 1; +} + +void lw_expr_simplify(lw_expr_t E) +{ + struct lw_expr_opers *o; + + // sort "constants" to the start of each operand list for + and * + lw_expr_simplify_sortconstfirst(E); + + // non-operators have no simplification to do! + if (E -> type != lw_expr_type_oper) + return; + + if (E -> value == lw_expr_oper_times) + { + for (o = E -> operands; o; o = o -> next) + { + if (o -> p -> type == lw_expr_type_int && o -> p -> value == 0) + { + // one operand of times is 0, replace operation with 0 + while (E -> operands) + { + o = E -> operands; + E -> operands = o -> next; + lw_expr_destroy(o -> p); + lw_free(o); + } + E -> type = lw_expr_type_int; + E -> value = 0; + return; + } + } + } + + // look for like terms and collect them together + if (E -> value == lw_expr_oper_plus) + { + for (o = E -> operands; o; o = o -> next) + { + if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_times) + { + // we have a "times" here + // find first non-const operand + struct lw_expr_opers *op1, *op2, *o2; + for (op1 = o -> p -> operands; op1; op1 = op1 -> next) + if (op1 -> p -> type != lw_expr_type_int) + break; + + for (o2 = o -> next; o2; o2 = o2 -> next) + { + if (o2 -> p -> type == lw_expr_type_oper && o2 -> p -> value == lw_expr_oper_times) + { + // another "times" + for (op2 = o2 -> p -> operands; op2; op2 = op2 -> next) + if (op2 -> p -> type != lw_expr_type_int) + break; + + if (lw_expr_compareoperandlist(&op1, &op2)) + { + // we have like terms here + // do something about it + } + } + } + } + } + } + + + for (o = E -> operands; o; o = o -> next) + lw_expr_simplify(o -> p); + + if (E -> value == lw_expr_oper_plus) + { + int c = 0, t = 0; + for (o = E -> operands; o; o = o -> next) + { + t++; + if (!(o -> p -> type == lw_expr_type_int && o -> p -> value == 0)) + { + c++; + } + } + if (c == 1) + { + lw_expr_t r; + // find the value and "move it up" + while (E -> operands) + { + o = E -> operands; + if (o -> p -> type != lw_expr_type_int || o -> p -> value != 0) + { + r = lw_expr_deepcopy(o -> p); + } + E -> operands = o -> next; + lw_expr_destroy(o -> p); + lw_free(o); + } + *E = *r; + return; + } + else if (c == 0) + { + // replace with 0 + while (E -> operands) + { + o = E -> operands; + E -> operands = o -> next; + lw_expr_destroy(o -> p); + lw_free(o); + } + E -> type = lw_expr_type_int; + E -> value = 0; + return; + } + else if (c != t) + { + // collapse out zero terms + struct lw_expr_opers *o2; + + for (o = E -> operands; o; o = o -> next) + { + if (o -> p -> type == lw_expr_type_int && o -> p -> value == 0) + { + if (o == E -> operands) + { + E -> operands = o -> next; + lw_expr_destroy(o -> p); + lw_free(o); + o = E -> operands; + } + else + { + for (o2 = E -> operands; o2 -> next == o; o2 = o2 -> next) + /* do nothing */ ; + o2 -> next = o -> next; + lw_expr_destroy(o -> p); + lw_free(o); + o = o2; + } + } + } + } + return; + } +}