aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/boot/dtc-src/dtc-parser.y
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/boot/dtc-src/dtc-parser.y')
-rw-r--r--arch/powerpc/boot/dtc-src/dtc-parser.y336
1 files changed, 336 insertions, 0 deletions
diff --git a/arch/powerpc/boot/dtc-src/dtc-parser.y b/arch/powerpc/boot/dtc-src/dtc-parser.y
new file mode 100644
index 0000000..002ea7f
--- /dev/null
+++ b/arch/powerpc/boot/dtc-src/dtc-parser.y
@@ -0,0 +1,336 @@
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
+ *
+ *
+ * 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
+ */
+
+%locations
+
+%{
+#include "dtc.h"
+#include "srcpos.h"
+
+int yylex(void);
+unsigned long long eval_literal(const char *s, int base, int bits);
+
+extern struct boot_info *the_boot_info;
+
+%}
+
+%union {
+ char *propnodename;
+ char *literal;
+ char *labelref;
+ unsigned int cbase;
+ u8 byte;
+ struct data data;
+
+ u64 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 <propnodename> DT_PROPNODENAME
+%token <literal> DT_LITERAL
+%token <literal> DT_LEGACYLITERAL
+%token <cbase> DT_BASE
+%token <byte> DT_BYTE
+%token <data> DT_STRING
+%token <labelref> DT_LABEL
+%token <labelref> DT_REF
+
+%type <data> propdata
+%type <data> propdataprefix
+%type <re> memreserve
+%type <re> memreserves
+%type <re> v0_memreserve
+%type <re> v0_memreserves
+%type <addr> addr
+%type <data> celllist
+%type <cbase> cellbase
+%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
+
+%%
+
+sourcefile:
+ DT_V1 ';' memreserves devicetree
+ {
+ the_boot_info = build_boot_info($3, $4);
+ }
+ | v0_memreserves devicetree
+ {
+ the_boot_info = build_boot_info($1, $2);
+ }
+ ;
+
+memreserves:
+ /* empty */
+ {
+ $$ = NULL;
+ }
+ | memreserve memreserves
+ {
+ $$ = chain_reserve_entry($1, $2);
+ }
+ ;
+
+memreserve:
+ label DT_MEMRESERVE addr addr ';'
+ {
+ $$ = build_reserve_entry($3, $4, $1);
+ }
+ ;
+
+v0_memreserves:
+ /* empty */
+ {
+ $$ = NULL;
+ }
+ | v0_memreserve v0_memreserves
+ {
+ $$ = chain_reserve_entry($1, $2);
+ };
+ ;
+
+v0_memreserve:
+ memreserve
+ {
+ $$ = $1;
+ }
+ | label DT_MEMRESERVE addr '-' addr ';'
+ {
+ $$ = build_reserve_entry($3, $5 - $3 + 1, $1);
+ }
+ ;
+
+addr:
+ DT_LITERAL
+ {
+ $$ = eval_literal($1, 0, 64);
+ }
+ | DT_LEGACYLITERAL
+ {
+ $$ = eval_literal($1, 16, 64);
+ }
+ ;
+
+devicetree:
+ '/' nodedef
+ {
+ $$ = name_node($2, "", NULL);
+ }
+ ;
+
+nodedef:
+ '{' proplist subnodes '}' ';'
+ {
+ $$ = build_node($2, $3);
+ }
+ ;
+
+proplist:
+ /* empty */
+ {
+ $$ = NULL;
+ }
+ | proplist propdef
+ {
+ $$ = chain_property($2, $1);
+ }
+ ;
+
+propdef:
+ label DT_PROPNODENAME '=' propdata ';'
+ {
+ $$ = build_property($2, $4, $1);
+ }
+ | label DT_PROPNODENAME ';'
+ {
+ $$ = build_property($2, empty_data, $1);
+ }
+ ;
+
+propdata:
+ propdataprefix DT_STRING
+ {
+ $$ = data_merge($1, $2);
+ }
+ | propdataprefix '<' celllist '>'
+ {
+ $$ = data_merge($1, $3);
+ }
+ | propdataprefix '[' bytestring ']'
+ {
+ $$ = data_merge($1, $3);
+ }
+ | propdataprefix DT_REF
+ {
+ $$ = data_add_marker($1, REF_PATH, $2);
+ }
+ | propdata DT_LABEL
+ {
+ $$ = data_add_marker($1, LABEL, $2);
+ }
+ ;
+
+propdataprefix:
+ /* empty */
+ {
+ $$ = empty_data;
+ }
+ | propdata ','
+ {
+ $$ = $1;
+ }
+ | propdataprefix DT_LABEL
+ {
+ $$ = data_add_marker($1, LABEL, $2);
+ }
+ ;
+
+celllist:
+ /* empty */
+ {
+ $$ = empty_data;
+ }
+ | celllist cellval
+ {
+ $$ = data_append_cell($1, $2);
+ }
+ | celllist DT_REF
+ {
+ $$ = data_append_cell(data_add_marker($1, REF_PHANDLE,
+ $2), -1);
+ }
+ | celllist DT_LABEL
+ {
+ $$ = data_add_marker($1, LABEL, $2);
+ }
+ ;
+
+cellbase:
+ /* empty */
+ {
+ $$ = 16;
+ }
+ | DT_BASE
+ ;
+
+cellval:
+ DT_LITERAL
+ {
+ $$ = eval_literal($1, 0, 32);
+ }
+ | cellbase DT_LEGACYLITERAL
+ {
+ $$ = eval_literal($2, $1, 32);
+ }
+ ;
+
+bytestring:
+ /* empty */
+ {
+ $$ = empty_data;
+ }
+ | bytestring DT_BYTE
+ {
+ $$ = data_append_byte($1, $2);
+ }
+ | bytestring DT_LABEL
+ {
+ $$ = data_add_marker($1, LABEL, $2);
+ }
+ ;
+
+subnodes:
+ /* empty */
+ {
+ $$ = NULL;
+ }
+ | subnode subnodes
+ {
+ $$ = chain_node($1, $2);
+ }
+ | subnode propdef
+ {
+ yyerror("syntax error: properties must precede subnodes\n");
+ YYERROR;
+ }
+ ;
+
+subnode:
+ label DT_PROPNODENAME nodedef
+ {
+ $$ = name_node($3, $2, $1);
+ }
+ ;
+
+label:
+ /* empty */
+ {
+ $$ = NULL;
+ }
+ | DT_LABEL
+ {
+ $$ = $1;
+ }
+ ;
+
+%%
+
+void yyerror (char const *s)
+{
+ const char *fname = srcpos_filename_for_num(yylloc.filenum);
+
+ if (strcmp(fname, "-") == 0)
+ fname = "stdin";
+
+ fprintf(stderr, "%s:%d %s\n",
+ fname, yylloc.first_line, s);
+}
+
+unsigned long long eval_literal(const char *s, int base, int bits)
+{
+ 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;
+}