diff lwlib/lw_expr.c @ 371:9c24d9d485b9

Much bugfixing
author lost@starbug
date Wed, 21 Apr 2010 23:29:18 -0600
parents 6b33faa21a0a
children 90de73ba0cac
line wrap: on
line diff
--- a/lwlib/lw_expr.c	Tue Apr 20 21:59:58 2010 -0600
+++ b/lwlib/lw_expr.c	Wed Apr 21 23:29:18 2010 -0600
@@ -171,7 +171,8 @@
 		r -> type = lw_expr_type_oper;
 		r -> value = t;
 		lw_expr_add_operand(r, te1);
-		lw_expr_add_operand(r, te2);
+		if (te2)
+			lw_expr_add_operand(r, te2);
 		break;
 	
 	default:
@@ -206,7 +207,10 @@
 	switch (E -> type)
 	{
 	case lw_expr_type_int:
-		fprintf(fp, "%d ", E -> value);
+		if (E -> value < 0)
+			fprintf(fp, "-%#x ", -(E -> value));
+		else
+			fprintf(fp, "%#x ", E -> value);
 		break;
 	
 	case lw_expr_type_var:
@@ -337,9 +341,17 @@
 void lw_expr_simplify_sortconstfirst(lw_expr_t E)
 {
 	struct lw_expr_opers *o;
-	
+
+	if (E -> type != lw_expr_type_oper)
+		return;
+	if (E -> value != lw_expr_oper_times && E -> value != lw_expr_oper_plus)
+		return;
+
 	for (o = E -> operands; o; o = o -> next)
-		lw_expr_simplify_sortconstfirst(o -> p);
+	{
+		if (o -> p -> type == lw_expr_type_oper && (o -> p -> value == lw_expr_oper_times || o -> p -> value == lw_expr_oper_plus))
+			lw_expr_simplify_sortconstfirst(o -> p);
+	}
 	
 	for (o = E -> operands; o; o = o -> next)
 	{
@@ -380,10 +392,93 @@
 	return 1;
 }
 
+int lw_expr_simplify_isliketerm(lw_expr_t e1, lw_expr_t e2)
+{
+	fprintf(stderr, "isliketerm in: ");
+	lw_expr_print(e1, stderr);
+	fprintf(stderr, "; ");
+	lw_expr_print(e2, stderr);
+	fprintf(stderr, "\n");
+
+	// first term is a "times"
+	if (e1 -> type == lw_expr_type_oper && e1 -> value == lw_expr_oper_times)
+	{
+		// second term is a "times"
+		if (e2 -> type == lw_expr_type_oper && e2 -> value == lw_expr_oper_times)
+		{
+			// both times - easy check
+			struct lw_expr_opers *o1, *o2;
+			for (o1 = e1 -> operands; o1; o1 = o1 -> next)
+				if (o1 -> p -> type != lw_expr_type_int)
+					break;
+			
+			for (o2 = e2 -> operands; o2; o2 = o2 -> next)
+				if (o2 -> p -> type != lw_expr_type_int)
+					break;
+			
+			if (lw_expr_simplify_compareoperandlist(&o1, &o2))
+				return 1;
+			return 0;
+		}
+		
+		// not a times - have to assume it's the operand list
+		// with a "1 *" in front if it
+		if (e1 -> operands -> next -> next)
+			return 0;
+		if (!lw_expr_compare(e1 -> operands -> next -> p, e2))
+			return 0;
+		return 1;
+	}
+	
+	// e1 is not a times
+	if (e2 -> type == lw_expr_type_oper && e2 -> value == lw_expr_oper_times)
+	{
+		// e2 is a times
+		if (e2 -> operands -> next -> next)
+			return 0;
+		if (!lw_expr_compare(e1, e2 -> operands -> next -> p))
+			return 0;
+		return 1;
+	}
+	
+	// neither are times
+	if (!lw_expr_compare(e1, e2))
+		return 0;
+	return 1;
+}
+
 void lw_expr_simplify(lw_expr_t E, void *priv)
 {
 	struct lw_expr_opers *o;
 
+	// replace subtraction with O1 + -1(O2)...
+	// needed for like term collection
+	if (E -> type == lw_expr_type_oper && E -> value == lw_expr_oper_minus)
+	{
+		for (o = E -> operands -> next; o; o = o -> next)
+		{
+			lw_expr_t e1, e2;
+			
+			e2 = lw_expr_build(lw_expr_type_int, -1);
+			e1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_times, e2, o -> p);
+			lw_expr_destroy(o -> p);
+			lw_expr_destroy(e2);
+			o -> p = e1;
+		}
+		E -> value = lw_expr_oper_plus;
+	}
+
+	// turn "NEG" into -1(O) - needed for like term collection
+	if (E -> type == lw_expr_type_oper && E -> value == lw_expr_oper_neg)
+	{
+		lw_expr_t e1;
+		
+		E -> value = lw_expr_oper_times;
+		e1 = lw_expr_build(lw_expr_type_int, -1);
+		lw_expr_add_operand(E, e1);
+		lw_expr_destroy(e1);
+	}
+	
 again:
 	// try to resolve non-constant terms to constants here
 	if (E -> type == lw_expr_type_special && evaluate_special)
@@ -442,8 +537,65 @@
 	if (E -> type != lw_expr_type_oper)
 		return;
 
-	// sort "constants" to the start of each operand list for + and *
-	lw_expr_simplify_sortconstfirst(E);
+	// merge plus operations
+	if (E -> value == lw_expr_oper_plus)
+	{
+		lw_expr_t e2;
+
+	tryagainplus:
+		for (o = E -> operands; o; o = o -> next)
+		{
+			if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_plus)
+			{
+				struct lw_expr_opers *o2, *o3;
+				// we have a + operation - bring operands up
+				
+				for (o2 = E -> operands; o2 && o2 -> next != o; o2 = o2 -> next)
+					/* do nothing */ ;
+				if (o2)
+					o2 -> next = o -> p -> operands;
+				else
+					E -> operands = o -> p -> operands;
+				for (o2 = o -> p -> operands; o2 -> next; o2 = o2 -> next)
+					/* do nothing */ ;
+				o2 -> next = o -> next;
+				o -> p -> operands = NULL;
+				lw_expr_destroy(o -> p);
+				lw_free(o);
+				goto tryagainplus;
+			}
+		}
+	}
+	
+	// merge times operations
+	if (E -> value == lw_expr_oper_times)
+	{
+		lw_expr_t e2;
+
+	tryagaintimes:
+		for (o = E -> operands; o; o = o -> next)
+		{
+			if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_times)
+			{
+				struct lw_expr_opers *o2, *o3;
+				// we have a + operation - bring operands up
+				
+				for (o2 = E -> operands; o2 && o2 -> next != o; o2 = o2 -> next)
+					/* do nothing */ ;
+				if (o2)
+					o2 -> next = o -> p -> operands;
+				else
+					E -> operands = o -> p -> operands;
+				for (o2 = o -> p -> operands; o2 -> next; o2 = o2 -> next)
+					/* do nothing */ ;
+				o2 -> next = o -> next;
+				o -> p -> operands = NULL;
+				lw_expr_destroy(o -> p);
+				lw_free(o);
+				goto tryagaintimes;
+			}
+		}
+	}
 	
 	// simplify operands
 	for (o = E -> operands; o; o = o -> next)
@@ -534,6 +686,56 @@
 		return;
 	}
 
+	if (E -> value == lw_expr_oper_plus)
+	{
+		lw_expr_t e1;
+		int cval = 0;
+		
+		e1 = lw_expr_create();
+		e1 -> operands = E -> operands;
+		E -> operands = 0;
+		
+		for (o = e1 -> operands; o; o = o -> next)
+		{
+			if (o -> p -> type == lw_expr_type_int)
+				cval += o -> p -> value;
+			else
+				lw_expr_add_operand(E, o -> p);
+		}
+		lw_expr_destroy(e1);
+		if (cval)
+		{
+			e1 = lw_expr_build(lw_expr_type_int, cval);
+			lw_expr_add_operand(E, e1);
+			lw_expr_destroy(e1);
+		}
+	}
+
+	if (E -> value == lw_expr_oper_times)
+	{
+		lw_expr_t e1;
+		int cval = 1;
+		
+		e1 = lw_expr_create();
+		e1 -> operands = E -> operands;
+		E -> operands = 0;
+		
+		for (o = e1 -> operands; o; o = o -> next)
+		{
+			if (o -> p -> type == lw_expr_type_int)
+				cval *= o -> p -> value;
+			else
+				lw_expr_add_operand(E, o -> p);
+		}
+		lw_expr_destroy(e1);
+		if (cval != 1)
+		{
+			e1 = lw_expr_build(lw_expr_type_int, cval);
+			lw_expr_add_operand(E, e1);
+			lw_expr_destroy(e1);
+		}
+	}
+
 	if (E -> value == lw_expr_oper_times)
 	{
 		for (o = E -> operands; o; o = o -> next)
@@ -555,35 +757,74 @@
 		}
 	}
 	
+	// sort "constants" to the start of each operand list for + and *
+	if (E -> value == lw_expr_oper_plus || E -> value == lw_expr_oper_times)
+		lw_expr_simplify_sortconstfirst(E);
+	
 	// look for like terms and collect them together
 	if (E -> value == lw_expr_oper_plus)
 	{
+		struct lw_expr_opers *o2;
 		for (o = E -> operands; o; o = o -> next)
 		{
-			if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_times)
+			// skip constants
+			if (o -> p -> type == lw_expr_type_int)
+				continue;
+			
+			// we have a term to match
+			// (o -> p) is first term
+			for (o2 = o -> next; o2; o2 = o2 -> next)
 			{
-				// 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;
+				lw_expr_t e1, e2;
 				
-				for (o2 = o -> next; o2; o2 = o2 -> next)
+				if (o2 -> p -> type == lw_expr_type_int)
+					continue;
+
+				if (lw_expr_simplify_isliketerm(o -> p, o2 -> p))
 				{
+					int coef, coef2;
+					
+					// we have a like term here
+					// do something about it
+					if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_times)
+					{
+						if (o -> p -> operands -> p -> type == lw_expr_type_int)
+							coef = o -> p -> operands -> p -> value;
+						else
+							coef = 1;
+					}
+					else
+						coef = 1;
 					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 (o2 -> p -> operands -> p -> type == lw_expr_type_int)
+							coef2 = o2 -> p -> operands -> p -> value;
+						else
+							coef2 = 1;
 					}
+					else
+						coef2 = 1;
+					coef += coef2;
+					e1 = lw_expr_create();
+					e1 -> type = lw_expr_type_oper;
+					e1 -> value = lw_expr_oper_times;
+					if (coef != 1)
+					{
+						e2 = lw_expr_build(lw_expr_type_int, coef);
+						lw_expr_add_operand(e1, e2);
+						lw_expr_destroy(e2);
+					}
+					lw_expr_destroy(o -> p);
+					o -> p = e1;
+					for (o = o2 -> p -> operands; o; o = o -> next)
+					{
+						if (o -> p -> type == lw_expr_type_int)
+							continue;
+						lw_expr_add_operand(e1, o -> p);
+					}
+					lw_expr_destroy(o2 -> p);
+					o2 -> p = lw_expr_build(lw_expr_type_int, 0);
+					goto again;
 				}
 			}
 		}