[PATCH 03/10] Add type information to expression trees

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




This implements a rudimentary dynamic typing system for dtc expressions,
laying the groundwork for expressions of multiple types (e.g. string,
bytestring).  For now, we don't actually implement any types beyond
integer, though.

Signed-off-by: David Gibson <david@xxxxxxxxxxxxxxxxxxxxx>
---
 dtc-parser.y |  19 ++++++-----
 dtc.h        |  20 +++++++++--
 expression.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++--------
 3 files changed, 123 insertions(+), 25 deletions(-)

diff --git a/dtc-parser.y b/dtc-parser.y
index c5522e3..fbf5f3c 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -128,8 +128,7 @@ memreserves:
 memreserve:
 	  DT_MEMRESERVE expr_prim expr_prim ';'
 		{
-			$$ = build_reserve_entry(expr_int($2),
-						 expr_int($3));
+			$$ = build_reserve_entry(expr_int($2), expr_int($3));
 		}
 	| DT_LABEL memreserve
 		{
@@ -338,8 +337,8 @@ arrayprefix:
 	;
 
 expr_prim:
-	  DT_LITERAL 		{ $$ = expression_constant(&yylloc, $1); }
-	| DT_CHAR_LITERAL	{ $$ = expression_constant(&yylloc, $1); }
+	  DT_LITERAL 		{ $$ = expression_integer_constant(&yylloc, $1); }
+	| DT_CHAR_LITERAL	{ $$ = expression_integer_constant(&yylloc, $1); }
 	| '(' expr ')'
 		{
 			$$ = $2;
@@ -479,8 +478,12 @@ void yyerror(char const *s)
 
 static uint64_t expr_int(struct expression *expr)
 {
-	uint64_t val;
-	val = expression_evaluate(expr);
-	expression_free(expr);
-	return val;
+	struct expression_value v = expression_evaluate(expr, EXPR_INTEGER);
+
+	if (v.type == EXPR_VOID) {
+		treesource_error = true;
+		return -1;
+	}
+	assert(v.type == EXPR_INTEGER);
+	return v.value.integer;
 }
diff --git a/dtc.h b/dtc.h
index fed9d2d..95ed75e 100644
--- a/dtc.h
+++ b/dtc.h
@@ -223,20 +223,34 @@ uint32_t guess_boot_cpuid(struct node *tree);
 struct operator;
 struct srcpos;
 
+enum expr_type {
+	EXPR_VOID = 0, /* Missing or unspecified type */
+	EXPR_INTEGER,
+};
+
+struct expression_value {
+	enum expr_type type;
+	union {
+		uint64_t integer;
+	} value;
+};
+
 struct expression {
 	struct srcpos *loc;
 	struct operator *op;
 	int nargs;
 	union {
-		uint64_t constant;
+		struct expression_value constant;
 	} u;
 	struct expression *arg[0];
 };
 
 void expression_free(struct expression *expr);
-uint64_t expression_evaluate(struct expression *expr);
+struct expression_value expression_evaluate(struct expression *expr,
+					    enum expr_type context);
 
-struct expression *expression_constant(struct srcpos *pos, uint64_t val);
+struct expression *expression_integer_constant(struct srcpos *pos,
+					       uint64_t val);
 
 #define DEF_UNARY_OP(nm) \
 	struct expression *expression_##nm(struct srcpos *, \
diff --git a/expression.c b/expression.c
index 05d0df5..a89eea3 100644
--- a/expression.c
+++ b/expression.c
@@ -20,10 +20,25 @@
 #include "srcpos.h"
 #include "dtc.h"
 
+static const char *expression_typename(enum expr_type t)
+{
+	switch (t) {
+	case EXPR_VOID:
+		return "void";
+
+	case EXPR_INTEGER:
+		return "integer";
+
+	default:
+		assert(0);
+	}
+}
+
 struct operator {
 	const char *name;
 	unsigned nargs;
-	uint64_t (*evaluate)(struct expression *);
+	struct expression_value (*evaluate)(struct expression *,
+					    enum expr_type context);
 	void (*free)(struct expression *);
 };
 
@@ -70,12 +85,51 @@ void expression_free(struct expression *expr)
 	free(expr);
 }
 
-uint64_t expression_evaluate(struct expression *expr)
+static struct expression_value type_error(struct expression *expr,
+					  const char *fmt, ...)
+{
+	static const struct expression_value v = {
+		.type = EXPR_VOID,
+	};
+
+	va_list(ap);
+
+	va_start(ap, fmt);
+	srcpos_verror(expr->loc, "Type error", fmt, ap);
+	va_end(ap);
+
+	return v;
+}
+
+struct expression_value expression_evaluate(struct expression *expr,
+					    enum expr_type context)
 {
-	return expr->op->evaluate(expr);
+	struct expression_value v = expr->op->evaluate(expr, context);
+
+	if ((context != EXPR_VOID) && (context != v.type))
+		return type_error(expr, "Expected %s expression (found %s)",
+				  expression_typename(context),
+				  expression_typename(v.type));
+
+	return v;
 }
 
-static uint64_t op_eval_constant(struct expression *expr)
+#define EVALUATE(_v, _ex, _ctx) \
+	do { \
+		(_v) = expression_evaluate((_ex), (_ctx)); \
+		if ((_v).type == EXPR_VOID) \
+			return (_v); \
+	} while (0)
+
+#define EVALUATE_INT(_vi, _ex) \
+	do { \
+		struct expression_value _v; \
+		EVALUATE(_v, (_ex), EXPR_INTEGER); \
+		(_vi) = (_v).value.integer; \
+	} while (0)
+
+static struct expression_value op_eval_constant(struct expression *expr,
+						enum expr_type context)
 {
 	assert(expr->nargs == 0);
 	return expr->u.constant;
@@ -84,7 +138,9 @@ static struct operator op_constant = {
 	.name = "constant",
 	.evaluate = op_eval_constant,
 };
-struct expression *expression_constant(struct srcpos *loc, uint64_t val)
+
+static struct expression *__expression_constant(struct srcpos *loc,
+						struct expression_value val)
 {
 	struct expression *expr = expression_build(loc, &op_constant);
 
@@ -92,11 +148,27 @@ struct expression *expression_constant(struct srcpos *loc, uint64_t val)
 	return expr;
 }
 
+struct expression *expression_integer_constant(struct srcpos *pos,
+					       uint64_t val)
+{
+	struct expression_value v = {
+		.type = EXPR_INTEGER,
+		.value.integer = val,
+	};
+
+	return __expression_constant(pos, v);
+}
+
 #define INT_UNARY_OP(nm, cop) \
-	static uint64_t op_eval_##nm(struct expression *expr) \
+	static struct expression_value op_eval_##nm(struct expression *expr, \
+						    enum expr_type context) \
 	{ \
+		struct expression_value v = { .type = EXPR_INTEGER, }; \
+		uint64_t arg; \
 		assert(expr->nargs == 1); \
-		return cop expression_evaluate(expr->arg[0]);	\
+		EVALUATE_INT(arg, expr->arg[0]); \
+		v.value.integer = cop arg; \
+		return v; \
 	} \
 	static struct operator op_##nm = { \
 		.name = #cop, \
@@ -113,11 +185,16 @@ INT_UNARY_OP(bit_not, ~)
 INT_UNARY_OP(logic_not, !)
 
 #define INT_BINARY_OP(nm, cop) \
-	static uint64_t op_eval_##nm(struct expression *expr) \
+	static struct expression_value op_eval_##nm(struct expression *expr, \
+						    enum expr_type context) \
 	{ \
+		struct expression_value v = { .type = EXPR_INTEGER, }; \
+		uint64_t arg0, arg1; \
 		assert(expr->nargs == 2); \
-		return expression_evaluate(expr->arg[0]) \
-			cop expression_evaluate(expr->arg[1]);	\
+		EVALUATE_INT(arg0, expr->arg[0]); \
+		EVALUATE_INT(arg1, expr->arg[1]); \
+		v.value.integer = arg0 cop arg1; \
+		return v; \
 	} \
 	static struct operator op_##nm = { \
 		.name = #cop, \
@@ -155,12 +232,16 @@ INT_BINARY_OP(bit_or, |)
 INT_BINARY_OP(logic_and, &&)
 INT_BINARY_OP(logic_or, ||)
 
-static uint64_t op_eval_conditional(struct expression *expr)
+static struct expression_value op_eval_conditional(struct expression *expr,
+						   enum expr_type context)
 {
+	uint64_t cond;
+
 	assert(expr->nargs == 3);
-	return expression_evaluate(expr->arg[0])
-		? expression_evaluate(expr->arg[1])
-		: expression_evaluate(expr->arg[2]);
+	EVALUATE_INT(cond, expr->arg[0]);
+
+	return cond ? expression_evaluate(expr->arg[1], context)
+		: expression_evaluate(expr->arg[2], context);
 }
 static struct operator op_conditional = {
 	.name = "?:",
-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux