Patchwork [U-Boot,05/11] imximage: add expression evaluation

login
register
mail settings
Submitter Troy Kisky
Date Sept. 19, 2012, 12:03 a.m.
Message ID <1348012989-19674-6-git-send-email-troy.kisky@boundarydevices.com>
Download mbox | patch
Permalink /patch/184884/
State Changes Requested
Headers show

Comments

Troy Kisky - Sept. 19, 2012, 12:03 a.m.
Basic expressions with order precedence is
now supported.
ie. (----3 + ((1+2*3)/--2 + --5 *(8/4))) is 16.

Signed-off-by: Troy Kisky <troy.kisky@boundarydevices.com>
---
 tools/imximage.c |  172 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 162 insertions(+), 10 deletions(-)

Patch

diff --git a/tools/imximage.c b/tools/imximage.c
index 1e120354..2c5a622 100644
--- a/tools/imximage.c
+++ b/tools/imximage.c
@@ -380,20 +380,172 @@  char *grab_token(char *dest, int size, char *src)
 	return src;
 }
 
+char precedence[] = {
+	/* (  +  -  *  /  &  ^  |  ) */
+	   0, 2, 2, 1, 1, 3, 4, 5, 6
+};
+char unary_operations[]  = "(+-";
+char binary_operations[] = " +-*/&^|)";
+
+uint32_t do_func(uint32_t val1, uint32_t val2, int op)
+{
+	switch (op) {
+	case 1:
+		return val1 + val2;
+	case 2:
+		return val1 - val2;
+	case 3:
+		return val1 * val2;
+	case 4:
+		return val1 / val2;
+	case 5:
+		return val1 & val2;
+	case 6:
+		return val1 ^ val2;
+	case 7:
+		return val1 | val2;
+	}
+	fprintf(stderr, "Error: in func %s: val1=%d val2=%d op = %d\n",
+			__func__, val1, val2, op);
+	exit(EXIT_FAILURE);
+}
+
+int find_op(char c, char *p)
+{
+	int i;
+	for (i = 0; ; i++) {
+		if (c == p[i])
+			return i;
+		if (!p[i])
+			break;
+	}
+	return -1;
+}
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
 static uint32_t get_cfg_value(struct data_src *ds, uint32_t *pval)
 {
 	char *endptr;
-	uint32_t value;
+	int op_i = 0;
+	int val_i = 0;
+	unsigned char op[16];
+	uint32_t val[16];
+	int unary = 1;
+	char *p;
 
-	if (skip_separators(ds))
-		return -1;
-	errno = 0;
-	value = strtoul(ds->p, &endptr, 16);
-	if (errno || (ds->p == endptr))
-		return -1;
-	*pval = value;
-	ds->p = endptr;
-	return 0;
+	p = ds->p;
+	for (;;) {
+		char c;
+		int i, j;
+		char *ops = unary ? unary_operations : binary_operations;
+
+		if (unary) {
+			ds->p = p;
+			if (skip_separators(ds))
+				return -1;
+			p = ds->p;
+			c = *p;
+		} else {
+			for (;;) {
+				c = *p;
+				if ((c != ' ') && (c != '\t'))
+					break;
+				p++;
+			}
+		}
+		i = find_op(c, ops);
+		debug("%d,%c,%d:%s\n", i, c, unary, p);
+		if ((i < 0) && unary) {
+			if (val_i >= ARRAY_SIZE(val))
+				return -1;
+			errno = 0;
+			val[val_i++] = strtoul(p, &endptr, 16);
+			if (errno || (p == endptr)) {
+				ds->p = p;
+				return -1;
+			}
+			p = endptr;
+			unary = 0;
+			debug("val[%d]=%x,%d,%d\n", val_i - 1, val[val_i - 1],
+					op_i, val_i);
+do_unary:
+			while (op_i) {
+				j = op[op_i - 1];
+				if (!(j & 0x80))
+					break;
+				op_i--;
+				val[val_i - 1] = do_func(0,
+						val[val_i - 1], j & 0x7f);
+				debug("un:%d,%x,%d,%d\n", val[val_i - 1], j,
+						op_i, val_i);
+			}
+			continue;
+		}
+		if (i < 0) {
+			c = 0;
+			i = 8;
+		} else {
+			p++;
+		}
+		if (c == '(') {
+			if (op_i >= ARRAY_SIZE(op))
+				return -1;
+			op[op_i++] = i;
+			debug("op[%d]=%x,%d,%d\n", op_i - 1, op[op_i - 1],
+					op_i, val_i);
+			unary = 1;
+			continue;
+		}
+		for (;;) {
+			if (!op_i || unary)
+				break;
+			j = op[op_i - 1];
+			if (j == 0) {
+				if (c == ')') {
+					op_i--;
+					goto do_unary;
+				}
+				break;
+			}
+			if ((j & 0x80)) {
+				op_i--;
+				val[val_i - 1] = do_func(0,
+						val[val_i - 1], j & 0x7f);
+				debug("unary:%d,%x\n", val[val_i - 1], j);
+				continue;
+			}
+			if (precedence[i] < precedence[j])
+				break;
+			if (val_i < 2)
+				return -1;
+			op_i--;
+			val[val_i - 2] = do_func(val[val_i - 2],
+					val[val_i - 1], j);
+			val_i--;
+			debug("binary:%d,%x,%d,%d\n", val[val_i - 1], j,
+					op_i, val_i);
+		}
+		if (c == ')') {
+			fprintf(stderr, "Error: unmatched parenthesis\n");
+			return -1;
+		}
+		if (i == 8) {
+			if ((op_i != 0) || (val_i != 1)) {
+				fprintf(stderr, "Error: syntax %d %d\n",
+						op_i, val_i);
+				return -1;
+			}
+			ds->p = p;
+			*pval = val[0];
+			return 0;
+		}
+		if (op_i >= ARRAY_SIZE(op))
+			return -1;
+		op[op_i++] = i | (unary << 7);
+		debug("op[%d]=%x,%d,%d\n", op_i - 1, op[op_i - 1], op_i, val_i);
+		unary = 1;
+	}
 }
 
 static int parse_cmd_data(struct data_src *ds)