* [0/10] RFC: A new start on richer dtc expression support [REPOST]
@ 2014-02-27 11:21 David Gibson
[not found] ` <1393500099-28544-1-git-send-email-david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
0 siblings, 1 reply; 11+ messages in thread
From: David Gibson @ 2014-02-27 11:21 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA; +Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ
I previously sent these patches to the new devicetree-compiler, but I
suspect not many people had subscribed so I'm resending to the
devicetree list.
So, we've been talking about richer expression / constant / function /
macro support for dtc since forever. So far attempts to start on that
haven't gotten very far (in large part because of my pickiness about
new syntax).
Anyway, I've started having a new crack at this. This patch series
implements the infrastructure for "runtime" evaluated expressions.
For now they're just constructed and immediately evaluated, so they're
not quite usable for user-defined functions yet, but it's a big step
towards that.
10/10 is the only patch in this series which implements new
user-visible functionality, the rest are just internal reworking.
10/10 experiments with the new mechanisms to implement string append
and repeat operators - I'm not 100% sure if I'm happy with the syntax
used for this yet (overloaded + and *, like Python). Suggestions
welcome.
This is indirectly relevant to the schema checking concepts current
much discused. Any schema language is likely to want richer
expression support than we currently have to be useful. In addition,
I expect we'll need data structures very similar to the expression
trees implemented here to keep track of schema "patterns" or other
pieces.
These patches can also be found in the 'expressions' branch at
git://git.kernel.org/pub/scm/utils/dtc/dtc.git. [NOTE: I'm
considering this an experimental branch for now, which will be rebased
at whim].
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 01/10] First cut at expression trees
[not found] ` <1393500099-28544-1-git-send-email-david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
@ 2014-02-27 11:21 ` David Gibson
2014-02-27 11:21 ` [PATCH 02/10] Add srcpos information to expressions David Gibson
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: David Gibson @ 2014-02-27 11:21 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ, David Gibson
At the moment, the integer expressions supported by dtc are always constant
expressions, and are evaluated as we parse. That's nice and simple but
limits us in a number of ways. It makes named constants awkward to
implement and user defined functions more or less impossible.
As a first step to allowing more possibilities, create the structures we
need to represent expressions at runtime. For now we just construct them
in the parser, then immediately evaluate, but one thing at a time.
Signed-off-by: David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
---
Makefile.dtc | 1 +
dtc-parser.y | 173 +++++++++++++++++++++++++++++++++--------------------------
dtc.h | 58 ++++++++++++++++++++
expression.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 321 insertions(+), 76 deletions(-)
create mode 100644 expression.c
diff --git a/Makefile.dtc b/Makefile.dtc
index bece49b..d41d9c5 100644
--- a/Makefile.dtc
+++ b/Makefile.dtc
@@ -7,6 +7,7 @@ DTC_SRCS = \
checks.c \
data.c \
dtc.c \
+ expression.o \
flattree.c \
fstree.c \
livetree.c \
diff --git a/dtc-parser.y b/dtc-parser.y
index ea57e0a..5e2348e 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -33,6 +33,11 @@ extern void yyerror(char const *s);
extern struct boot_info *the_boot_info;
extern bool treesource_error;
+
+static uint64_t expr_int(struct expression *expr);
+
+#define UNOP(op, a) (expression_##op((a)))
+#define BINOP(op, a, b) (expression_##op((a), (b)))
%}
%union {
@@ -52,6 +57,7 @@ extern bool treesource_error;
struct node *nodelist;
struct reserve_info *re;
uint64_t integer;
+ struct expression *expr;
}
%token DT_V1
@@ -83,20 +89,20 @@ extern bool treesource_error;
%type <node> subnode
%type <nodelist> subnodes
-%type <integer> integer_prim
-%type <integer> integer_unary
-%type <integer> integer_mul
-%type <integer> integer_add
-%type <integer> integer_shift
-%type <integer> integer_rela
-%type <integer> integer_eq
-%type <integer> integer_bitand
-%type <integer> integer_bitxor
-%type <integer> integer_bitor
-%type <integer> integer_and
-%type <integer> integer_or
-%type <integer> integer_trinary
-%type <integer> integer_expr
+%type <expr> expr_prim
+%type <expr> expr_unary
+%type <expr> expr_mul
+%type <expr> expr_add
+%type <expr> expr_shift
+%type <expr> expr_rela
+%type <expr> expr_eq
+%type <expr> expr_bitand
+%type <expr> expr_bitxor
+%type <expr> expr_bitor
+%type <expr> expr_and
+%type <expr> expr_or
+%type <expr> expr_conditional
+%type <expr> expr
%%
@@ -120,9 +126,10 @@ memreserves:
;
memreserve:
- DT_MEMRESERVE integer_prim integer_prim ';'
+ DT_MEMRESERVE expr_prim expr_prim ';'
{
- $$ = build_reserve_entry($2, $3);
+ $$ = build_reserve_entry(expr_int($2),
+ expr_int($3));
}
| DT_LABEL memreserve
{
@@ -219,18 +226,19 @@ propdata:
{
$$ = data_add_marker($1, REF_PATH, $2);
}
- | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
+ | propdataprefix DT_INCBIN '(' DT_STRING ',' expr_prim ',' expr_prim ')'
{
FILE *f = srcfile_relative_open($4.val, NULL);
+ off_t offset = expr_int($6);
struct data d;
- if ($6 != 0)
- if (fseek(f, $6, SEEK_SET) != 0)
+ if (offset != 0)
+ if (fseek(f, offset, SEEK_SET) != 0)
die("Couldn't seek to offset %llu in \"%s\": %s",
- (unsigned long long)$6, $4.val,
+ (unsigned long long)offset, $4.val,
strerror(errno));
- d = data_copy_file(f, $8);
+ d = data_copy_file(f, expr_int($8));
$$ = data_merge($1, d);
fclose(f);
@@ -288,8 +296,10 @@ arrayprefix:
$$.data = empty_data;
$$.bits = 32;
}
- | arrayprefix integer_prim
+ | arrayprefix expr_prim
{
+ uint64_t val = expr_int($2);
+
if ($1.bits < 64) {
uint64_t mask = (1ULL << $1.bits) - 1;
/*
@@ -300,12 +310,12 @@ arrayprefix:
* within the mask to one (i.e. | in the
* mask), all bits are one.
*/
- if (($2 > mask) && (($2 | mask) != -1ULL))
+ if ((val > mask) && ((val | mask) != -1ULL))
ERROR(&@2, "Value out of range for"
" %d-bit array element", $1.bits);
}
- $$.data = data_append_integer($1.data, $2, $1.bits);
+ $$.data = data_append_integer($1.data, val, $1.bits);
}
| arrayprefix DT_REF
{
@@ -327,87 +337,90 @@ arrayprefix:
}
;
-integer_prim:
- DT_LITERAL
- | DT_CHAR_LITERAL
- | '(' integer_expr ')'
+expr_prim:
+ DT_LITERAL { $$ = expression_constant($1); }
+ | DT_CHAR_LITERAL { $$ = expression_constant($1); }
+ | '(' expr ')'
{
$$ = $2;
}
;
-integer_expr:
- integer_trinary
+expr:
+ expr_conditional
;
-integer_trinary:
- integer_or
- | integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
+expr_conditional:
+ expr_or
+ | expr_or '?' expr ':' expr_conditional
+ {
+ $$ = expression_conditional($1, $3, $5);
+ }
;
-integer_or:
- integer_and
- | integer_or DT_OR integer_and { $$ = $1 || $3; }
+expr_or:
+ expr_and
+ | expr_or DT_OR expr_and { $$ = BINOP(logic_or, $1, $3); }
;
-integer_and:
- integer_bitor
- | integer_and DT_AND integer_bitor { $$ = $1 && $3; }
+expr_and:
+ expr_bitor
+ | expr_and DT_AND expr_bitor { $$ = BINOP(logic_and, $1, $3); }
;
-integer_bitor:
- integer_bitxor
- | integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
+expr_bitor:
+ expr_bitxor
+ | expr_bitor '|' expr_bitxor { $$ = BINOP(bit_or, $1, $3); }
;
-integer_bitxor:
- integer_bitand
- | integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
+expr_bitxor:
+ expr_bitand
+ | expr_bitxor '^' expr_bitand { $$ = BINOP(bit_xor, $1, $3); }
;
-integer_bitand:
- integer_eq
- | integer_bitand '&' integer_eq { $$ = $1 & $3; }
+expr_bitand:
+ expr_eq
+ | expr_bitand '&' expr_eq { $$ = BINOP(bit_and, $1, $3); }
;
-integer_eq:
- integer_rela
- | integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
- | integer_eq DT_NE integer_rela { $$ = $1 != $3; }
+expr_eq:
+ expr_rela
+ | expr_eq DT_EQ expr_rela { $$ = BINOP(eq, $1, $3); }
+ | expr_eq DT_NE expr_rela { $$ = BINOP(ne, $1, $3); }
;
-integer_rela:
- integer_shift
- | integer_rela '<' integer_shift { $$ = $1 < $3; }
- | integer_rela '>' integer_shift { $$ = $1 > $3; }
- | integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
- | integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
+expr_rela:
+ expr_shift
+ | expr_rela '<' expr_shift { $$ = BINOP(lt, $1, $3); }
+ | expr_rela '>' expr_shift { $$ = BINOP(gt, $1, $3); }
+ | expr_rela DT_LE expr_shift { $$ = BINOP(le, $1, $3); }
+ | expr_rela DT_GE expr_shift { $$ = BINOP(ge, $1, $3); }
;
-integer_shift:
- integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
- | integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
- | integer_add
+expr_shift:
+ expr_shift DT_LSHIFT expr_add { $$ = BINOP(lshift, $1, $3); }
+ | expr_shift DT_RSHIFT expr_add { $$ = BINOP(rshift, $1, $3); }
+ | expr_add
;
-integer_add:
- integer_add '+' integer_mul { $$ = $1 + $3; }
- | integer_add '-' integer_mul { $$ = $1 - $3; }
- | integer_mul
+expr_add:
+ expr_add '+' expr_mul { $$ = BINOP(add, $1, $3); }
+ | expr_add '-' expr_mul { $$ = BINOP(sub, $1, $3); }
+ | expr_mul
;
-integer_mul:
- integer_mul '*' integer_unary { $$ = $1 * $3; }
- | integer_mul '/' integer_unary { $$ = $1 / $3; }
- | integer_mul '%' integer_unary { $$ = $1 % $3; }
- | integer_unary
+expr_mul:
+ expr_mul '*' expr_unary { $$ = BINOP(mul, $1, $3); }
+ | expr_mul '/' expr_unary { $$ = BINOP(div, $1, $3); }
+ | expr_mul '%' expr_unary { $$ = BINOP(mod, $1, $3); }
+ | expr_unary
;
-integer_unary:
- integer_prim
- | '-' integer_unary { $$ = -$2; }
- | '~' integer_unary { $$ = ~$2; }
- | '!' integer_unary { $$ = !$2; }
+expr_unary:
+ expr_prim
+ | '-' expr_unary { $$ = UNOP(negate, $2); }
+ | '~' expr_unary { $$ = UNOP(bit_not, $2); }
+ | '!' expr_unary { $$ = UNOP(logic_not, $2); }
;
bytestring:
@@ -463,3 +476,11 @@ void yyerror(char const *s)
{
ERROR(&yylloc, "%s", s);
}
+
+static uint64_t expr_int(struct expression *expr)
+{
+ uint64_t val;
+ val = expression_evaluate(expr);
+ expression_free(expr);
+ return val;
+}
diff --git a/dtc.h b/dtc.h
index 20de073..c40e9d7 100644
--- a/dtc.h
+++ b/dtc.h
@@ -218,6 +218,64 @@ cell_t get_node_phandle(struct node *root, struct node *node);
uint32_t guess_boot_cpuid(struct node *tree);
+/* Expressions */
+
+struct operator;
+
+struct expression {
+ struct operator *op;
+ int nargs;
+ union {
+ uint64_t constant;
+ } u;
+ struct expression *arg[0];
+};
+
+void expression_free(struct expression *expr);
+uint64_t expression_evaluate(struct expression *expr);
+
+struct expression *expression_constant(uint64_t val);
+
+#define DEF_UNARY_OP(nm) \
+ struct expression *expression_##nm(struct expression *)
+DEF_UNARY_OP(negate);
+DEF_UNARY_OP(bit_not);
+DEF_UNARY_OP(logic_not);
+
+#define DEF_BINARY_OP(nm) \
+ struct expression *expression_##nm(struct expression *, struct expression *)
+DEF_BINARY_OP(mod);
+DEF_BINARY_OP(div);
+DEF_BINARY_OP(mul);
+
+DEF_BINARY_OP(add);
+DEF_BINARY_OP(sub);
+
+DEF_BINARY_OP(lshift);
+DEF_BINARY_OP(rshift);
+
+DEF_BINARY_OP(lt);
+DEF_BINARY_OP(gt);
+DEF_BINARY_OP(le);
+DEF_BINARY_OP(ge);
+
+DEF_BINARY_OP(eq);
+DEF_BINARY_OP(ne);
+
+DEF_BINARY_OP(bit_and);
+
+DEF_BINARY_OP(bit_xor);
+
+DEF_BINARY_OP(bit_or);
+
+DEF_BINARY_OP(logic_and);
+
+DEF_BINARY_OP(logic_or);
+
+struct expression *expression_conditional(struct expression *,
+ struct expression *,
+ struct expression *);
+
/* Boot info (tree plus memreserve information */
struct reserve_info {
diff --git a/expression.c b/expression.c
new file mode 100644
index 0000000..dd31a37
--- /dev/null
+++ b/expression.c
@@ -0,0 +1,165 @@
+/*
+ * (C) Copyright David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>, Red Hat 2013.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "dtc.h"
+
+struct operator {
+ const char *name;
+ unsigned nargs;
+ uint64_t (*evaluate)(struct expression *);
+ void (*free)(struct expression *);
+};
+
+static struct expression *__expression_build(struct operator *op, ...)
+{
+ int nargs = 0;
+ struct expression *expr;
+ va_list ap;
+ int i;
+
+ /* Sanity check number of arguments */
+ va_start(ap, op);
+ while (va_arg(ap, struct expression *) != NULL)
+ nargs++;
+ va_end(ap);
+
+ expr = xmalloc(sizeof(*expr) + nargs*sizeof(struct expression *));
+ expr->op = op;
+ expr->nargs = nargs;
+
+ va_start(ap, op);
+ for (i = 0; i < nargs; i++)
+ expr->arg[i] = va_arg(ap, struct expression *);
+ va_end(ap);
+
+ return expr;
+}
+#define expression_build(...) \
+ (__expression_build(__VA_ARGS__, NULL))
+
+void expression_free(struct expression *expr)
+{
+ int i;
+
+ for (i = 0; i < expr->nargs; i++)
+ expression_free(expr->arg[i]);
+ if (expr->op->free)
+ expr->op->free(expr);
+ free(expr);
+}
+
+uint64_t expression_evaluate(struct expression *expr)
+{
+ return expr->op->evaluate(expr);
+}
+
+static uint64_t op_eval_constant(struct expression *expr)
+{
+ assert(expr->nargs == 0);
+ return expr->u.constant;
+}
+static struct operator op_constant = {
+ .name = "constant",
+ .evaluate = op_eval_constant,
+};
+struct expression *expression_constant(uint64_t val)
+{
+ struct expression *expr = expression_build(&op_constant);
+
+ expr->u.constant = val;
+ return expr;
+}
+
+#define INT_UNARY_OP(nm, cop) \
+ static uint64_t op_eval_##nm(struct expression *expr) \
+ { \
+ assert(expr->nargs == 1); \
+ return cop expression_evaluate(expr->arg[0]); \
+ } \
+ static struct operator op_##nm = { \
+ .name = #cop, \
+ .evaluate = op_eval_##nm, \
+ }; \
+ struct expression *expression_##nm(struct expression *arg) \
+ { \
+ return expression_build(&op_##nm, arg); \
+ }
+
+INT_UNARY_OP(negate, -)
+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) \
+ { \
+ assert(expr->nargs == 2); \
+ return expression_evaluate(expr->arg[0]) \
+ cop expression_evaluate(expr->arg[1]); \
+ } \
+ static struct operator op_##nm = { \
+ .name = #cop, \
+ .evaluate = op_eval_##nm, \
+ }; \
+ struct expression *expression_##nm(struct expression *arg1, struct expression *arg2) \
+ { \
+ return expression_build(&op_##nm, arg1, arg2); \
+ }
+
+INT_BINARY_OP(mod, %)
+INT_BINARY_OP(div, /)
+INT_BINARY_OP(mul, *)
+
+INT_BINARY_OP(add, +)
+INT_BINARY_OP(sub, -)
+
+INT_BINARY_OP(lshift, <<)
+INT_BINARY_OP(rshift, >>)
+
+INT_BINARY_OP(lt, <)
+INT_BINARY_OP(gt, >)
+INT_BINARY_OP(le, <=)
+INT_BINARY_OP(ge, >=)
+
+INT_BINARY_OP(eq, ==)
+INT_BINARY_OP(ne, !=)
+
+INT_BINARY_OP(bit_and, &)
+INT_BINARY_OP(bit_xor, ^)
+INT_BINARY_OP(bit_or, |)
+
+INT_BINARY_OP(logic_and, &&)
+INT_BINARY_OP(logic_or, ||)
+
+static uint64_t op_eval_conditional(struct expression *expr)
+{
+ assert(expr->nargs == 3);
+ return expression_evaluate(expr->arg[0])
+ ? expression_evaluate(expr->arg[1])
+ : expression_evaluate(expr->arg[2]);
+}
+static struct operator op_conditional = {
+ .name = "?:",
+ .evaluate = op_eval_conditional,
+};
+struct expression *expression_conditional(struct expression *arg1, struct expression *arg2,
+ struct expression *arg3)
+{
+ return expression_build(&op_conditional, arg1, arg2, arg3);
+}
--
1.8.5.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 02/10] Add srcpos information to expressions
[not found] ` <1393500099-28544-1-git-send-email-david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
2014-02-27 11:21 ` [PATCH 01/10] First cut at expression trees David Gibson
@ 2014-02-27 11:21 ` David Gibson
2014-02-27 11:21 ` [PATCH 03/10] Add type information to expression trees David Gibson
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: David Gibson @ 2014-02-27 11:21 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ, David Gibson
This patch allows information about source locations to be attached to
expression structures. We'll need this information later on in order to
provide reasonable error messages.
Signed-off-by: David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
---
dtc-parser.y | 52 ++++++++++++++++++++++++++--------------------------
dtc.h | 14 ++++++++++----
expression.c | 34 ++++++++++++++++++++++------------
3 files changed, 58 insertions(+), 42 deletions(-)
diff --git a/dtc-parser.y b/dtc-parser.y
index 5e2348e..c5522e3 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -36,8 +36,8 @@ extern bool treesource_error;
static uint64_t expr_int(struct expression *expr);
-#define UNOP(op, a) (expression_##op((a)))
-#define BINOP(op, a, b) (expression_##op((a), (b)))
+#define UNOP(loc, op, a) (expression_##op(&loc, (a)))
+#define BINOP(loc, op, a, b) (expression_##op(&loc, (a), (b)))
%}
%union {
@@ -338,8 +338,8 @@ arrayprefix:
;
expr_prim:
- DT_LITERAL { $$ = expression_constant($1); }
- | DT_CHAR_LITERAL { $$ = expression_constant($1); }
+ DT_LITERAL { $$ = expression_constant(&yylloc, $1); }
+ | DT_CHAR_LITERAL { $$ = expression_constant(&yylloc, $1); }
| '(' expr ')'
{
$$ = $2;
@@ -354,73 +354,73 @@ expr_conditional:
expr_or
| expr_or '?' expr ':' expr_conditional
{
- $$ = expression_conditional($1, $3, $5);
+ $$ = expression_conditional(&yylloc, $1, $3, $5);
}
;
expr_or:
expr_and
- | expr_or DT_OR expr_and { $$ = BINOP(logic_or, $1, $3); }
+ | expr_or DT_OR expr_and { $$ = BINOP(@$, logic_or, $1, $3); }
;
expr_and:
expr_bitor
- | expr_and DT_AND expr_bitor { $$ = BINOP(logic_and, $1, $3); }
+ | expr_and DT_AND expr_bitor { $$ = BINOP(@$, logic_and, $1, $3); }
;
expr_bitor:
expr_bitxor
- | expr_bitor '|' expr_bitxor { $$ = BINOP(bit_or, $1, $3); }
+ | expr_bitor '|' expr_bitxor { $$ = BINOP(@$, bit_or, $1, $3); }
;
expr_bitxor:
expr_bitand
- | expr_bitxor '^' expr_bitand { $$ = BINOP(bit_xor, $1, $3); }
+ | expr_bitxor '^' expr_bitand { $$ = BINOP(@$, bit_xor, $1, $3); }
;
expr_bitand:
expr_eq
- | expr_bitand '&' expr_eq { $$ = BINOP(bit_and, $1, $3); }
+ | expr_bitand '&' expr_eq { $$ = BINOP(@$, bit_and, $1, $3); }
;
expr_eq:
expr_rela
- | expr_eq DT_EQ expr_rela { $$ = BINOP(eq, $1, $3); }
- | expr_eq DT_NE expr_rela { $$ = BINOP(ne, $1, $3); }
+ | expr_eq DT_EQ expr_rela { $$ = BINOP(@$, eq, $1, $3); }
+ | expr_eq DT_NE expr_rela { $$ = BINOP(@$, ne, $1, $3); }
;
expr_rela:
expr_shift
- | expr_rela '<' expr_shift { $$ = BINOP(lt, $1, $3); }
- | expr_rela '>' expr_shift { $$ = BINOP(gt, $1, $3); }
- | expr_rela DT_LE expr_shift { $$ = BINOP(le, $1, $3); }
- | expr_rela DT_GE expr_shift { $$ = BINOP(ge, $1, $3); }
+ | expr_rela '<' expr_shift { $$ = BINOP(@$, lt, $1, $3); }
+ | expr_rela '>' expr_shift { $$ = BINOP(@$, gt, $1, $3); }
+ | expr_rela DT_LE expr_shift { $$ = BINOP(@$, le, $1, $3); }
+ | expr_rela DT_GE expr_shift { $$ = BINOP(@$, ge, $1, $3); }
;
expr_shift:
- expr_shift DT_LSHIFT expr_add { $$ = BINOP(lshift, $1, $3); }
- | expr_shift DT_RSHIFT expr_add { $$ = BINOP(rshift, $1, $3); }
+ expr_shift DT_LSHIFT expr_add { $$ = BINOP(@$, lshift, $1, $3); }
+ | expr_shift DT_RSHIFT expr_add { $$ = BINOP(@$, rshift, $1, $3); }
| expr_add
;
expr_add:
- expr_add '+' expr_mul { $$ = BINOP(add, $1, $3); }
- | expr_add '-' expr_mul { $$ = BINOP(sub, $1, $3); }
+ expr_add '+' expr_mul { $$ = BINOP(@$, add, $1, $3); }
+ | expr_add '-' expr_mul { $$ = BINOP(@$, sub, $1, $3); }
| expr_mul
;
expr_mul:
- expr_mul '*' expr_unary { $$ = BINOP(mul, $1, $3); }
- | expr_mul '/' expr_unary { $$ = BINOP(div, $1, $3); }
- | expr_mul '%' expr_unary { $$ = BINOP(mod, $1, $3); }
+ expr_mul '*' expr_unary { $$ = BINOP(@$, mul, $1, $3); }
+ | expr_mul '/' expr_unary { $$ = BINOP(@$, div, $1, $3); }
+ | expr_mul '%' expr_unary { $$ = BINOP(@$, mod, $1, $3); }
| expr_unary
;
expr_unary:
expr_prim
- | '-' expr_unary { $$ = UNOP(negate, $2); }
- | '~' expr_unary { $$ = UNOP(bit_not, $2); }
- | '!' expr_unary { $$ = UNOP(logic_not, $2); }
+ | '-' expr_unary { $$ = UNOP(@$, negate, $2); }
+ | '~' expr_unary { $$ = UNOP(@$, bit_not, $2); }
+ | '!' expr_unary { $$ = UNOP(@$, logic_not, $2); }
;
bytestring:
diff --git a/dtc.h b/dtc.h
index c40e9d7..fed9d2d 100644
--- a/dtc.h
+++ b/dtc.h
@@ -221,8 +221,10 @@ uint32_t guess_boot_cpuid(struct node *tree);
/* Expressions */
struct operator;
+struct srcpos;
struct expression {
+ struct srcpos *loc;
struct operator *op;
int nargs;
union {
@@ -234,16 +236,19 @@ struct expression {
void expression_free(struct expression *expr);
uint64_t expression_evaluate(struct expression *expr);
-struct expression *expression_constant(uint64_t val);
+struct expression *expression_constant(struct srcpos *pos, uint64_t val);
#define DEF_UNARY_OP(nm) \
- struct expression *expression_##nm(struct expression *)
+ struct expression *expression_##nm(struct srcpos *, \
+ struct expression *)
DEF_UNARY_OP(negate);
DEF_UNARY_OP(bit_not);
DEF_UNARY_OP(logic_not);
#define DEF_BINARY_OP(nm) \
- struct expression *expression_##nm(struct expression *, struct expression *)
+ struct expression *expression_##nm(struct srcpos *, \
+ struct expression *, \
+ struct expression *)
DEF_BINARY_OP(mod);
DEF_BINARY_OP(div);
DEF_BINARY_OP(mul);
@@ -272,7 +277,8 @@ DEF_BINARY_OP(logic_and);
DEF_BINARY_OP(logic_or);
-struct expression *expression_conditional(struct expression *,
+struct expression *expression_conditional(struct srcpos *pos,
+ struct expression *,
struct expression *,
struct expression *);
diff --git a/expression.c b/expression.c
index dd31a37..05d0df5 100644
--- a/expression.c
+++ b/expression.c
@@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
-
+#include "srcpos.h"
#include "dtc.h"
struct operator {
@@ -27,7 +27,8 @@ struct operator {
void (*free)(struct expression *);
};
-static struct expression *__expression_build(struct operator *op, ...)
+static struct expression *__expression_build(struct srcpos *loc,
+ struct operator *op, ...)
{
int nargs = 0;
struct expression *expr;
@@ -43,6 +44,10 @@ static struct expression *__expression_build(struct operator *op, ...)
expr = xmalloc(sizeof(*expr) + nargs*sizeof(struct expression *));
expr->op = op;
expr->nargs = nargs;
+ if (loc)
+ expr->loc = srcpos_copy(loc);
+ else
+ expr->loc = NULL;
va_start(ap, op);
for (i = 0; i < nargs; i++)
@@ -51,8 +56,8 @@ static struct expression *__expression_build(struct operator *op, ...)
return expr;
}
-#define expression_build(...) \
- (__expression_build(__VA_ARGS__, NULL))
+#define expression_build(loc, ...) \
+ (__expression_build(loc, __VA_ARGS__, NULL))
void expression_free(struct expression *expr)
{
@@ -79,9 +84,9 @@ static struct operator op_constant = {
.name = "constant",
.evaluate = op_eval_constant,
};
-struct expression *expression_constant(uint64_t val)
+struct expression *expression_constant(struct srcpos *loc, uint64_t val)
{
- struct expression *expr = expression_build(&op_constant);
+ struct expression *expr = expression_build(loc, &op_constant);
expr->u.constant = val;
return expr;
@@ -97,9 +102,10 @@ struct expression *expression_constant(uint64_t val)
.name = #cop, \
.evaluate = op_eval_##nm, \
}; \
- struct expression *expression_##nm(struct expression *arg) \
+ struct expression *expression_##nm(struct srcpos *loc, \
+ struct expression *arg) \
{ \
- return expression_build(&op_##nm, arg); \
+ return expression_build(loc, &op_##nm, arg); \
}
INT_UNARY_OP(negate, -)
@@ -117,9 +123,11 @@ INT_UNARY_OP(logic_not, !)
.name = #cop, \
.evaluate = op_eval_##nm, \
}; \
- struct expression *expression_##nm(struct expression *arg1, struct expression *arg2) \
+ struct expression *expression_##nm(struct srcpos *loc, \
+ struct expression *arg1, \
+ struct expression *arg2) \
{ \
- return expression_build(&op_##nm, arg1, arg2); \
+ return expression_build(loc, &op_##nm, arg1, arg2); \
}
INT_BINARY_OP(mod, %)
@@ -158,8 +166,10 @@ static struct operator op_conditional = {
.name = "?:",
.evaluate = op_eval_conditional,
};
-struct expression *expression_conditional(struct expression *arg1, struct expression *arg2,
+struct expression *expression_conditional(struct srcpos *loc,
+ struct expression *arg1,
+ struct expression *arg2,
struct expression *arg3)
{
- return expression_build(&op_conditional, arg1, arg2, arg3);
+ return expression_build(loc, &op_conditional, arg1, arg2, arg3);
}
--
1.8.5.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 03/10] Add type information to expression trees
[not found] ` <1393500099-28544-1-git-send-email-david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
2014-02-27 11:21 ` [PATCH 01/10] First cut at expression trees David Gibson
2014-02-27 11:21 ` [PATCH 02/10] Add srcpos information to expressions David Gibson
@ 2014-02-27 11:21 ` David Gibson
2014-02-27 11:21 ` [PATCH 04/10] Add string and bytestring expression types David Gibson
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: David Gibson @ 2014-02-27 11:21 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ, David Gibson
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-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
---
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-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 04/10] Add string and bytestring expression types
[not found] ` <1393500099-28544-1-git-send-email-david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
` (2 preceding siblings ...)
2014-02-27 11:21 ` [PATCH 03/10] Add type information to expression trees David Gibson
@ 2014-02-27 11:21 ` David Gibson
2014-02-27 11:21 ` [PATCH 05/10] Integrate /incbin/ with expanded expressions David Gibson
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: David Gibson @ 2014-02-27 11:21 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ, David Gibson
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-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
---
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 majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 05/10] Integrate /incbin/ with expanded expressions
[not found] ` <1393500099-28544-1-git-send-email-david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
` (3 preceding siblings ...)
2014-02-27 11:21 ` [PATCH 04/10] Add string and bytestring expression types David Gibson
@ 2014-02-27 11:21 ` David Gibson
2014-02-27 11:21 ` [PATCH 06/10] Implement arrays as expressions David Gibson
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: David Gibson @ 2014-02-27 11:21 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ, David Gibson
Implement /incbin/ as a new type of bytestring expression operator. This
delays the evaluation of the /incbin/'s parameters until the evaluation
of the /incbin/ itself.
Signed-off-by: David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
---
dtc-parser.y | 56 +++++++++++++++-----------------------------------------
dtc.h | 4 ++++
expression.c | 41 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 60 insertions(+), 41 deletions(-)
diff --git a/dtc-parser.y b/dtc-parser.y
index e4df947..07cb067 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -35,7 +35,6 @@ 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)))
@@ -91,6 +90,7 @@ static struct data expr_bytestring(struct expression *expr);
%type <node> subnode
%type <nodelist> subnodes
+%type <expr> expr_incbin
%type <expr> expr_prim
%type <expr> expr_unary
%type <expr> expr_mul
@@ -224,34 +224,6 @@ propdata:
{
$$ = data_add_marker($1, REF_PATH, $2);
}
- | propdataprefix DT_INCBIN '(' expr_prim ',' expr_prim ',' expr_prim ')'
- {
- 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, filename,
- strerror(errno));
-
- d = data_copy_file(f, expr_int($8));
-
- $$ = data_merge($1, d);
- fclose(f);
- }
- | propdataprefix DT_INCBIN '(' DT_STRING ')'
- {
- FILE *f = srcfile_relative_open($4.val, NULL);
- struct data d = empty_data;
-
- d = data_copy_file(f, -1);
-
- $$ = data_merge($1, d);
- fclose(f);
- }
| propdata DT_LABEL
{
$$ = data_add_marker($1, LABEL, $2);
@@ -336,6 +308,19 @@ arrayprefix:
}
;
+expr_incbin:
+ DT_INCBIN '(' expr_conditional ',' expr_conditional ',' expr_conditional ')'
+ {
+ $$ = expression_incbin(&@$, $3, $5, $7);
+ }
+ | DT_INCBIN '(' expr_conditional ')'
+ {
+ $$ = expression_incbin(&@$, $3,
+ expression_integer_constant(NULL, 0),
+ expression_integer_constant(NULL, -1));
+ }
+ ;
+
expr_prim:
DT_LITERAL { $$ = expression_integer_constant(&yylloc, $1); }
| DT_CHAR_LITERAL { $$ = expression_integer_constant(&yylloc, $1); }
@@ -347,6 +332,7 @@ expr_prim:
{
$$ = expression_bytestring_constant(&@2, $2);
}
+ | expr_incbin
| '(' expr ')'
{
$$ = $2;
@@ -496,18 +482,6 @@ static uint64_t expr_int(struct expression *expr)
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);
diff --git a/dtc.h b/dtc.h
index 0b644d2..2ab4ba4 100644
--- a/dtc.h
+++ b/dtc.h
@@ -305,6 +305,10 @@ struct expression *expression_conditional(struct srcpos *pos,
struct expression *,
struct expression *,
struct expression *);
+struct expression *expression_incbin(struct srcpos *loc,
+ struct expression *file,
+ struct expression *off,
+ struct expression *len);
/* Boot info (tree plus memreserve information */
diff --git a/expression.c b/expression.c
index 4ecd84a..49bc8b0 100644
--- a/expression.c
+++ b/expression.c
@@ -339,3 +339,44 @@ struct expression *expression_conditional(struct srcpos *loc,
{
return expression_build(loc, &op_conditional, arg1, arg2, arg3);
}
+
+
+static struct expression_value op_eval_incbin(struct expression *expr,
+ enum expr_type context)
+{
+ struct data filename;
+ uint64_t offset, len;
+ FILE *f;
+ struct expression_value v = {
+ .type = EXPR_BYTESTRING,
+ };
+
+ EVALUATE_STR(filename, expr->arg[0]);
+ EVALUATE_INT(offset, expr->arg[1]);
+ EVALUATE_INT(len, expr->arg[2]);
+
+ f = srcfile_relative_open(filename.val, NULL);
+
+ if (offset != 0)
+ if (fseek(f, offset, SEEK_SET) != 0)
+ die("Couldn't seek to offset %llu in \"%s\": %s",
+ (unsigned long long)offset, filename.val,
+ strerror(errno));
+
+ v.value.d = data_copy_file(f, len);
+
+ fclose(f);
+ return v;
+}
+static struct operator op_incbin = {
+ .name = "/incbin/",
+ .nargs = 3,
+ .evaluate = op_eval_incbin,
+};
+struct expression *expression_incbin(struct srcpos *loc,
+ struct expression *file,
+ struct expression *off,
+ struct expression *len)
+{
+ return expression_build(loc, &op_incbin, file, off, len);
+}
--
1.8.5.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 06/10] Implement arrays as expressions
[not found] ` <1393500099-28544-1-git-send-email-david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
` (4 preceding siblings ...)
2014-02-27 11:21 ` [PATCH 05/10] Integrate /incbin/ with expanded expressions David Gibson
@ 2014-02-27 11:21 ` David Gibson
2014-02-27 11:21 ` [PATCH 07/10] Implement labels within property values as bytestring expressions David Gibson
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: David Gibson @ 2014-02-27 11:21 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ, David Gibson
This implements dtc's < ... > array syntax in terms of the new expression
infrastructure. Internally this uses two operator types, one to convert
an integer expression to a bytestring expression and another to append
multiple bytestring expressions together.
phandle references require some fiddling. These are implemented by using a
constant bytestring expression containing a placeholder plus the marker
to substitute in the correct phandle later. Logically it would be neater
for an integer expression itself to expand to the right phandle value, but
we can't do that just yet since the tree's phandle values aren't all
resolved at the time we evaluate expressions.
Signed-off-by: David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
---
dtc-parser.y | 60 +++++++++++++++++++++++++++++-------------------------------
dtc.h | 6 ++++++
expression.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 89 insertions(+), 31 deletions(-)
diff --git a/dtc-parser.y b/dtc-parser.y
index 07cb067..fcc3b4d 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -48,8 +48,8 @@ static struct data expr_bytestring(struct expression *expr);
struct data data;
struct {
- struct data data;
- int bits;
+ int bits;
+ struct expression *expr;
} array;
struct property *prop;
@@ -80,6 +80,7 @@ static struct data expr_bytestring(struct expression *expr);
%type <data> propdataprefix
%type <re> memreserve
%type <re> memreserves
+%type <array> array
%type <array> arrayprefix
%type <data> bytestring_literal
%type <prop> propdef
@@ -216,10 +217,6 @@ propdata:
struct data d = expr_bytestring($2);
$$ = data_merge($1, d);
}
- | propdataprefix arrayprefix '>'
- {
- $$ = data_merge($1, $2.data);
- }
| propdataprefix DT_REF
{
$$ = data_add_marker($1, REF_PATH, $2);
@@ -245,6 +242,10 @@ propdataprefix:
}
;
+array:
+ arrayprefix '>' { $$ = $1; }
+ ;
+
arrayprefix:
DT_BITS DT_LITERAL '<'
{
@@ -259,52 +260,48 @@ arrayprefix:
bits = 32;
}
- $$.data = empty_data;
$$.bits = bits;
+ $$.expr = expression_bytestring_constant(&@$, empty_data);
}
| '<'
{
- $$.data = empty_data;
$$.bits = 32;
+ $$.expr = expression_bytestring_constant(&@$, empty_data);
}
| arrayprefix expr_prim
{
- uint64_t val = expr_int($2);
-
- if ($1.bits < 64) {
- uint64_t mask = (1ULL << $1.bits) - 1;
- /*
- * Bits above mask must either be all zero
- * (positive within range of mask) or all one
- * (negative and sign-extended). The second
- * condition is true if when we set all bits
- * within the mask to one (i.e. | in the
- * mask), all bits are one.
- */
- if ((val > mask) && ((val | mask) != -1ULL))
- ERROR(&@2, "Value out of range for"
- " %d-bit array element", $1.bits);
- }
-
- $$.data = data_append_integer($1.data, val, $1.bits);
+ struct expression *cell = expression_arraycell(&@2,
+ $1.bits,
+ $2);
+ $$.bits = $1.bits;
+ $$.expr = expression_join(&@$, $1.expr, cell);
}
| arrayprefix DT_REF
{
uint64_t val = ~0ULL >> (64 - $1.bits);
+ struct data d = empty_data;
+ struct expression *cell;
if ($1.bits == 32)
- $1.data = data_add_marker($1.data,
- REF_PHANDLE,
- $2);
+ d = data_add_marker(d, REF_PHANDLE, $2);
else
ERROR(&@2, "References are only allowed in "
"arrays with 32-bit elements.");
- $$.data = data_append_integer($1.data, val, $1.bits);
+ d = data_append_integer(d, val, $1.bits);
+ cell = expression_bytestring_constant(&@2, d);
+
+ $$.bits = $1.bits;
+ $$.expr = expression_join(&@$, $1.expr, cell);
}
| arrayprefix DT_LABEL
{
- $$.data = data_add_marker($1.data, LABEL, $2);
+ struct data d = data_add_marker(empty_data, LABEL, $2);
+ struct expression *label;
+
+ label = expression_bytestring_constant(&@2, d);
+ $$.bits = $1.bits;
+ $$.expr = expression_join(&@$, $1.expr, label);
}
;
@@ -333,6 +330,7 @@ expr_prim:
$$ = expression_bytestring_constant(&@2, $2);
}
| expr_incbin
+ | array { $$ = $1.expr; }
| '(' expr ')'
{
$$ = $2;
diff --git a/dtc.h b/dtc.h
index 2ab4ba4..d270626 100644
--- a/dtc.h
+++ b/dtc.h
@@ -246,6 +246,7 @@ struct expression {
int nargs;
union {
struct expression_value constant;
+ int bits;
} u;
struct expression *arg[0];
};
@@ -309,6 +310,11 @@ struct expression *expression_incbin(struct srcpos *loc,
struct expression *file,
struct expression *off,
struct expression *len);
+struct expression *expression_arraycell(struct srcpos *loc, int bits,
+ struct expression *cell);
+struct expression *expression_join(struct srcpos *loc,
+ struct expression *arg0,
+ struct expression *arg1);
/* Boot info (tree plus memreserve information */
diff --git a/expression.c b/expression.c
index 49bc8b0..8d6474b 100644
--- a/expression.c
+++ b/expression.c
@@ -380,3 +380,57 @@ struct expression *expression_incbin(struct srcpos *loc,
{
return expression_build(loc, &op_incbin, file, off, len);
}
+
+static struct expression_value op_eval_arraycell(struct expression *expr,
+ enum expr_type context)
+{
+ uint64_t cellval;
+ struct expression_value v = {
+ .type = EXPR_BYTESTRING,
+ };
+ int bits = expr->u.bits;
+
+ assert(expr->nargs == 1);
+ EVALUATE_INT(cellval, expr->arg[0]);
+
+ v.value.d = data_append_integer(empty_data, cellval, bits);
+ return v;
+}
+static struct operator op_arraycell = {
+ .name = "< >",
+ .evaluate = op_eval_arraycell,
+};
+struct expression *expression_arraycell(struct srcpos *loc, int bits,
+ struct expression *cell)
+{
+ struct expression *expr = expression_build(loc, &op_arraycell, cell);
+
+ expr->u.bits = bits;
+ return expr;
+}
+
+static struct expression_value op_eval_join(struct expression *expr,
+ enum expr_type context)
+{
+ struct data arg0, arg1;
+ struct expression_value v = {
+ .type = EXPR_BYTESTRING,
+ };
+
+ assert(expr->nargs == 2);
+ EVALUATE_BS(arg0, expr->arg[0]);
+ EVALUATE_BS(arg1, expr->arg[1]);
+
+ v.value.d = data_merge(arg0, arg1);
+ return v;
+}
+static struct operator op_join = {
+ .name = ",",
+ .evaluate = op_eval_join,
+};
+struct expression *expression_join(struct srcpos *loc,
+ struct expression *arg0,
+ struct expression *arg1)
+{
+ return expression_build(loc, &op_join, arg0, arg1);
+}
--
1.8.5.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 07/10] Implement labels within property values as bytestring expressions
[not found] ` <1393500099-28544-1-git-send-email-david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
` (5 preceding siblings ...)
2014-02-27 11:21 ` [PATCH 06/10] Implement arrays as expressions David Gibson
@ 2014-02-27 11:21 ` David Gibson
2014-02-27 11:21 ` [PATCH 08/10] Implement path references in terms of " David Gibson
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: David Gibson @ 2014-02-27 11:21 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ, David Gibson
This re-implements labels within property values as a form of bytestring
expression. The grammar gets a little hairy to handle the fact that
labels are allowed both at the beginning and end of property values without
introducing parser conflicts.
Signed-off-by: David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
---
dtc-parser.y | 38 ++++++++++++++++++++++++++++----------
1 file changed, 28 insertions(+), 10 deletions(-)
diff --git a/dtc-parser.y b/dtc-parser.y
index fcc3b4d..bff22d9 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -93,6 +93,7 @@ static struct data expr_bytestring(struct expression *expr);
%type <expr> expr_incbin
%type <expr> expr_prim
+%type <expr> expr_prelabel
%type <expr> expr_unary
%type <expr> expr_mul
%type <expr> expr_add
@@ -105,6 +106,7 @@ static struct data expr_bytestring(struct expression *expr);
%type <expr> expr_and
%type <expr> expr_or
%type <expr> expr_conditional
+%type <expr> expr_postlabel
%type <expr> expr
%%
@@ -221,10 +223,6 @@ propdata:
{
$$ = data_add_marker($1, REF_PATH, $2);
}
- | propdata DT_LABEL
- {
- $$ = data_add_marker($1, LABEL, $2);
- }
;
propdataprefix:
@@ -236,10 +234,6 @@ propdataprefix:
{
$$ = $1;
}
- | propdataprefix DT_LABEL
- {
- $$ = data_add_marker($1, LABEL, $2);
- }
;
array:
@@ -338,7 +332,19 @@ expr_prim:
;
expr:
- expr_conditional
+ expr_postlabel
+ ;
+
+expr_postlabel:
+ expr_conditional
+ | expr_conditional DT_LABEL
+ {
+ struct data d = data_add_marker(empty_data, LABEL, $2);
+ struct expression *label;
+
+ label = expression_bytestring_constant(&@2, d);
+ $$ = expression_join(&@$, $1, label);
+ }
;
expr_conditional:
@@ -408,12 +414,24 @@ expr_mul:
;
expr_unary:
- expr_prim
+ expr_prelabel
| '-' expr_unary { $$ = UNOP(@$, negate, $2); }
| '~' expr_unary { $$ = UNOP(@$, bit_not, $2); }
| '!' expr_unary { $$ = UNOP(@$, logic_not, $2); }
;
+expr_prelabel:
+ expr_prim
+ | DT_LABEL expr_prelabel
+ {
+ struct data d = data_add_marker(empty_data, LABEL, $1);
+ struct expression *label;
+
+ label = expression_bytestring_constant(&@1, d);
+ $$ = expression_join(&@$, label, $2);
+ }
+ ;
+
bytestring_literal:
/* empty */
{
--
1.8.5.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 08/10] Implement path references in terms of bytestring expressions
[not found] ` <1393500099-28544-1-git-send-email-david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
` (6 preceding siblings ...)
2014-02-27 11:21 ` [PATCH 07/10] Implement labels within property values as bytestring expressions David Gibson
@ 2014-02-27 11:21 ` David Gibson
2014-02-27 11:21 ` [PATCH 09/10] Re-implement "," in property definitions as a bytestring operator David Gibson
2014-02-27 11:21 ` [PATCH 10/10] Implement string concatenate and repeat operators David Gibson
9 siblings, 0 replies; 11+ messages in thread
From: David Gibson @ 2014-02-27 11:21 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ, David Gibson
This patch re-implements path references (&label which expands to the
referenced node's full path) in terms of the bytestring expression
infrastructure.
Internally this is implemented as a constant bytestring expression
containing nothing but the marker to insert the path reference later.
Logically it would be neater to have the expression itself expand directly
to the right value itself, but for now we're evaluating these expressions
before all the tree's paths have been constructed.
Signed-off-by: David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
---
dtc-parser.y | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/dtc-parser.y b/dtc-parser.y
index bff22d9..7e1251d 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -219,10 +219,6 @@ propdata:
struct data d = expr_bytestring($2);
$$ = data_merge($1, d);
}
- | propdataprefix DT_REF
- {
- $$ = data_add_marker($1, REF_PATH, $2);
- }
;
propdataprefix:
@@ -349,6 +345,11 @@ expr_postlabel:
expr_conditional:
expr_or
+ | DT_REF
+ {
+ struct data d = data_add_marker(empty_data, REF_PATH, $1);
+ $$ = expression_bytestring_constant(&@$, d);
+ }
| expr_or '?' expr ':' expr_conditional
{
$$ = expression_conditional(&yylloc, $1, $3, $5);
--
1.8.5.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 09/10] Re-implement "," in property definitions as a bytestring operator
[not found] ` <1393500099-28544-1-git-send-email-david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
` (7 preceding siblings ...)
2014-02-27 11:21 ` [PATCH 08/10] Implement path references in terms of " David Gibson
@ 2014-02-27 11:21 ` David Gibson
2014-02-27 11:21 ` [PATCH 10/10] Implement string concatenate and repeat operators David Gibson
9 siblings, 0 replies; 11+ messages in thread
From: David Gibson @ 2014-02-27 11:21 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ, David Gibson
We've already introduced an internal "join" operator which appends
bytestring expressions together. This uses it to implement the "," syntax
in property values as expressions.
This is the last piece of property value syntax to be converted to use
the expression infrastructure, so all (non-empty) property values can now
be implemented as a single expression. For now we still just immediately
evaluate the expression though.
Signed-off-by: David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
---
dtc-parser.y | 37 ++++++++++++++-----------------------
1 file changed, 14 insertions(+), 23 deletions(-)
diff --git a/dtc-parser.y b/dtc-parser.y
index 7e1251d..61cdf66 100644
--- a/dtc-parser.y
+++ b/dtc-parser.y
@@ -76,8 +76,6 @@ static struct data expr_bytestring(struct expression *expr);
%token <labelref> DT_REF
%token DT_INCBIN
-%type <data> propdata
-%type <data> propdataprefix
%type <re> memreserve
%type <re> memreserves
%type <array> array
@@ -107,6 +105,7 @@ static struct data expr_bytestring(struct expression *expr);
%type <expr> expr_or
%type <expr> expr_conditional
%type <expr> expr_postlabel
+%type <expr> expr_join
%type <expr> expr
%%
@@ -194,9 +193,11 @@ proplist:
;
propdef:
- DT_PROPNODENAME '=' propdata ';'
+ DT_PROPNODENAME '=' expr ';'
{
- $$ = build_property($1, $3);
+ struct data d = expr_bytestring($3);
+
+ $$ = build_property($1, d);
}
| DT_PROPNODENAME ';'
{
@@ -213,25 +214,6 @@ propdef:
}
;
-propdata:
- propdataprefix expr
- {
- struct data d = expr_bytestring($2);
- $$ = data_merge($1, d);
- }
- ;
-
-propdataprefix:
- /* empty */
- {
- $$ = empty_data;
- }
- | propdata ','
- {
- $$ = $1;
- }
- ;
-
array:
arrayprefix '>' { $$ = $1; }
;
@@ -328,7 +310,15 @@ expr_prim:
;
expr:
+ expr_join
+ ;
+
+expr_join:
expr_postlabel
+ | expr_join ',' expr_postlabel
+ {
+ $$ = expression_join(&@$, $1, $3);
+ }
;
expr_postlabel:
@@ -343,6 +333,7 @@ expr_postlabel:
}
;
+
expr_conditional:
expr_or
| DT_REF
--
1.8.5.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 10/10] Implement string concatenate and repeat operators
[not found] ` <1393500099-28544-1-git-send-email-david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
` (8 preceding siblings ...)
2014-02-27 11:21 ` [PATCH 09/10] Re-implement "," in property definitions as a bytestring operator David Gibson
@ 2014-02-27 11:21 ` David Gibson
9 siblings, 0 replies; 11+ messages in thread
From: David Gibson @ 2014-02-27 11:21 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: grant.likely-s3s/WqlpOiPyB63q8FvJNQ, David Gibson
This patch exercises the new expression infrastructure to implement syntax
to concatenate and repeat strings. We use syntax inspired by Python,
with '+' overloaded for string concatenation and '*' overloaded for string
repeat. Normally we'd use C syntax to inspire dts syntax, but C has no
obvious candidates for these string operators.
Signed-off-by: David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
---
dtc.h | 4 ++
expression.c | 117 ++++++++++++++++++++++++++++++++++++++++++++-
tests/.gitignore | 1 +
tests/Makefile.tests | 2 +-
tests/run_tests.sh | 5 ++
tests/string-expressions.c | 97 +++++++++++++++++++++++++++++++++++++
6 files changed, 223 insertions(+), 3 deletions(-)
create mode 100644 tests/string-expressions.c
diff --git a/dtc.h b/dtc.h
index d270626..d3f8ad0 100644
--- a/dtc.h
+++ b/dtc.h
@@ -302,6 +302,10 @@ DEF_BINARY_OP(logic_and);
DEF_BINARY_OP(logic_or);
+struct expression *expression_concat(struct srcpos *pos,
+ struct expression *arg0,
+ struct expression *arg1);
+
struct expression *expression_conditional(struct srcpos *pos,
struct expression *,
struct expression *,
diff --git a/expression.c b/expression.c
index 8d6474b..2b86fed 100644
--- a/expression.c
+++ b/expression.c
@@ -294,9 +294,7 @@ INT_UNARY_OP(logic_not, !)
INT_BINARY_OP(mod, %)
INT_BINARY_OP(div, /)
-INT_BINARY_OP(mul, *)
-INT_BINARY_OP(add, +)
INT_BINARY_OP(sub, -)
INT_BINARY_OP(lshift, <<)
@@ -317,6 +315,121 @@ INT_BINARY_OP(bit_or, |)
INT_BINARY_OP(logic_and, &&)
INT_BINARY_OP(logic_or, ||)
+/*
+ * We need to write out add and mul in full, since they can be used on
+ * both integer and string arguments with different meanings
+ */
+
+static struct expression_value op_eval_mul(struct expression *expr,
+ enum expr_type context)
+{
+ struct expression_value arg0, arg1;
+ struct expression_value v;
+ uint64_t n, i;
+ struct data s;
+ struct data d = empty_data;
+
+ assert(expr->nargs == 2);
+ EVALUATE(arg0, expr->arg[0], EXPR_VOID);
+ EVALUATE(arg1, expr->arg[1], EXPR_VOID);
+
+ if ((arg0.type == EXPR_INTEGER) && (arg1.type == EXPR_INTEGER)) {
+ v.type = EXPR_INTEGER;
+ v.value.integer = arg0.value.integer * arg1.value.integer;
+ return v;
+ } else if ((arg0.type != EXPR_INTEGER) && (arg0.type != EXPR_STRING)) {
+ return type_error(expr->arg[0], "Expected integer or string"
+ " expression (found %s)",
+ expression_typename(arg0.type));
+ } else if (arg0.type == EXPR_INTEGER) {
+ if (arg1.type != EXPR_STRING)
+ return type_error(expr->arg[1], "Expected string"
+ " expression (found %s)",
+ expression_typename(arg1.type));
+ n = arg0.value.integer;
+ s = arg1.value.d;
+ } else {
+ assert(arg0.type == EXPR_STRING);
+ if (arg1.type != EXPR_INTEGER)
+ return type_error(expr->arg[1], "Expected integer"
+ " expression (found %s)",
+ expression_typename(arg1.type));
+ n = arg1.value.integer;
+ s = arg0.value.d;
+ }
+
+ for (i = 0; i < n; i++)
+ d = data_append_data(d, s.val, s.len - 1);
+
+ v.type = EXPR_STRING;
+ v.value.d = data_append_byte(d, 0); /* Terminating \0 */
+
+ return v;
+}
+static struct operator op_mul = {
+ .name = "*",
+ .evaluate = op_eval_mul,
+};
+struct expression *expression_mul(struct srcpos *loc,
+ struct expression *arg0,
+ struct expression *arg1)
+{
+ return expression_build(loc, &op_mul, arg0, arg1);
+}
+
+static struct expression_value op_eval_add(struct expression *expr,
+ enum expr_type context)
+{
+ struct expression_value arg0, arg1;
+ struct expression_value v;
+
+ assert(expr->nargs == 2);
+ EVALUATE(arg0, expr->arg[0], EXPR_VOID);
+ EVALUATE(arg1, expr->arg[1], EXPR_VOID);
+ if ((arg0.type != EXPR_INTEGER) && (arg0.type != EXPR_STRING))
+ return type_error(expr->arg[0], "Expected integer or string"
+ " expression (found %s)",
+ expression_typename(arg0.type));
+ if ((arg1.type != EXPR_INTEGER) && (arg1.type != EXPR_STRING))
+ return type_error(expr->arg[0], "Expected integer or string"
+ " expression (found %s)",
+ expression_typename(arg1.type));
+
+ if (arg0.type != arg1.type)
+ return type_error(expr, "Operand types to + (%s, %s) don't match",
+ expression_typename(arg0.type),
+ expression_typename(arg1.type));
+
+ v.type = arg0.type;
+
+ switch (v.type) {
+ case EXPR_INTEGER:
+ v.value.integer = arg0.value.integer + arg1.value.integer;
+ break;
+
+ case EXPR_STRING:
+ v.value.d = data_copy_mem(arg0.value.d.val,
+ arg0.value.d.len - 1);
+ v.value.d = data_append_data(v.value.d, arg1.value.d.val,
+ arg1.value.d.len);
+ break;
+
+ default:
+ assert(0);
+ }
+ return v;
+}
+static struct operator op_add = {
+ .name = "+",
+ .evaluate = op_eval_add,
+};
+struct expression *expression_add(struct srcpos *loc,
+ struct expression *arg0,
+ struct expression *arg1)
+{
+ return expression_build(loc, &op_add, arg0, arg1);
+}
+
static struct expression_value op_eval_conditional(struct expression *expr,
enum expr_type context)
{
diff --git a/tests/.gitignore b/tests/.gitignore
index bb5e33a..7931067 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -48,6 +48,7 @@ tmp.*
/setprop_inplace
/sized_cells
/string_escapes
+/string-expressions
/subnode_iterate
/subnode_offset
/supernode_atdepth_offset
diff --git a/tests/Makefile.tests b/tests/Makefile.tests
index dafb618..fa4e2d2 100644
--- a/tests/Makefile.tests
+++ b/tests/Makefile.tests
@@ -20,7 +20,7 @@ LIB_TESTS_L = get_mem_rsv \
dtb_reverse dtbs_equal_unordered \
add_subnode_with_nops path_offset_aliases \
utilfdt_test \
- integer-expressions \
+ integer-expressions string-expressions \
subnode_iterate
LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 97e016b..44de059 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -446,6 +446,11 @@ dtc_tests () {
run_dtc_test -I dts -O dtb -o integer-expressions.test.dtb integer-expressions.test.dts
run_test integer-expressions integer-expressions.test.dtb
+ # Check string expresisons
+ run_test string-expressions -g string-expressions.test.dts
+ run_dtc_test -I dts -O dtb -o string-expressions.test.dtb string-expressions.test.dts
+ run_test string-expressions string-expressions.test.dtb
+
# Check for graceful failure in some error conditions
run_sh_test dtc-fatal.sh -I dts -O dtb nosuchfile.dts
run_sh_test dtc-fatal.sh -I dtb -O dtb nosuchfile.dtb
diff --git a/tests/string-expressions.c b/tests/string-expressions.c
new file mode 100644
index 0000000..da6854f
--- /dev/null
+++ b/tests/string-expressions.c
@@ -0,0 +1,97 @@
+/*
+ * Testcase for dtc string expression support
+ *
+ * Copyright (C) 2013 David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+struct test_expr {
+ const char *expr;
+ const char *result;
+} expr_table[] = {
+#define TE(expr, res) { #expr, (res) }
+ TE("hello", "hello"),
+ TE("hello " + "world", "hello world"),
+ TE("hello" + " " + "world", "hello world"),
+ TE("hello" * 2 + " world", "hellohello world"),
+ TE("hello " + 2 * "world", "hello worldworld"),
+ TE(("hello"), "hello"),
+ TE(0 ? "hello" : "goodbye", "goodbye"),
+ TE(1 ? "hello" : "goodbye", "hello"),
+};
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ const char *res;
+ int reslen;
+ int i;
+
+ test_init(argc, argv);
+
+ if ((argc == 3) && (strcmp(argv[1], "-g") == 0)) {
+ FILE *f = fopen(argv[2], "w");
+
+ if (!f)
+ FAIL("Couldn't open \"%s\" for output: %s\n",
+ argv[2], strerror(errno));
+
+ fprintf(f, "/dts-v1/;\n");
+ fprintf(f, "/ {\n");
+ for (i = 0; i < ARRAY_SIZE(expr_table); i++)
+ fprintf(f, "\texpression-%d = %s;\n", i,
+ expr_table[i].expr);
+ fprintf(f, "};\n");
+ fclose(f);
+ } else {
+ fdt = load_blob_arg(argc, argv);
+
+ for (i = 0; i < ARRAY_SIZE(expr_table); i++) {
+ char propname[16];
+ int len = strlen(expr_table[i].result) + 1;
+
+ sprintf(propname, "expression-%d", i);
+ res = fdt_getprop(fdt, 0, propname, &reslen);
+
+ if (reslen != len)
+ FAIL("Incorrect length for expression %s,"
+ " %d instead of %d\n",
+ expr_table[i].expr, reslen, len);
+
+ if (memcmp(res, expr_table[i].result, len) != 0)
+ FAIL("Incorrect result for expression %s,"
+ " \"%s\" instead of \"%s\"\n",
+ expr_table[i].expr, res,
+ expr_table[i].result);
+ }
+ }
+
+ PASS();
+}
--
1.8.5.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2014-02-27 11:21 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-02-27 11:21 [0/10] RFC: A new start on richer dtc expression support [REPOST] David Gibson
[not found] ` <1393500099-28544-1-git-send-email-david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
2014-02-27 11:21 ` [PATCH 01/10] First cut at expression trees David Gibson
2014-02-27 11:21 ` [PATCH 02/10] Add srcpos information to expressions David Gibson
2014-02-27 11:21 ` [PATCH 03/10] Add type information to expression trees David Gibson
2014-02-27 11:21 ` [PATCH 04/10] Add string and bytestring expression types David Gibson
2014-02-27 11:21 ` [PATCH 05/10] Integrate /incbin/ with expanded expressions David Gibson
2014-02-27 11:21 ` [PATCH 06/10] Implement arrays as expressions David Gibson
2014-02-27 11:21 ` [PATCH 07/10] Implement labels within property values as bytestring expressions David Gibson
2014-02-27 11:21 ` [PATCH 08/10] Implement path references in terms of " David Gibson
2014-02-27 11:21 ` [PATCH 09/10] Re-implement "," in property definitions as a bytestring operator David Gibson
2014-02-27 11:21 ` [PATCH 10/10] Implement string concatenate and repeat operators David Gibson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).