Introduce function defs and statements. Added support for expressions. Added if, for, assign and return statements. Added support for BUILTIN functions. Added support for /const/ definitions. Added support for command line defines, eg: -D x=1 Unified /memreserve/ into declaration list. Add lexical support for column source position information. Notably, this involved identifying all the newline characters to reset the column count. Had to rewrite the C comment rules, and break \n out of the {WS} set. Prevent lone +, -, and ? chars from being property names. Add lexical source positions to all IR nodes. Change error reporting to use IR source positions.
Passes test suite. Signed-off-by: Jon Loeliger <[EMAIL PROTECTED]> --- Makefile | 2 +- Makefile.dtc | 18 ++- dtc-lexer.l | 271 ++++++++++++++++++---- dtc-parser.y | 711 ++++++++++++++++++++++++++++++++++++++++++++++------------ dtc.c | 7 +- dtc.h | 1 + ir.h | 1 - ir_dump.c | 9 - ir_emit.c | 67 +++--- ir_eval.c | 2 - ir_scope.c | 3 +- livetree.c | 16 ++ nv.c | 108 +++++++++ nv.h | 34 +++ srcpos.c | 75 +++++-- srcpos.h | 10 +- treesource.c | 3 + 17 files changed, 1068 insertions(+), 270 deletions(-) create mode 100644 nv.c create mode 100644 nv.h diff --git a/Makefile b/Makefile index 5ad0189..1ae5577 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ CONFIG_LOCALVERSION = CPPFLAGS = -I libfdt CFLAGS = -Wall -g -Os -Wpointer-arith -Wcast-qual -BISON = bison +BISON = bison -v LEX = flex INSTALL = /usr/bin/install diff --git a/Makefile.dtc b/Makefile.dtc index 6ddf9ec..dd53276 100644 --- a/Makefile.dtc +++ b/Makefile.dtc @@ -3,7 +3,21 @@ # This is not a complete Makefile of itself. Instead, it is designed to # be easily embeddable into other systems of Makefiles. # -DTC_SRCS = dtc.c flattree.c fstree.c data.c livetree.c treesource.c srcpos.c \ - checks.c +DTC_SRCS = \ + checks.c \ + data.c \ + dtc.c \ + flattree.c \ + fstree.c \ + ir.c \ + ir_builtin.c \ + ir_dump.c \ + ir_emit.c \ + ir_eval.c \ + ir_scope.c \ + livetree.c \ + nv.c \ + srcpos.c \ + treesource.c DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o) diff --git a/dtc-lexer.l b/dtc-lexer.l index 6b862d2..d4efdef 100644 --- a/dtc-lexer.l +++ b/dtc-lexer.l @@ -18,19 +18,20 @@ * USA */ -%option noyywrap nounput noinput yylineno +%option noyywrap nounput noinput yylineno stack -%x INCLUDE %x BYTESTRING %x PROPNODENAME +%x COMMENT %s V1 +NOTPROPNAMES [+?-] PROPNODECHAR [a-zA-Z0-9,[EMAIL PROTECTED] PATHCHAR ({PROPNODECHAR}|[/]) LABEL [a-zA-Z_][a-zA-Z0-9_]* +ID \\[a-zA-Z_][a-zA-Z0-9_]* STRING \"([^\\"]|\\.)*\" -WS [[:space:]] -COMMENT "/*"([^*]|\*+[^*/])*\*+"/" +WS [[:blank:]] LINECOMMENT "//".*\n %{ @@ -49,6 +50,22 @@ LINECOMMENT "//".*\n static int dts_version = 1; +/* + * Track column positions too. Brute force. + */ +int yycolno = 1; + +#define SET_SRCPOS(yylloc) do { \ + yylloc.file = srcpos_file; \ + yylloc.first_line = yylineno; \ + yylloc.last_line = yylineno; \ + yylloc.first_column = yycolno; \ + yycolno += yyleng; \ + yylloc.last_column = yycolno - 1; \ + DPRINT("Set srcpos: %s\n", \ + srcpos_string(&yylloc)); \ + } while (0) + #define BEGIN_DEFAULT() DPRINT("<V1>\n"); \ BEGIN(V1); \ @@ -59,29 +76,27 @@ static int pop_input_file(void); %% <*>"/include/"{WS}*{STRING} { char *name = strchr(yytext, '\"') + 1; + SET_SRCPOS(yylloc); yytext[yyleng-1] = '\0'; push_input_file(name); } -<*><<EOF>> { +<*><<EOF>> { if (!pop_input_file()) { yyterminate(); } } <*>{STRING} { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; + SET_SRCPOS(yylloc); DPRINT("String: %s\n", yytext); - yylval.data = data_copy_escape_string(yytext+1, - yyleng-2); - yylloc.first_line = yylineno; + yytext[yyleng-1] = 0; /* remove close quote */ + yylval.litstr = strdup(yytext + 1); return DT_STRING; } <*>"/dts-v1/" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; + SET_SRCPOS(yylloc); DPRINT("Keyword: /dts-v1/\n"); dts_version = 1; BEGIN_DEFAULT(); @@ -89,41 +104,31 @@ static int pop_input_file(void); } <*>"/memreserve/" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; + SET_SRCPOS(yylloc); DPRINT("Keyword: /memreserve/\n"); BEGIN_DEFAULT(); return DT_MEMRESERVE; } <*>{LABEL}: { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; + SET_SRCPOS(yylloc); DPRINT("Label: %s\n", yytext); yylval.labelref = strdup(yytext); yylval.labelref[yyleng-1] = '\0'; return DT_LABEL; } -<V1>[0-9]+|0[xX][0-9a-fA-F]+ { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; - yylval.literal = strdup(yytext); - DPRINT("Literal: '%s'\n", yylval.literal); - return DT_LITERAL; - } - -\&{LABEL} { /* label reference */ - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; +<*>\&{LABEL} { + /* label reference */ + SET_SRCPOS(yylloc); DPRINT("Ref: %s\n", yytext+1); yylval.labelref = strdup(yytext+1); return DT_REF; } -"&{/"{PATHCHAR}+\} { /* new-style path reference */ - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; +<*>"&{/"{PATHCHAR}+\} { + /* new-style path reference */ + SET_SRCPOS(yylloc); yytext[yyleng-1] = '\0'; DPRINT("Ref: %s\n", yytext+2); yylval.labelref = strdup(yytext+2); @@ -131,44 +136,210 @@ static int pop_input_file(void); } <BYTESTRING>[0-9a-fA-F]{2} { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; + SET_SRCPOS(yylloc); yylval.byte = strtol(yytext, NULL, 16); DPRINT("Byte: %02x\n", (int)yylval.byte); return DT_BYTE; } <BYTESTRING>"]" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; + SET_SRCPOS(yylloc); DPRINT("/BYTESTRING\n"); BEGIN_DEFAULT(); return ']'; } +<*>[0-9]+|0[xX][0-9a-fA-F]+ { + SET_SRCPOS(yylloc); + yylval.literal = strdup(yytext); + DPRINT("Literal: '%s'\n", yylval.literal); + return DT_LITERAL; + } + +<*>"for" { + SET_SRCPOS(yylloc); + DPRINT("token: for\n"); + BEGIN_DEFAULT(); + return DT_FOR; + } + +<*>"if" { + SET_SRCPOS(yylloc); + DPRINT("token: if\n"); + BEGIN_DEFAULT(); + return DT_IF; + } + +<*>"void" { + SET_SRCPOS(yylloc); + DPRINT("token: void\n"); + return DT_VOID; + } + +<*>"in" { + SET_SRCPOS(yylloc); + DPRINT("token: in\n"); + BEGIN_DEFAULT(); + return DT_IN; + } + +<*>"else" { + SET_SRCPOS(yylloc); + DPRINT("token: else\n"); + BEGIN_DEFAULT(); + return DT_ELSE; + } + +<*>"return" { + SET_SRCPOS(yylloc); + DPRINT("token: return\n"); + return DT_RETURN; + } + +<*>"/define/" { + SET_SRCPOS(yylloc); + DPRINT("token: define\n"); + return DT_DEFINE; + } + +<*>"/const/" { + SET_SRCPOS(yylloc); + DPRINT("token: const\n"); + return DT_CONST; +} + +<*>"/incbin/" { + SET_SRCPOS(yylloc); + DPRINT("Binary Include\n"); + return DT_INCBIN; + } + +<*>{ID} { + SET_SRCPOS(yylloc); + DPRINT("Id: %s\n", yytext); + yylval.id = strdup(yytext + 1); /* drop \ */ + BEGIN_DEFAULT(); + return DT_ID; + } + +<PROPNODENAME>{NOTPROPNAMES} { + /* + * Lone +, - and ? chars shouldn't be + * property names. + */ + SET_SRCPOS(yylloc); + BEGIN_DEFAULT(); + return yytext[0]; + } + + <PROPNODENAME>{PROPNODECHAR}+ { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; + SET_SRCPOS(yylloc); DPRINT("PropNodeName: %s\n", yytext); yylval.propnodename = strdup(yytext); BEGIN_DEFAULT(); return DT_PROPNODENAME; } -"/incbin/" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; - DPRINT("Binary Include\n"); - return DT_INCBIN; + +<*>{WS}+ { + /* eat whitespace, but not newline */ + SET_SRCPOS(yylloc); + } + +<*>"/*" { + SET_SRCPOS(yylloc); + yy_push_state(COMMENT); + } + +<COMMENT>{ +[^*\n]* { + /* munch */ + SET_SRCPOS(yylloc); + } + +[^*\n]*\n { + yycolno = 1; + } + +"*"+[^*/\n]* { + /* munch */ + SET_SRCPOS(yylloc); + } + +"*"+[^*/\n]*\n { + yycolno = 1; + } + +"*"+"/" { + SET_SRCPOS(yylloc); + yy_pop_state(); + } +} + + +<*>{LINECOMMENT}+ { + /* eat C++-style comments including newline */ + yycolno = 1; } -<*>{WS}+ /* eat whitespace */ -<*>{COMMENT}+ /* eat C-style comments */ -<*>{LINECOMMENT}+ /* eat C++-style comments */ +<*>":=" { + SET_SRCPOS(yylloc); + DPRINT("token: <<\n"); + return DT_ASSIGN; + } +<*>"<<" { + SET_SRCPOS(yylloc); + DPRINT("token: <<\n"); + return DT_LSHIFT; + } +<*>">>" { + SET_SRCPOS(yylloc); + DPRINT("token: >>\n"); + return DT_RSHIFT; + } +<*>"<=" { + SET_SRCPOS(yylloc); + DPRINT("token: <=\n"); + return DT_LE; + } +<*>">=" { + SET_SRCPOS(yylloc); + DPRINT("token: >=\n"); + return DT_GE; + } +<*>"==" { + SET_SRCPOS(yylloc); + DPRINT("token: ==\n"); + return DT_EQ; + } +<*>"!=" { + SET_SRCPOS(yylloc); + DPRINT("token: !=\n"); + return DT_NE; + } +<*>"&&" { + SET_SRCPOS(yylloc); + DPRINT("token: &&\n"); + return DT_AND; + } +<*>"||" { + SET_SRCPOS(yylloc); + DPRINT("token: ||\n"); + return DT_OR; + } +<*>".." { + SET_SRCPOS(yylloc); + DPRINT("token: ..\n"); + return DT_RANGE; + } + +<*>\n { + yycolno = 1; + } <*>. { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; + SET_SRCPOS(yylloc); DPRINT("Char: %c (\\x%02x)\n", yytext[0], (unsigned)yytext[0]); if (yytext[0] == '[') { @@ -176,7 +347,9 @@ static int pop_input_file(void); BEGIN(BYTESTRING); } if ((yytext[0] == '{') - || (yytext[0] == ';')) { + || (yytext[0] == ';') + || (yytext[0] == ':') + ) { DPRINT("<PROPNODENAME>\n"); BEGIN(PROPNODENAME); } @@ -194,6 +367,7 @@ struct incl_file { struct dtc_file *file; YY_BUFFER_STATE yy_prev_buf; int yy_prev_lineno; + int yy_prev_colno; struct incl_file *prev; }; @@ -235,6 +409,7 @@ static void push_input_file(const char *filename) */ incl_file->yy_prev_buf = YY_CURRENT_BUFFER; incl_file->yy_prev_lineno = yylineno; + incl_file->yy_prev_lineno = yycolno; incl_file->file = srcpos_file; incl_file->prev = incl_file_stack; @@ -245,6 +420,7 @@ static void push_input_file(const char *filename) */ srcpos_file = newfile; yylineno = 1; + yycolno = 1; yyin = newfile->file; yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); } @@ -272,6 +448,7 @@ static int pop_input_file(void) yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(incl_file->yy_prev_buf); yylineno = incl_file->yy_prev_lineno; + yycolno = incl_file->yy_prev_colno; srcpos_file = incl_file->file; yyin = incl_file->file ? incl_file->file->file : NULL; diff --git a/dtc-parser.y b/dtc-parser.y index 3762181..f976623 100644 --- a/dtc-parser.y +++ b/dtc-parser.y @@ -25,309 +25,722 @@ #include "dtc.h" #include "srcpos.h" +#include "ir.h" extern int yylex(void); +extern void yyerror(char const *s); -extern struct boot_info *the_boot_info; extern int treesource_error; -static unsigned long long eval_literal(const char *s, int base, int bits); +#define YYERROR_VERBOSE + %} %union { + struct ir *ir; char *propnodename; + char *id; + char *litstr; char *literal; char *labelref; - unsigned int cbase; uint8_t byte; - struct data data; - - uint64_t addr; - cell_t cell; - struct property *prop; - struct property *proplist; - struct node *node; - struct node *nodelist; - struct reserve_info *re; } %token DT_V1 %token DT_MEMRESERVE +%token DT_INCBIN +%token DT_DEFINE +%token DT_CONST +%token DT_FOR +%token DT_IN +%token DT_RANGE +%token DT_VOID +%token DT_IF +%token DT_ELSE +%token DT_RETURN + %token <propnodename> DT_PROPNODENAME +%token <id> DT_ID %token <literal> DT_LITERAL -%token <cbase> DT_BASE %token <byte> DT_BYTE -%token <data> DT_STRING +%token <litstr> DT_STRING %token <labelref> DT_LABEL %token <labelref> DT_REF -%token DT_INCBIN -%type <data> propdata -%type <data> propdataprefix -%type <re> memreserve -%type <re> memreserves -%type <addr> addr -%type <data> celllist -%type <cell> cellval -%type <data> bytestring -%type <prop> propdef -%type <proplist> proplist - -%type <node> devicetree -%type <node> nodedef -%type <node> subnode -%type <nodelist> subnodes -%type <labelref> label +%token DT_OR +%token DT_AND +%token DT_EQ DT_NE +%token DT_LE DT_GE +%token DT_LSHIFT DT_RSHIFT +%token DT_ASSIGN + +%type <ir> sourcefile +%type <ir> memreserve +%type <ir> devicetree +%type <ir> declaration_list +%type <ir> declaration +%type <ir> funcdef +%type <ir> constdef +%type <ir> errordef +%type <ir> subnode +%type <ir> paramdecl_list +%type <ir> paramdecls +%type <ir> paramdecl + +%type <ir> statement_block +%type <ir> statement_list +%type <ir> statement +%type <ir> for_statement +%type <ir> if_statement +%type <ir> return_statement +%type <ir> assign_statement +%type <ir> trivial_statement +%type <ir> error_statement + +%type <ir> propdef +%type <ir> celllist +%type <ir> cellval +%type <ir> literal +%type <ir> string +%type <ir> addr +%type <ir> byte +%type <ir> propnodename +%type <ir> label +%type <ir> opt_label +%type <ir> node_label +%type <ir> propdata +%type <ir> propdataitem +%type <ir> propdataprefix +%type <ir> bytestring + +%type <ir> param_list + +%type <ir> expr +%type <ir> expr_primary +%type <ir> expr_postfix +%type <ir> expr_unary +%type <ir> expr_mul +%type <ir> expr_add +%type <ir> expr_shift +%type <ir> expr_rela +%type <ir> expr_eq +%type <ir> expr_bitand +%type <ir> expr_bitxor +%type <ir> expr_bitor +%type <ir> expr_and +%type <ir> expr_or +%type <ir> expr_conditional + +%type <ir> range +%type <ir> identifier %% sourcefile: - DT_V1 ';' memreserves devicetree + DT_V1 ';' declaration_list devicetree { - the_boot_info = build_boot_info($3, $4, 0); + the_ir_tree = ir_alloc(IR_ROOT, &@4); + the_ir_tree->ir_declarations = $3; + the_ir_tree->ir_statements = $4; } ; -memreserves: +declaration_list: /* empty */ { $$ = NULL; } - | memreserve memreserves + | declaration_list declaration { - $$ = chain_reserve_entry($1, $2); + $$ = ir_list_append($1, $2); } ; +declaration: + memreserve + | constdef + | funcdef + | errordef + ; + memreserve: - label DT_MEMRESERVE addr addr ';' + opt_label DT_MEMRESERVE addr addr ';' { - $$ = build_reserve_entry($3, $4, $1); + $$ = ir_alloc_binop(IR_MEM_RESERVE, $3, $4, &@2); + $$->ir_label = $1; } ; -addr: - DT_LITERAL + +constdef: + DT_CONST identifier '=' expr ';' { - $$ = eval_literal($1, 0, 64); + $$ = ir_alloc_binop(IR_CONST_DEF, $2, $4, &@1); } - ; + ; -devicetree: - '/' nodedef +funcdef: + DT_DEFINE propnodename paramdecls statement_block + { + $$ = ir_alloc(IR_FUNC_DEF, &@1); + $$->ir_name = $2; + $$->ir_declarations = $3; + $$->ir_statements = $4; + } + ; + +errordef: + error { - $$ = name_node($2, "", NULL); + $$ = NULL } ; -nodedef: - '{' proplist subnodes '}' ';' +paramdecls: + '(' paramdecl_list ')' { - $$ = build_node($2, $3); + $$ = $2; } ; -proplist: +paramdecl_list: /* empty */ { $$ = NULL; } - | proplist propdef + | paramdecl + { + $$ = ir_list_append(NULL, $1); + } + | paramdecl_list ',' paramdecl { - $$ = chain_property($2, $1); + $$ = ir_list_append($1, $3); } ; -propdef: - label DT_PROPNODENAME '=' propdata ';' +paramdecl: + identifier + ; + + +devicetree: + '/' statement_block ';' { - $$ = build_property($2, $4, $1); + $$ = ir_alloc(IR_NODE, &@2); + $$->ir_statements = $2; + $$->ir_name = ir_alloc(IR_PROPNODENAME, &@1); + $$->ir_name->ir_lit_str = ""; + $$->ir_label = NULL; } - | label DT_PROPNODENAME ';' + ; + + +statement_block: + '{' statement_list '}' { - $$ = build_property($2, empty_data, $1); + $$ = $2; } ; -propdata: - propdataprefix DT_STRING +statement_list: + /* empty */ { - $$ = data_merge($1, $2); + $$ = NULL; } - | propdataprefix '<' celllist '>' + | statement_list statement { - $$ = data_merge($1, $3); + $$ = ir_list_append($1, $2); } - | propdataprefix '[' bytestring ']' + ; + +statement: + for_statement + | if_statement + | return_statement + | assign_statement + | propdef + | subnode + | statement_block + | trivial_statement + | error_statement + ; + + +subnode: + node_label expr statement_block ';' { - $$ = data_merge($1, $3); + $$ = ir_alloc(IR_NODE, &@3); + $$->ir_statements = $3; + $$->ir_label = $1; + $$->ir_name = $2; } - | propdataprefix DT_REF + | label expr statement_block ';' { - $$ = data_add_marker($1, REF_PATH, $2); + $$ = ir_alloc(IR_NODE, &@3); + $$->ir_statements = $3; + $$->ir_label = $1; + $$->ir_name = $2; } - | propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')' + | expr statement_block ';' { - struct search_path path = { srcpos_file->dir, NULL, NULL }; - struct dtc_file *file = dtc_open_file($4.val, &path); - struct data d = empty_data; + $$ = ir_alloc(IR_NODE, &@2); + $$->ir_statements = $2; + $$->ir_label = NULL; + $$->ir_name = $1; + } + ; - if ($6 != 0) - if (fseek(file->file, $6, SEEK_SET) != 0) - yyerrorf("Couldn't seek to offset %llu in \"%s\": %s", - (unsigned long long)$6, - $4.val, strerror(errno)); +for_statement: + DT_FOR identifier DT_IN range statement_block + { + $$ = ir_alloc_binop(IR_FOR, $2, $4, &@1); + $$->ir_statements = $5; + } + ; - d = data_copy_file(file->file, $8); +range: + expr DT_RANGE expr + { + $$ = ir_alloc_binop(IR_RANGE, $1, $3, &@2); + } + ; - $$ = data_merge($1, d); - dtc_close_file(file); +if_statement: + DT_IF '(' expr ')' statement_block + { + $$ = ir_alloc_unop(IR_IF, $3, &@1); + $$->ir_statements = $5; } - | propdataprefix DT_INCBIN '(' DT_STRING ')' + | DT_IF '(' expr ')' statement_block DT_ELSE statement_block { - struct search_path path = { srcpos_file->dir, NULL, NULL }; - struct dtc_file *file = dtc_open_file($4.val, &path); - struct data d = empty_data; + $$ = ir_alloc_unop(IR_IF, $3, &@1); + $$->ir_statements = $5; + $$->ir_statements2 = $7; + } + ; - d = data_copy_file(file->file, -1); +return_statement: + DT_RETURN expr ';' + { + $$ = ir_alloc_unop(IR_RETURN, $2, &@1); + } + ; - $$ = data_merge($1, d); - dtc_close_file(file); +assign_statement: + identifier DT_ASSIGN expr ';' + { + $$ = ir_alloc_binop(IR_ASSIGN, $1, $3, &@2); } - | propdata DT_LABEL + ; + +trivial_statement: + ';' { - $$ = data_add_marker($1, LABEL, $2); + $$ = NULL; + } + ; + +error_statement: + error + { + $$ = NULL; + } + ; + +propdef: + expr ';' + { + $$ = ir_alloc_unop(IR_PROP_DEF, + ir_alloc_unop(IR_CVT_PROPNODENAME, + $1, + &@1), + &@1); + $$->ir_label = NULL; + } + | expr '=' propdata ';' + { + $$ = ir_alloc_binop(IR_PROP_DEF, + ir_alloc_unop(IR_CVT_PROPNODENAME, + $1, + &@1), + $3, + &@2); + $$->ir_label = NULL; + } + | label expr ';' + { + $$ = ir_alloc_unop(IR_PROP_DEF, + ir_alloc_unop(IR_CVT_PROPNODENAME, + $2, + &@2), + &@2); + $$->ir_label = $1; + } + | label expr '=' propdata ';' + { + $$ = ir_alloc_binop(IR_PROP_DEF, + ir_alloc_unop(IR_CVT_PROPNODENAME, + $2, + &@2), + $4, + &@3); + $$->ir_label = $1; + } + ; + +propdata: + propdataprefix propdataitem + { + $$ = ir_list_append($1, $2); + } + | propdata label + { + $$ = ir_list_append($1, $2); + } + ; + +propdataitem: + string + { + $$ = $1; + } + | '<' celllist '>' + { + $$ = $2; + } + | '[' bytestring ']' + { + $$ = $2; + } + | DT_REF + { + $$ = ir_alloc(IR_REF_PATH, &@1); + $$->ir_label_name = $1; + } + | DT_INCBIN '(' expr ')' + { + $$ = ir_alloc_unop(IR_INCBIN, $3, &@1); + } + | DT_INCBIN '(' expr ',' expr ',' expr ')' + { + $$ = ir_alloc_triop(IR_INCBIN, $3, $5, $7, &@1); } ; propdataprefix: /* empty */ { - $$ = empty_data; + $$ = NULL; } | propdata ',' { $$ = $1; } - | propdataprefix DT_LABEL + | propdataprefix label { - $$ = data_add_marker($1, LABEL, $2); + $$ = ir_list_append($1, $2); } ; celllist: /* empty */ { - $$ = empty_data; + $$ = NULL; } | celllist cellval { - $$ = data_append_cell($1, $2); + $$ = ir_list_append($1, $2); + } + | celllist '&' '(' expr ')' + { + $$ = ir_alloc(IR_REF_PHANDLE, &@2); + $$->ir_label = $4; + $$ = ir_list_append($1, $$); + } | celllist DT_REF { - $$ = data_append_cell(data_add_marker($1, REF_PHANDLE, - $2), -1); + $$ = ir_alloc(IR_REF_PHANDLE, &@2); + $$->ir_label_name = $2; + $$ = ir_list_append($1, $$); } - | celllist DT_LABEL + | celllist label { - $$ = data_add_marker($1, LABEL, $2); + $$ = ir_list_append($1, $2); } ; cellval: - DT_LITERAL + expr_primary { - $$ = eval_literal($1, 0, 32); + $$ = ir_alloc_unop(IR_CELL, $1, &@1); } ; -bytestring: - /* empty */ + +expr: + expr_conditional + ; + +expr_conditional: + expr_or + | expr_or '?' expr_or ':' expr_conditional { - $$ = empty_data; + $$ = ir_alloc_triop(IR_SELECT, $1, $3, $5, &@2); } - | bytestring DT_BYTE + ; + +expr_or: + expr_and + | expr_or DT_OR expr_and + { + $$ = ir_alloc_binop(IR_OR, $1, $3, &@2); + }; + +expr_and: + expr_bitor + | expr_and DT_AND expr_bitor + { + $$ = ir_alloc_binop(IR_AND, $1, $3, &@2); + }; + ; + +expr_bitor: + expr_bitxor + | expr_bitor '|' expr_bitxor { - $$ = data_append_byte($1, $2); + $$ = ir_alloc_binop(IR_BIT_OR, $1, $3, &@2); + }; + ; + +expr_bitxor: + expr_bitand + | expr_bitxor '^' expr_bitand + { + $$ = ir_alloc_binop(IR_BIT_XOR, $1, $3, &@2); + }; + ; + +expr_bitand: + expr_eq + | expr_bitand '&' expr_eq + { + $$ = ir_alloc_binop(IR_BIT_AND, $1, $3, &@2); + }; + ; + +expr_eq: + expr_rela + | expr_eq DT_EQ expr_rela + { + $$ = ir_alloc_binop(IR_EQ, $1, $3, &@2); + } + | expr_eq DT_NE expr_rela + { + $$ = ir_alloc_binop(IR_NE, $1, $3, &@2); + } + ; + +expr_rela: + expr_shift + | expr_rela '<' expr_shift + { + $$ = ir_alloc_binop(IR_LT, $1, $3, &@2); + } + | expr_rela '>' expr_shift + { + $$ = ir_alloc_binop(IR_GT, $1, $3, &@2); + } + | expr_rela DT_LE expr_shift + { + $$ = ir_alloc_binop(IR_LE, $1, $3, &@2); + } + | expr_rela DT_GE expr_shift + { + $$ = ir_alloc_binop(IR_GE, $1, $3, &@2); + } + ; + +expr_shift: + expr_add + | expr_shift DT_LSHIFT expr_add + { + $$ = ir_alloc_binop(IR_LSHIFT, $1, $3, &@2); + } + | expr_shift DT_RSHIFT expr_add + { + $$ = ir_alloc_binop(IR_RSHIFT, $1, $3, &@2); + } + ; + +expr_add: + expr_mul + | expr_add '+' expr_mul + { + $$ = ir_alloc_binop(IR_ADD, $1, $3, &@2); + } + | expr_add '-' expr_mul + { + $$ = ir_alloc_binop(IR_MINUS, $1, $3, &@2); + } + ; + +expr_mul: + expr_unary + | expr_mul '*' expr_unary + { + $$ = ir_alloc_binop(IR_MULT, $1, $3, &@2); + } + | expr_mul '/' expr_unary + { + $$ = ir_alloc_binop(IR_DIV, $1, $3, &@2); + } + | expr_mul '%' expr_unary + { + $$ = ir_alloc_binop(IR_MOD, $1, $3, &@2); + } + ; + +expr_unary: + expr_postfix + | '-' expr_unary + { + $$ = ir_alloc_unop(IR_UMINUS, $2, &@1); + } + | '~' expr_unary + { + $$ = ir_alloc_unop(IR_BIT_COMPL, $2, &@1); + } + | '!' expr_unary + { + $$ = ir_alloc_unop(IR_NOT, $2, &@1); + } + ; + +expr_postfix: + expr_primary + | expr_postfix '(' ')' + { + $$ = ir_alloc_binop(IR_FUNC_CALL, $1, NULL, &@2); } - | bytestring DT_LABEL + | expr_postfix '(' param_list ')' { - $$ = data_add_marker($1, LABEL, $2); + $$ = ir_alloc_binop(IR_FUNC_CALL, $1, $3, &@2); } ; -subnodes: +param_list: + expr + { + $$ = ir_list_append(NULL, $1); + } + | param_list ',' expr + { + $$ = ir_list_append($1, $3); + } + ; + + + +expr_primary: + literal + | string + | propnodename + | identifier + | '(' expr ')' + { + $$ = $2; + } + ; + +addr: + expr_primary + ; + + +bytestring: /* empty */ { $$ = NULL; } - | subnode subnodes + | bytestring byte { - $$ = chain_node($1, $2); + $$ = ir_list_append($1, $2); } - | subnode propdef + | bytestring label { - yyerror("syntax error: properties must precede subnodes"); - YYERROR; + $$ = ir_list_append($1, $2); } ; -subnode: - label DT_PROPNODENAME nodedef +propnodename: + DT_PROPNODENAME { - $$ = name_node($3, $2, $1); + $$ = ir_alloc(IR_PROPNODENAME, &@1); + $$->ir_lit_str = $1; } ; -label: +identifier: + DT_ID + { + $$ = ir_alloc(IR_ID, &@1); + $$->ir_lit_str = $1; + } + ; + +literal: + DT_LITERAL + { + $$ = ir_alloc(IR_LITERAL, &@1); + $$->ir_lit_str = $1; + } + ; + +byte: + DT_BYTE + { + $$ = ir_alloc(IR_LIT_BYTE, &@1); + $$->ir_literal = $1; + } + ; + +string: + DT_STRING + { + $$ = ir_alloc(IR_LIT_STR, &@1); + $$->ir_lit_str = $1; + } + ; + +opt_label: /* empty */ { $$ = NULL; } - | DT_LABEL + | label { $$ = $1; } ; -%% - -void yyerrorf(char const *s, ...) -{ - const char *fname = srcpos_file ? srcpos_file->name : "<no-file>"; - va_list va; - va_start(va, s); - - if (strcmp(fname, "-") == 0) - fname = "stdin"; +label: + DT_LABEL + { + $$ = ir_alloc(IR_LABEL, &@1); + $$->ir_label_name = $1; + } + ; - fprintf(stderr, "%s:%d ", fname, yylloc.first_line); - vfprintf(stderr, s, va); - fprintf(stderr, "\n"); +node_label: + expr ':' + ; - treesource_error = 1; - va_end(va); -} -void yyerror (char const *s) -{ - yyerrorf("%s", s); -} +%% -static unsigned long long eval_literal(const char *s, int base, int bits) +void yyerror(char const *s) { - unsigned long long val; - char *e; - - errno = 0; - val = strtoull(s, &e, base); - if (*e) - yyerror("bad characters in literal"); - else if ((errno == ERANGE) - || ((bits < 64) && (val >= (1ULL << bits)))) - yyerror("literal out of range"); - else if (errno != 0) - yyerror("bad literal"); - return val; + srcpos_error(&yylloc, "%s", s); + treesource_error = 1; } diff --git a/dtc.c b/dtc.c index 84bee2d..ccaf89c 100644 --- a/dtc.c +++ b/dtc.c @@ -20,6 +20,7 @@ #include "dtc.h" #include "srcpos.h" +#include "nv.h" #include "version_gen.h" @@ -127,7 +128,7 @@ int main(int argc, char *argv[]) minsize = 0; padsize = 0; - while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:v")) != EOF) { + while ((opt = getopt(argc, argv, "hD:I:O:o:V:R:S:p:fcqb:v")) != EOF) { switch (opt) { case 'I': inform = optarg; @@ -162,6 +163,9 @@ int main(int argc, char *argv[]) case 'b': cmdline_boot_cpuid = strtoll(optarg, NULL, 0); break; + case 'D': + nv_note_define(optarg); + break; case 'v': printf("Version: %s\n", DTC_VERSION); exit(0); @@ -203,7 +207,6 @@ int main(int argc, char *argv[]) fill_fullpaths(bi->dt, ""); process_checks(force, bi); - if (streq(outname, "-")) { outf = stdout; } else { diff --git a/dtc.h b/dtc.h index ec636f8..327fc15 100644 --- a/dtc.h +++ b/dtc.h @@ -187,6 +187,7 @@ struct property *reverse_properties(struct property *first); struct node *build_node(struct property *proplist, struct node *children); struct node *name_node(struct node *node, char *name, char *label); struct node *chain_node(struct node *first, struct node *list); +struct node *reverse_nodes(struct node *first); void add_property(struct node *node, struct property *prop); void add_child(struct node *parent, struct node *child); diff --git a/ir.h b/ir.h index 630ec52..b17b87d 100644 --- a/ir.h +++ b/ir.h @@ -100,7 +100,6 @@ struct ir { struct ir *ir_expr2; struct ir *ir_expr3; - struct ir *ir_mem_reserves; struct ir *ir_statements; struct ir *ir_statements2; struct ir *ir_declarations; diff --git a/ir_dump.c b/ir_dump.c index f949423..edf11a7 100644 --- a/ir_dump.c +++ b/ir_dump.c @@ -152,15 +152,6 @@ ir_dump_node(struct ir *ir, unsigned int level) indent, "", ir->ir_prev); /* - * Dump mem-reserves. - */ - if (ir->ir_mem_reserves) { - printf("%*sir_mem_reserves: %p\n", - indent, "", ir->ir_mem_reserves); - ir_dump_node(ir->ir_mem_reserves, level + 1); - } - - /* * Dump sub-expressions */ if (ir->ir_expr1) { diff --git a/ir_emit.c b/ir_emit.c index 31005ca..54b5a00 100644 --- a/ir_emit.c +++ b/ir_emit.c @@ -323,6 +323,34 @@ ir_emit_const_def(struct ir *ir_const_def) void +ir_emit_mem_reserve(struct ir *ir_mem) +{ + struct reserve_info *ri; + uint64_t addr; + uint64_t size; + char *lab; + + if (ir_mem == NULL) + return; + + addr = ir_eval_for_addr(ir_mem->ir_expr1); + size = ir_eval_for_addr(ir_mem->ir_expr2); + lab = ir_eval_for_label(ir_mem->ir_label); + + debug("ir_emit_mem_reserve(0x%llx, 0x%llx, ", + (unsigned long long)addr, (unsigned long long)size); + if (lab) { + debug("%s)\n", lab); + } else { + debug("<no-label>)\n"); + } + + ri = build_reserve_entry(addr, size, lab); + irs_append_reserve(ri); +} + + +void ir_emit_declaration_list(struct ir *ir_list) { struct ir *ir; @@ -343,9 +371,13 @@ ir_emit_declaration_list(struct ir *ir_list) ir_emit_func_def(ir); break; + case IR_MEM_RESERVE: + ir_emit_mem_reserve(ir); + break; + default: ir_error(ir, - "Unknown devlaration type %s\n", + "Unknown declaration type %s\n", ir_type_string(ir->ir_type)); break; } @@ -391,37 +423,6 @@ ir_emit_node(struct ir *ir) void -ir_emit_mem_reserves(struct ir *ir_mem) -{ - struct ir *ir; - struct reserve_info *ri; - uint64_t addr; - uint64_t size; - char *lab; - - if (ir_mem == NULL) - return; - - for (ir = ir_mem->ir_first; ir != NULL; ir = ir->ir_next) { - addr = ir_eval_for_addr(ir->ir_expr1); - size = ir_eval_for_addr(ir->ir_expr2); - lab = ir_eval_for_label(ir->ir_label); - - debug("emit: build_reserve_entry(0x%llx, 0x%llx, ", - (unsigned long long)addr, (unsigned long long)size); - if (lab) { - debug("%s)\n", lab); - } else { - debug("<no-label>)\n"); - } - - ri = build_reserve_entry(addr, size, lab); - irs_append_reserve(ri); - } -} - - -void ir_add_cmd_line_constant_defs(void) { struct nv_pair *nv; @@ -460,8 +461,6 @@ ir_emit_root(struct ir *ir) */ ir_add_cmd_line_constant_defs(); - ir_emit_mem_reserves(ir->ir_mem_reserves); - /* * Fast-and-loose... These are definitions, not declarations! */ diff --git a/ir_eval.c b/ir_eval.c index bd667cb..ba6da6a 100644 --- a/ir_eval.c +++ b/ir_eval.c @@ -1461,8 +1461,6 @@ ir_simplify(struct ir *ir, unsigned int ctxt) case IR_ROOT: ir_new = ir_copy(ir); - ir_new->ir_mem_reserves = - ir_simplify(ir->ir_mem_reserves, ctxt); ir_new->ir_declarations = ir_simplify(ir->ir_declarations, ctxt); ir_new->ir_statements = diff --git a/ir_scope.c b/ir_scope.c index c9a52e8..20d784d 100644 --- a/ir_scope.c +++ b/ir_scope.c @@ -97,8 +97,7 @@ irs_append_reserve(struct reserve_info *ri) struct ir_scope *irs; irs = irs_find_scope(IRS_ROOT); - irs->irs_reserve_list = chain_reserve_entry(ri, - irs->irs_reserve_list); + irs->irs_reserve_list = add_reserve_entry(irs->irs_reserve_list, ri); } diff --git a/livetree.c b/livetree.c index 0ca3de5..fec33b4 100644 --- a/livetree.c +++ b/livetree.c @@ -97,6 +97,22 @@ struct node *chain_node(struct node *first, struct node *list) return first; } +struct node *reverse_nodes(struct node *first) +{ + struct node *p = first; + struct node *head = NULL; + struct node *next; + + while (p) { + next = p->next_sibling; + p->next_sibling = head; + head = p; + p = next; + } + return head; +} + + void add_property(struct node *node, struct property *prop) { struct property **p; diff --git a/nv.c b/nv.c new file mode 100644 index 0000000..f02b8bc --- /dev/null +++ b/nv.c @@ -0,0 +1,108 @@ +/* + * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc. + * + * 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" +#include "nv.h" + +struct nv_pair *nv_list; + + +struct nv_pair * +nv_alloc(void) +{ + struct nv_pair *nv; + + nv = xmalloc(sizeof(struct nv_pair)); + memset(nv, 0, sizeof(struct nv_pair)); + + return nv; +} + + +int +nv_is_present(char *name) +{ + struct nv_pair *nv; + + for (nv = nv_list; nv != NULL; nv = nv->nv_next) { + if (strcmp(nv->nv_name, name) == 0) { + return 1; + } + } + return 0; +} + + +void +nv_dump(void) +{ + struct nv_pair *nv; + + for (nv = nv_list; nv != NULL; nv = nv->nv_next) { + printf("NV: %s = \"%s\"\n", nv->nv_name, nv->nv_value); + } +} + + +/* + * Accept a string like "foo=123", or "cpu=mpc8548". + * Split it on the = for name and value parts. + * Record it in a name-value pairing list for later + * use when setting up the IR evaluation environment. + */ + +void +nv_note_define(char *defstr) +{ + struct nv_pair *nv; + char *name; + char *value; + + if (!defstr || ! *defstr) + return; + + name = strdup(defstr); + + /* + * Separate name and value at equal sign. + */ + value = strchr(name, '='); + if (value) { + *value = 0; + value++; + if (! *value) { + value = NULL; + } + } + + if (nv_is_present(name)) { + printf("Warning: Ignored duplicate value %s for %s\n", + value, name); + return; + } + + debug("nv_note_define(): %s = \"%s\"\n", name, value); + + nv = nv_alloc(); + nv->nv_name = name; + nv->nv_value = value; + + nv->nv_next = nv_list; + nv_list = nv; +} diff --git a/nv.h b/nv.h new file mode 100644 index 0000000..70ed718 --- /dev/null +++ b/nv.h @@ -0,0 +1,34 @@ +/* + * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc. + * + * 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 + */ + +#ifndef _NV_H_ +#define _NV_H_ + + +struct nv_pair { + char *nv_name; + char *nv_value; + struct nv_pair *nv_next; +}; + +extern struct nv_pair *nv_list; + +extern void nv_note_define(char *defstr); + +#endif /* _NV_H_ */ diff --git a/srcpos.c b/srcpos.c index 59d1835..ac1fdab 100644 --- a/srcpos.c +++ b/srcpos.c @@ -17,9 +17,14 @@ * USA */ +#define _GNU_SOURCE + +#include <stdio.h> + #include "dtc.h" #include "srcpos.h" + /* * Like yylineno, this is the current open file pos. */ @@ -129,9 +134,6 @@ dtc_close_file(struct dtc_file *file) { if (fclose(file->file)) die("Error closing \"%s\": %s\n", file->name, strerror(errno)); - - free(file->dir); - free(file); } @@ -164,34 +166,75 @@ srcpos_dump(srcpos *pos) char * srcpos_string(srcpos *pos) { -# define POS_BUF_SIZE (100) - const char *fname; - char buf[POS_BUF_SIZE]; + char col_buf[100]; + char *pos_str; - if (pos->file && pos->file->name) + if (!pos) { + fname = "<no-file>"; + } else if (pos->file->name) { fname = pos->file->name; - else + if (strcmp(fname, "-") == 0) + fname = "stdin"; + } else { fname = "<no-file>"; + } if (pos->first_line == pos->last_line) { if (pos->first_column == pos->last_column) { - snprintf(buf, POS_BUF_SIZE, "%s %d:%d", - fname, pos->first_line, pos->first_column); + snprintf(col_buf, sizeof(col_buf), + "%d:%d", + pos->first_line, pos->first_column); } else { - snprintf(buf, POS_BUF_SIZE, "%s %d:%d-%d", - fname, pos->first_line, + snprintf(col_buf, sizeof(col_buf), + "%d:%d-%d", + pos->first_line, pos->first_column, pos->last_column); } } else { - snprintf(buf, POS_BUF_SIZE, "%s %d:%d - %d:%d", - fname, + snprintf(col_buf, sizeof(col_buf), + "%d:%d - %d:%d", pos->first_line, pos->first_column, pos->last_line, pos->last_column); } - return strdup(buf); + if (asprintf(&pos_str, "%s %s", fname, col_buf) == -1) + return "<unknown source position?"; + + return pos_str; +} + + +void +srcpos_error(srcpos *pos, char const *fmt, ...) +{ + const char *srcstr; + va_list va; + va_start(va, fmt); + + srcstr = srcpos_string(pos); + + fprintf(stderr, "Error: %s ", srcstr); + vfprintf(stderr, fmt, va); + fprintf(stderr, "\n"); + + va_end(va); +} + + +void +srcpos_warn(srcpos *pos, char const *fmt, ...) +{ + const char *srcstr; + va_list va; + va_start(va, fmt); + + srcstr = srcpos_string(pos); + + fprintf(stderr, "Warning: %s ", srcstr); + vfprintf(stderr, fmt, va); + fprintf(stderr, "\n"); -# undef POS_BUF_SIZE + va_end(va); } diff --git a/srcpos.h b/srcpos.h index 3c39dd0..a6d0077 100644 --- a/srcpos.h +++ b/srcpos.h @@ -81,11 +81,6 @@ typedef YYLTYPE srcpos; */ extern srcpos srcpos_empty; - - -extern void yyerror(char const *); -extern void yyerrorf(char const *, ...) __attribute__((format(printf, 1, 2))); - extern struct dtc_file *srcpos_file; struct search_path { @@ -101,4 +96,9 @@ extern srcpos *srcpos_copy(srcpos *pos); extern char *srcpos_string(srcpos *pos); extern void srcpos_dump(srcpos *pos); +extern void srcpos_error(srcpos *pos, char const *, ...) + __attribute__((format(printf, 2, 3))); +extern void srcpos_warn(srcpos *pos, char const *, ...) + __attribute__((format(printf, 2, 3))); + #endif /* _SRCPOS_H_ */ diff --git a/treesource.c b/treesource.c index 1521ff1..5d69878 100644 --- a/treesource.c +++ b/treesource.c @@ -20,6 +20,7 @@ #include "dtc.h" #include "srcpos.h" +#include "ir.h" extern FILE *yyin; extern int yyparse(void); @@ -41,6 +42,8 @@ struct boot_info *dt_from_source(const char *fname) if (treesource_error) die("Syntax error parsing input tree\n"); + ir_process(); + return the_boot_info; } -- 1.6.0.90.g436ed _______________________________________________ devicetree-discuss mailing list devicetree-discuss@ozlabs.org https://ozlabs.org/mailman/listinfo/devicetree-discuss