Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[linux-2.6] / scripts / dtc / dtc-parser.y
1 /*
2  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
3  *
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18  *                                                                   USA
19  */
20
21 %locations
22
23 %{
24 #include <stdio.h>
25
26 #include "dtc.h"
27 #include "srcpos.h"
28
29 extern int yylex(void);
30
31 extern struct boot_info *the_boot_info;
32 extern int treesource_error;
33
34 static unsigned long long eval_literal(const char *s, int base, int bits);
35 %}
36
37 %union {
38         char *propnodename;
39         char *literal;
40         char *labelref;
41         unsigned int cbase;
42         uint8_t byte;
43         struct data data;
44
45         uint64_t addr;
46         cell_t cell;
47         struct property *prop;
48         struct property *proplist;
49         struct node *node;
50         struct node *nodelist;
51         struct reserve_info *re;
52 }
53
54 %token DT_V1
55 %token DT_MEMRESERVE
56 %token <propnodename> DT_PROPNODENAME
57 %token <literal> DT_LITERAL
58 %token <literal> DT_LEGACYLITERAL
59 %token <cbase> DT_BASE
60 %token <byte> DT_BYTE
61 %token <data> DT_STRING
62 %token <labelref> DT_LABEL
63 %token <labelref> DT_REF
64 %token DT_INCBIN
65
66 %type <data> propdata
67 %type <data> propdataprefix
68 %type <re> memreserve
69 %type <re> memreserves
70 %type <re> v0_memreserve
71 %type <re> v0_memreserves
72 %type <addr> addr
73 %type <data> celllist
74 %type <cbase> cellbase
75 %type <cell> cellval
76 %type <data> bytestring
77 %type <prop> propdef
78 %type <proplist> proplist
79
80 %type <node> devicetree
81 %type <node> nodedef
82 %type <node> subnode
83 %type <nodelist> subnodes
84 %type <labelref> label
85
86 %%
87
88 sourcefile:
89           DT_V1 ';' memreserves devicetree
90                 {
91                         the_boot_info = build_boot_info($3, $4, 0);
92                 }
93         | v0_memreserves devicetree
94                 {
95                         the_boot_info = build_boot_info($1, $2, 0);
96                 }
97         ;
98
99 memreserves:
100           /* empty */
101                 {
102                         $$ = NULL;
103                 }
104         | memreserve memreserves
105                 {
106                         $$ = chain_reserve_entry($1, $2);
107                 }
108         ;
109
110 memreserve:
111           label DT_MEMRESERVE addr addr ';'
112                 {
113                         $$ = build_reserve_entry($3, $4, $1);
114                 }
115         ;
116
117 v0_memreserves:
118           /* empty */
119                 {
120                         $$ = NULL;
121                 }
122         | v0_memreserve v0_memreserves
123                 {
124                         $$ = chain_reserve_entry($1, $2);
125                 };
126         ;
127
128 v0_memreserve:
129           memreserve
130                 {
131                         $$ = $1;
132                 }
133         | label DT_MEMRESERVE addr '-' addr ';'
134                 {
135                         $$ = build_reserve_entry($3, $5 - $3 + 1, $1);
136                 }
137         ;
138
139 addr:
140           DT_LITERAL
141                 {
142                         $$ = eval_literal($1, 0, 64);
143                 }
144         | DT_LEGACYLITERAL
145                 {
146                         $$ = eval_literal($1, 16, 64);
147                 }
148           ;
149
150 devicetree:
151           '/' nodedef
152                 {
153                         $$ = name_node($2, "", NULL);
154                 }
155         ;
156
157 nodedef:
158           '{' proplist subnodes '}' ';'
159                 {
160                         $$ = build_node($2, $3);
161                 }
162         ;
163
164 proplist:
165           /* empty */
166                 {
167                         $$ = NULL;
168                 }
169         | proplist propdef
170                 {
171                         $$ = chain_property($2, $1);
172                 }
173         ;
174
175 propdef:
176           label DT_PROPNODENAME '=' propdata ';'
177                 {
178                         $$ = build_property($2, $4, $1);
179                 }
180         | label DT_PROPNODENAME ';'
181                 {
182                         $$ = build_property($2, empty_data, $1);
183                 }
184         ;
185
186 propdata:
187           propdataprefix DT_STRING
188                 {
189                         $$ = data_merge($1, $2);
190                 }
191         | propdataprefix '<' celllist '>'
192                 {
193                         $$ = data_merge($1, $3);
194                 }
195         | propdataprefix '[' bytestring ']'
196                 {
197                         $$ = data_merge($1, $3);
198                 }
199         | propdataprefix DT_REF
200                 {
201                         $$ = data_add_marker($1, REF_PATH, $2);
202                 }
203         | propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')'
204                 {
205                         struct search_path path = { srcpos_file->dir, NULL, NULL };
206                         struct dtc_file *file = dtc_open_file($4.val, &path);
207                         struct data d = empty_data;
208
209                         if ($6 != 0)
210                                 if (fseek(file->file, $6, SEEK_SET) != 0)
211                                         yyerrorf("Couldn't seek to offset %llu in \"%s\": %s",
212                                                  (unsigned long long)$6,
213                                                  $4.val, strerror(errno));
214
215                         d = data_copy_file(file->file, $8);
216
217                         $$ = data_merge($1, d);
218                         dtc_close_file(file);
219                 }
220         | propdataprefix DT_INCBIN '(' DT_STRING ')'
221                 {
222                         struct search_path path = { srcpos_file->dir, NULL, NULL };
223                         struct dtc_file *file = dtc_open_file($4.val, &path);
224                         struct data d = empty_data;
225
226                         d = data_copy_file(file->file, -1);
227
228                         $$ = data_merge($1, d);
229                         dtc_close_file(file);
230                 }
231         | propdata DT_LABEL
232                 {
233                         $$ = data_add_marker($1, LABEL, $2);
234                 }
235         ;
236
237 propdataprefix:
238           /* empty */
239                 {
240                         $$ = empty_data;
241                 }
242         | propdata ','
243                 {
244                         $$ = $1;
245                 }
246         | propdataprefix DT_LABEL
247                 {
248                         $$ = data_add_marker($1, LABEL, $2);
249                 }
250         ;
251
252 celllist:
253           /* empty */
254                 {
255                         $$ = empty_data;
256                 }
257         | celllist cellval
258                 {
259                         $$ = data_append_cell($1, $2);
260                 }
261         | celllist DT_REF
262                 {
263                         $$ = data_append_cell(data_add_marker($1, REF_PHANDLE,
264                                                               $2), -1);
265                 }
266         | celllist DT_LABEL
267                 {
268                         $$ = data_add_marker($1, LABEL, $2);
269                 }
270         ;
271
272 cellbase:
273           /* empty */
274                 {
275                         $$ = 16;
276                 }
277         | DT_BASE
278         ;
279
280 cellval:
281           DT_LITERAL
282                 {
283                         $$ = eval_literal($1, 0, 32);
284                 }
285         | cellbase DT_LEGACYLITERAL
286                 {
287                         $$ = eval_literal($2, $1, 32);
288                 }
289         ;
290
291 bytestring:
292           /* empty */
293                 {
294                         $$ = empty_data;
295                 }
296         | bytestring DT_BYTE
297                 {
298                         $$ = data_append_byte($1, $2);
299                 }
300         | bytestring DT_LABEL
301                 {
302                         $$ = data_add_marker($1, LABEL, $2);
303                 }
304         ;
305
306 subnodes:
307           /* empty */
308                 {
309                         $$ = NULL;
310                 }
311         |  subnode subnodes
312                 {
313                         $$ = chain_node($1, $2);
314                 }
315         | subnode propdef
316                 {
317                         yyerror("syntax error: properties must precede subnodes");
318                         YYERROR;
319                 }
320         ;
321
322 subnode:
323           label DT_PROPNODENAME nodedef
324                 {
325                         $$ = name_node($3, $2, $1);
326                 }
327         ;
328
329 label:
330           /* empty */
331                 {
332                         $$ = NULL;
333                 }
334         | DT_LABEL
335                 {
336                         $$ = $1;
337                 }
338         ;
339
340 %%
341
342 void yyerrorf(char const *s, ...)
343 {
344         const char *fname = srcpos_file ? srcpos_file->name : "<no-file>";
345         va_list va;
346         va_start(va, s);
347
348         if (strcmp(fname, "-") == 0)
349                 fname = "stdin";
350
351         fprintf(stderr, "%s:%d ", fname, yylloc.first_line);
352         vfprintf(stderr, s, va);
353         fprintf(stderr, "\n");
354
355         treesource_error = 1;
356         va_end(va);
357 }
358
359 void yyerror (char const *s)
360 {
361         yyerrorf("%s", s);
362 }
363
364 static unsigned long long eval_literal(const char *s, int base, int bits)
365 {
366         unsigned long long val;
367         char *e;
368
369         errno = 0;
370         val = strtoull(s, &e, base);
371         if (*e)
372                 yyerror("bad characters in literal");
373         else if ((errno == ERANGE)
374                  || ((bits < 64) && (val >= (1ULL << bits))))
375                 yyerror("literal out of range");
376         else if (errno != 0)
377                 yyerror("bad literal");
378         return val;
379 }