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 <da...@gibson.dropbear.id.au>
---
 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to