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;
+	}
+}