diff lwlib/lw_expr.c @ 337:04c80c51b16a

Checkpoint development
author lost
date Fri, 12 Mar 2010 06:01:38 +0000
parents 401587ab6a09
children 7b4123dce741
line wrap: on
line diff
--- a/lwlib/lw_expr.c	Fri Mar 05 02:34:16 2010 +0000
+++ b/lwlib/lw_expr.c	Fri Mar 12 06:01:38 2010 +0000
@@ -31,44 +31,58 @@
 #include "lw_error.h"
 #include "lw_string.h"
 
+static lw_expr_t (*evaluate_special)(int t, void *ptr) = NULL;
+static lw_expr_t (*evaluate_var)(char *var) = NULL;
+
+void lw_expr_set_special_handler(lw_expr_t (*fn)(int t, void *ptr))
+{
+	evaluate_special = fn;
+}
+
+void lw_expr_set_var_handler(lw_expr_t (*fn)(char *var))
+{
+	evaluate_var = fn;
+}
+
 lw_expr_t lw_expr_create(void)
 {
 	lw_expr_t r;
 	
 	r = lw_alloc(sizeof(struct lw_expr_priv));
-	r -> refcount = 1;
 	r -> operands = NULL;
 
 	return r;
 }
 
-/* useful for constant expression construction */
-/* lw_expr_deref(lw_expr_create(...)) */
-/* use of this function on an expression that is not already referenced by the caller */
-lw_expr_t lw_expr_deref(lw_expr_t r)
-{
-	r -> refcount--;
-	return r;
-}
-
 void lw_expr_destroy(lw_expr_t E)
 {
-	E -> refcount--;
-	if (E -> refcount <= 0)
-	{
-		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);
-	}
+	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)
 {
-	E -> refcount++;
-	return 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)
@@ -87,27 +101,6 @@
 		E -> operands = o;
 }
 
-/* actually duplicates the entire expression */
-lw_expr_t lw_expr_deepcopy(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 -> refcount = 1;
-	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_deref(lw_expr_deepcopy(o -> p)));
-	}
-	
-	return r;
-}
-
 lw_expr_t lw_expr_build_aux(int exprtype, va_list args)
 {
 	lw_expr_t r;
@@ -136,6 +129,7 @@
 		t = va_arg(args, int);
 		p = va_arg(args, char *);
 		r -> type = lw_expr_type_special;
+		r -> value = t;
 		r -> value2 = p;
 		break;
 
@@ -171,18 +165,6 @@
 	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;
-}
-
 void lw_expr_print(lw_expr_t E)
 {
 	struct lw_expr_opers *o;
@@ -375,12 +357,155 @@
 {
 	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);
 	
-	// non-operators have no simplification to do!
-	if (E -> type != lw_expr_type_oper)
+	// 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)
 	{
@@ -438,9 +563,6 @@
 	}
 
 
-	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;
@@ -461,7 +583,7 @@
 				o = E -> operands;
 				if (o -> p -> type != lw_expr_type_int || o -> p -> value != 0)
 				{
-					r = lw_expr_deepcopy(o -> p);
+					r = lw_expr_copy(o -> p);
 				}
 				E -> operands = o -> next;
 				lw_expr_destroy(o -> p);