Both string and bytestring expression values are represented by a
bytestring internally to handle things like "\0abc".  So, the only real
distinction is that string expressions must evaluate to a bytestring which
has a \0 in the last bye.  For now the only actual "expressions" of these
types are literals, but we'll expand on that later.

Signed-off-by: David Gibson <[email protected]>
---
 data.c       | 26 ++++++++++++++++--
 dtc-parser.y | 58 +++++++++++++++++++++++++++++++---------
 dtc.h        | 10 +++++++
 expression.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 165 insertions(+), 16 deletions(-)

diff --git a/data.c b/data.c
index 4c50b12..4db1f2f 100644
--- a/data.c
+++ b/data.c
@@ -237,12 +237,17 @@ struct data data_append_align(struct data d, int align)
        return data_append_zeroes(d, newlen - d.len);
 }
 
-struct data data_add_marker(struct data d, enum markertype type, char *ref)
+static struct data data_add_marker_at(struct data d, enum markertype type,
+                                     int offset, char *ref)
 {
        struct marker *m;
 
+       m = d.markers;
+       for_each_marker(m)
+               assert(m->offset <= offset);
+
        m = xmalloc(sizeof(*m));
-       m->offset = d.len;
+       m->offset = offset;
        m->type = type;
        m->ref = ref;
        m->next = NULL;
@@ -250,6 +255,11 @@ struct data data_add_marker(struct data d, enum markertype 
type, char *ref)
        return data_append_markers(d, m);
 }
 
+struct data data_add_marker(struct data d, enum markertype type, char *ref)
+{
+       return data_add_marker_at(d, type, d.len, ref);
+}
+
 bool data_is_one_string(struct data d)
 {
        int i;
@@ -267,3 +277,15 @@ bool data_is_one_string(struct data d)
 
        return true;
 }
+
+struct data data_clone(struct data d)
+{
+       struct data clone = data_copy_mem(d.val, d.len);
+       struct marker *m = d.markers;
+
+       for_each_marker(m)
+               clone = data_add_marker_at(clone, m->type,
+                                          m->offset, strdup(m->ref));
+
+       return clone;
+}
diff --git a/dtc-parser.y b/dtc-parser.y
index fbf5f3c..e4df947 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -35,6 +35,8 @@ extern struct boot_info *the_boot_info;
 extern bool treesource_error;
 
 static uint64_t expr_int(struct expression *expr);
+static const char *expr_str(struct expression *expr);
+static struct data expr_bytestring(struct expression *expr);
 
 #define UNOP(loc, op, a)       (expression_##op(&loc, (a)))
 #define BINOP(loc, op, a, b)   (expression_##op(&loc, (a), (b)))
@@ -80,7 +82,7 @@ static uint64_t expr_int(struct expression *expr);
 %type <re> memreserve
 %type <re> memreserves
 %type <array> arrayprefix
-%type <data> bytestring
+%type <data> bytestring_literal
 %type <prop> propdef
 %type <proplist> proplist
 
@@ -209,32 +211,30 @@ propdef:
        ;
 
 propdata:
-         propdataprefix DT_STRING
+         propdataprefix expr
                {
-                       $$ = data_merge($1, $2);
+                       struct data d = expr_bytestring($2);
+                       $$ = data_merge($1, d);
                }
        | propdataprefix arrayprefix '>'
                {
                        $$ = data_merge($1, $2.data);
                }
-       | propdataprefix '[' bytestring ']'
-               {
-                       $$ = data_merge($1, $3);
-               }
        | propdataprefix DT_REF
                {
                        $$ = data_add_marker($1, REF_PATH, $2);
                }
-       | propdataprefix DT_INCBIN '(' DT_STRING ',' expr_prim ',' expr_prim ')'
+       | propdataprefix DT_INCBIN '(' expr_prim ',' expr_prim ',' expr_prim ')'
                {
-                       FILE *f = srcfile_relative_open($4.val, NULL);
+                       const char *filename = expr_str($4);
+                       FILE *f = srcfile_relative_open(filename, NULL);
                        off_t offset = expr_int($6);
                        struct data d;
 
                        if (offset != 0)
                                if (fseek(f, offset, SEEK_SET) != 0)
                                        die("Couldn't seek to offset %llu in 
\"%s\": %s",
-                                           (unsigned long long)offset, $4.val,
+                                           (unsigned long long)offset, 
filename,
                                            strerror(errno));
 
                        d = data_copy_file(f, expr_int($8));
@@ -339,6 +339,14 @@ arrayprefix:
 expr_prim:
          DT_LITERAL            { $$ = expression_integer_constant(&yylloc, 
$1); }
        | DT_CHAR_LITERAL       { $$ = expression_integer_constant(&yylloc, 
$1); }
+       | DT_STRING
+               {
+                       $$ = expression_string_constant(&yylloc, $1);
+               }
+       | '[' bytestring_literal ']'
+               {
+                       $$ = expression_bytestring_constant(&@2, $2);
+               }
        | '(' expr ')'
                {
                        $$ = $2;
@@ -422,16 +430,16 @@ expr_unary:
        | '!' expr_unary { $$ = UNOP(@$, logic_not, $2); }
        ;
 
-bytestring:
+bytestring_literal:
          /* empty */
                {
                        $$ = empty_data;
                }
-       | bytestring DT_BYTE
+       | bytestring_literal DT_BYTE
                {
                        $$ = data_append_byte($1, $2);
                }
-       | bytestring DT_LABEL
+       | bytestring_literal DT_LABEL
                {
                        $$ = data_add_marker($1, LABEL, $2);
                }
@@ -487,3 +495,27 @@ static uint64_t expr_int(struct expression *expr)
        assert(v.type == EXPR_INTEGER);
        return v.value.integer;
 }
+
+static const char *expr_str(struct expression *expr)
+{
+       struct expression_value v = expression_evaluate(expr, EXPR_STRING);
+
+       if (v.type == EXPR_VOID) {
+               treesource_error = true;
+               return "";
+       }
+       assert(v.type == EXPR_STRING);
+       return v.value.d.val;
+}
+
+static struct data expr_bytestring(struct expression *expr)
+{
+       struct expression_value v = expression_evaluate(expr, EXPR_BYTESTRING);
+
+       if (v.type == EXPR_VOID) {
+               treesource_error = true;
+               return empty_data;
+       }
+       assert(v.type == EXPR_BYTESTRING);
+       return v.value.d;
+}
diff --git a/dtc.h b/dtc.h
index 95ed75e..0b644d2 100644
--- a/dtc.h
+++ b/dtc.h
@@ -120,6 +120,8 @@ struct data data_add_marker(struct data d, enum markertype 
type, char *ref);
 
 bool data_is_one_string(struct data d);
 
+struct data data_clone(struct data d);
+
 /* DT constraints */
 
 #define MAX_PROPNAME_LEN       31
@@ -226,12 +228,15 @@ struct srcpos;
 enum expr_type {
        EXPR_VOID = 0, /* Missing or unspecified type */
        EXPR_INTEGER,
+       EXPR_STRING,
+       EXPR_BYTESTRING,
 };
 
 struct expression_value {
        enum expr_type type;
        union {
                uint64_t integer;
+               struct data d;
        } value;
 };
 
@@ -252,6 +257,11 @@ struct expression_value expression_evaluate(struct 
expression *expr,
 struct expression *expression_integer_constant(struct srcpos *pos,
                                               uint64_t val);
 
+struct expression *expression_string_constant(struct srcpos *pos,
+                                             struct data d);
+struct expression *expression_bytestring_constant(struct srcpos *pos,
+                                                 struct data val);
+
 #define DEF_UNARY_OP(nm) \
        struct expression *expression_##nm(struct srcpos *, \
                                           struct expression *)
diff --git a/expression.c b/expression.c
index a89eea3..4ecd84a 100644
--- a/expression.c
+++ b/expression.c
@@ -29,11 +29,49 @@ static const char *expression_typename(enum expr_type t)
        case EXPR_INTEGER:
                return "integer";
 
+       case EXPR_STRING:
+               return "string";
+
+       case EXPR_BYTESTRING:
+               return "bytestring";
+
        default:
                assert(0);
        }
 }
 
+static struct expression_value value_clone(struct expression_value val)
+{
+       struct expression_value clone = val;
+
+       switch (val.type) {
+       case EXPR_STRING:
+       case EXPR_BYTESTRING:
+               clone.value.d = data_clone(val.value.d);
+               break;
+
+       default:
+               /* nothing more to do */
+               ;
+       }
+
+       return clone;
+}
+
+static void value_free(struct expression_value val)
+{
+       switch (val.type) {
+       case EXPR_STRING:
+       case EXPR_BYTESTRING:
+               data_free(val.value.d);
+               break;
+
+       default:
+               /* nothing to do */
+               ;
+       }
+}
+
 struct operator {
        const char *name;
        unsigned nargs;
@@ -106,6 +144,11 @@ struct expression_value expression_evaluate(struct 
expression *expr,
 {
        struct expression_value v = expr->op->evaluate(expr, context);
 
+       /* Strings can be promoted to bytestrings */
+       if ((v.type == EXPR_STRING)
+           && (context == EXPR_BYTESTRING))
+               v.type = EXPR_BYTESTRING;
+
        if ((context != EXPR_VOID) && (context != v.type))
                return type_error(expr, "Expected %s expression (found %s)",
                                  expression_typename(context),
@@ -128,15 +171,35 @@ struct expression_value expression_evaluate(struct 
expression *expr,
                (_vi) = (_v).value.integer; \
        } while (0)
 
+#define EVALUATE_STR(_vs, _ex) \
+       do { \
+               struct expression_value _v; \
+               EVALUATE(_v, (_ex), EXPR_STRING); \
+               (_vs) = (_v).value.d; \
+       } while (0)
+
+#define EVALUATE_BS(_vd, _ex) \
+       do { \
+               struct expression_value _v; \
+               EVALUATE(_v, (_ex), EXPR_BYTESTRING); \
+               (_vd) = (_v).value.d; \
+       } while (0)
+
 static struct expression_value op_eval_constant(struct expression *expr,
                                                enum expr_type context)
 {
        assert(expr->nargs == 0);
-       return expr->u.constant;
+       return value_clone(expr->u.constant);
+}
+static void op_free_constant(struct expression *expr)
+{
+       value_free(expr->u.constant);
 }
+
 static struct operator op_constant = {
        .name = "constant",
        .evaluate = op_eval_constant,
+       .free = op_free_constant,
 };
 
 static struct expression *__expression_constant(struct srcpos *loc,
@@ -159,6 +222,28 @@ struct expression *expression_integer_constant(struct 
srcpos *pos,
        return __expression_constant(pos, v);
 }
 
+struct expression *expression_string_constant(struct srcpos *pos,
+                                             struct data val)
+{
+       struct expression_value v = {
+               .type = EXPR_STRING,
+               .value.d = val,
+       };
+
+       return __expression_constant(pos, v);
+}
+
+struct expression *expression_bytestring_constant(struct srcpos *pos,
+                                                 struct data val)
+{
+       struct expression_value v = {
+               .type = EXPR_BYTESTRING,
+               .value.d = val,
+       };
+
+       return __expression_constant(pos, v);
+}
+
 #define INT_UNARY_OP(nm, cop) \
        static struct expression_value op_eval_##nm(struct expression *expr, \
                                                    enum expr_type context) \
-- 
1.8.5.3

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

Reply via email to