Mercurial > hg-old > index.cgi
view lwlib/lw_expr.c @ 342:7b4123dce741
Added basic symbol registration
author | lost@starbug |
---|---|
date | Wed, 24 Mar 2010 21:30:31 -0600 |
parents | 04c80c51b16a |
children | a82c55070624 |
line wrap: on
line source
/* lwexpr.c Copyright © 2010 William Astle This file is part of LWTOOLS. LWTOOLS is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <config.h> #include <stdarg.h> #include <stdio.h> #include <string.h> #define ___lw_expr_c_seen___ #include "lw_alloc.h" #include "lw_expr.h" #include "lw_error.h" #include "lw_string.h" static lw_expr_fn_t *evaluate_special = NULL; static lw_expr_fn2_t *evaluate_var = NULL; void lw_expr_set_special_handler(lw_expr_fn_t *fn) { evaluate_special = fn; } void lw_expr_set_var_handler(lw_expr_fn2_t *fn) { evaluate_var = fn; } lw_expr_t lw_expr_create(void) { lw_expr_t r; r = lw_alloc(sizeof(struct lw_expr_priv)); r -> operands = NULL; return r; } void lw_expr_destroy(lw_expr_t E) { struct lw_expr_opers *o; for (o = E -> operands; o; o = o -> next) lw_expr_destroy(o -> p); if (E -> type == lw_expr_type_var) lw_free(E -> value2); lw_free(E); } /* actually duplicates the entire expression */ void lw_expr_add_operand(lw_expr_t E, lw_expr_t O); lw_expr_t lw_expr_copy(lw_expr_t E) { lw_expr_t r, t; struct lw_expr_opers *o; r = lw_alloc(sizeof(struct lw_expr_priv)); *r = *E; r -> operands = NULL; if (E -> type == lw_expr_type_var) r -> value2 = lw_strdup(E -> value2); for (o = E -> operands; o; o = o -> next) { lw_expr_add_operand(r, lw_expr_copy(o -> p)); } return r; } void lw_expr_add_operand(lw_expr_t E, lw_expr_t O) { struct lw_expr_opers *o, *t; o = lw_alloc(sizeof(struct lw_expr_opers)); o -> p = lw_expr_copy(O); o -> next = NULL; for (t = E -> operands; t && t -> next; t = t -> next) /* do nothing */ ; if (t) t -> next = o; else E -> operands = o; } lw_expr_t lw_expr_build_aux(int exprtype, va_list args) { lw_expr_t r; int t; void *p; lw_expr_t te1, te2; r = lw_expr_create(); switch (exprtype) { case lw_expr_type_int: t = va_arg(args, int); r -> type = lw_expr_type_int; r -> value = t; break; case lw_expr_type_var: p = va_arg(args, char *); r -> type = lw_expr_type_var; r -> value2 = lw_strdup(p); break; case lw_expr_type_special: t = va_arg(args, int); p = va_arg(args, char *); r -> type = lw_expr_type_special; r -> value = t; r -> value2 = p; break; case lw_expr_type_oper: t = va_arg(args, int); te1 = va_arg(args, lw_expr_t); if (t != lw_expr_oper_com && t != lw_expr_oper_neg) te2 = va_arg(args, lw_expr_t); else te2 = NULL; r -> type = lw_expr_type_oper; r -> value = t; lw_expr_add_operand(r, te1); lw_expr_add_operand(r, te2); break; default: 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; } 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); } switch (E -> type) { 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: printf("+ "); break; case lw_expr_oper_minus: printf("- "); break; case lw_expr_oper_times: printf("* "); break; case lw_expr_oper_divide: printf("/ "); break; case lw_expr_oper_mod: printf("%% "); break; case lw_expr_oper_intdiv: printf("\\ "); break; case lw_expr_oper_bwand: printf("BWAND "); break; case lw_expr_oper_bwor: printf("BWOR "); break; case lw_expr_oper_bwxor: printf("BWXOR "); break; case lw_expr_oper_and: printf("AND "); break; case lw_expr_oper_or: printf("OR "); break; case lw_expr_oper_neg: printf("NEG "); break; case lw_expr_oper_com: printf("COM "); break; default: printf("OPER "); break; } break; default: printf("ERR "); break; } } /* Return: nonzero if expressions are the same (identical pointers or matching values) zero if expressions are not the same */ int lw_expr_compare(lw_expr_t E1, lw_expr_t E2) { struct lw_expr_opers *o1, *o2; if (E1 == E2) return 1; if (!(E1 -> type == E2 -> type && E1 -> value == E2 -> value)) return 0; if (E1 -> type == lw_expr_type_var) { if (!strcmp(E1 -> value2, E2 -> value2)) return 1; else return 0; } if (E1 -> type == lw_expr_type_special) { if (E1 -> value2 == E2 -> value2) return 1; else return 0; } for (o1 = E1 -> operands, o2 = E2 -> operands; o1 && o2; o1 = o1 -> next, o2 = o2 -> next) if (lw_expr_compare(o1 -> p, o2 -> p) == 0) return 0; if (o1 || o2) return 0; return 1; } /* return true if E is an operator of type oper */ int lw_expr_isoper(lw_expr_t E, int oper) { if (E -> type == lw_expr_type_oper && E -> value == oper) 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; } } } void lw_expr_sortoperandlist(struct lw_expr_opers **o) { fprintf(stderr, "lw_expr_sortoperandlist() not yet implemented\n"); } // 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; again: // try to resolve non-constant terms to constants here if (E -> type == lw_expr_type_special && evaluate_special) { lw_expr_t te; te = evaluate_special(E -> value, E -> value2); if (te) { for (o = E -> operands; o; o = o -> next) lw_expr_destroy(o -> p); if (E -> type == lw_expr_type_var) lw_free(E -> value2); *E = *te; E -> operands = NULL; if (te -> type == lw_expr_type_var) E -> value2 = lw_strdup(te -> value2); for (o = te -> operands; o; o = o -> next) { lw_expr_add_operand(E, lw_expr_copy(o -> p)); } lw_expr_destroy(te); goto again; } return; } if (E -> type == lw_expr_type_var && evaluate_var) { lw_expr_t te; te = evaluate_var(E -> value2); if (te) { for (o = E -> operands; o; o = o -> next) lw_expr_destroy(o -> p); if (E -> type == lw_expr_type_var) lw_free(E -> value2); *E = *te; E -> operands = NULL; if (te -> type == lw_expr_type_var) E -> value2 = lw_strdup(te -> value2); for (o = te -> operands; o; o = o -> next) { lw_expr_add_operand(E, lw_expr_copy(o -> p)); } lw_expr_destroy(te); goto again; } return; } // non-operators have no simplification to do! if (E -> type != lw_expr_type_oper) return; // sort "constants" to the start of each operand list for + and * lw_expr_simplify_sortconstfirst(E); // simplify operands for (o = E -> operands; o; o = o -> next) lw_expr_simplify(o -> p); for (o = E -> operands; o; o = o -> next) { if (o -> p -> type != lw_expr_type_int) break; } if (!o) { // we can do the operation here! int tr = -42424242; switch (E -> value) { case lw_expr_oper_neg: tr = -(E -> operands -> p -> value); break; case lw_expr_oper_com: tr = ~(E -> operands -> p -> value); break; case lw_expr_oper_plus: tr = E -> operands -> p -> value; for (o = E -> operands -> next; o; o = o -> next) tr += o -> p -> value; break; case lw_expr_oper_minus: tr = E -> operands -> p -> value; for (o = E -> operands -> next; o; o = o -> next) tr -= o -> p -> value; break; case lw_expr_oper_times: tr = E -> operands -> p -> value; for (o = E -> operands -> next; o; o = o -> next) tr *= o -> p -> value; break; case lw_expr_oper_divide: tr = E -> operands -> p -> value / E -> operands -> next -> p -> value; break; case lw_expr_oper_mod: tr = E -> operands -> p -> value % E -> operands -> next -> p -> value; break; case lw_expr_oper_intdiv: tr = E -> operands -> p -> value / E -> operands -> next -> p -> value; break; case lw_expr_oper_bwand: tr = E -> operands -> p -> value & E -> operands -> next -> p -> value; break; case lw_expr_oper_bwor: tr = E -> operands -> p -> value | E -> operands -> next -> p -> value; break; case lw_expr_oper_bwxor: tr = E -> operands -> p -> value ^ E -> operands -> next -> p -> value; break; case lw_expr_oper_and: tr = E -> operands -> p -> value && E -> operands -> next -> p -> value; break; case lw_expr_oper_or: tr = E -> operands -> p -> value || E -> operands -> next -> p -> value; break; } 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 = tr; 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_simplify_compareoperandlist(&op1, &op2)) { // we have like terms here // do something about it } } } } } } 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_copy(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; } }