summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2014-02-16 22:38:23 +1100
committerDavid Gibson <david@gibson.dropbear.id.au>2014-03-03 10:51:50 +1100
commit2168f9d921e1b11a9a8b3e825772e60a5930203a (patch)
tree9ab7a08e7472c251f442cb6b57869b79225c9cd9
parent11371d7d4e5dd7a15d486321c54a92373475b8ac (diff)
downloaddevice-tree-compiler-2168f9d921e1b11a9a8b3e825772e60a5930203a.tar.gz
Add string and bytestring expression types
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 <david@gibson.dropbear.id.au>
-rw-r--r--data.c26
-rw-r--r--dtc-parser.y58
-rw-r--r--dtc.h10
-rw-r--r--expression.c87
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) \