Merge branch 'fixes-2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
[pandora-kernel.git] / 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 %{
22 #include <stdio.h>
23
24 #include "dtc.h"
25 #include "srcpos.h"
26
27 YYLTYPE yylloc;
28
29 extern int yylex(void);
30 extern void print_error(char const *fmt, ...);
31 extern void yyerror(char const *s);
32
33 extern struct boot_info *the_boot_info;
34 extern int treesource_error;
35
36 static unsigned long long eval_literal(const char *s, int base, int bits);
37 %}
38
39 %union {
40         char *propnodename;
41         char *literal;
42         char *labelref;
43         unsigned int cbase;
44         uint8_t byte;
45         struct data data;
46
47         uint64_t addr;
48         cell_t cell;
49         struct property *prop;
50         struct property *proplist;
51         struct node *node;
52         struct node *nodelist;
53         struct reserve_info *re;
54 }
55
56 %token DT_V1
57 %token DT_MEMRESERVE
58 %token <propnodename> DT_PROPNODENAME
59 %token <literal> DT_LITERAL
60 %token <cbase> DT_BASE
61 %token <byte> DT_BYTE
62 %token <data> DT_STRING
63 %token <labelref> DT_LABEL
64 %token <labelref> DT_REF
65 %token DT_INCBIN
66
67 %type <data> propdata
68 %type <data> propdataprefix
69 %type <re> memreserve
70 %type <re> memreserves
71 %type <addr> addr
72 %type <data> celllist
73 %type <cell> cellval
74 %type <data> bytestring
75 %type <prop> propdef
76 %type <proplist> proplist
77
78 %type <node> devicetree
79 %type <node> nodedef
80 %type <node> subnode
81 %type <nodelist> subnodes
82
83 %%
84
85 sourcefile:
86           DT_V1 ';' memreserves devicetree
87                 {
88                         the_boot_info = build_boot_info($3, $4,
89                                                         guess_boot_cpuid($4));
90                 }
91         ;
92
93 memreserves:
94           /* empty */
95                 {
96                         $$ = NULL;
97                 }
98         | memreserve memreserves
99                 {
100                         $$ = chain_reserve_entry($1, $2);
101                 }
102         ;
103
104 memreserve:
105           DT_MEMRESERVE addr addr ';'
106                 {
107                         $$ = build_reserve_entry($2, $3);
108                 }
109         | DT_LABEL memreserve
110                 {
111                         add_label(&$2->labels, $1);
112                         $$ = $2;
113                 }
114         ;
115
116 addr:
117           DT_LITERAL
118                 {
119                         $$ = eval_literal($1, 0, 64);
120                 }
121           ;
122
123 devicetree:
124           '/' nodedef
125                 {
126                         $$ = name_node($2, "");
127                 }
128         | devicetree '/' nodedef
129                 {
130                         $$ = merge_nodes($1, $3);
131                 }
132         | devicetree DT_REF nodedef
133                 {
134                         struct node *target = get_node_by_ref($1, $2);
135
136                         if (target)
137                                 merge_nodes(target, $3);
138                         else
139                                 print_error("label or path, '%s', not found", $2);
140                         $$ = $1;
141                 }
142         ;
143
144 nodedef:
145           '{' proplist subnodes '}' ';'
146                 {
147                         $$ = build_node($2, $3);
148                 }
149         ;
150
151 proplist:
152           /* empty */
153                 {
154                         $$ = NULL;
155                 }
156         | proplist propdef
157                 {
158                         $$ = chain_property($2, $1);
159                 }
160         ;
161
162 propdef:
163           DT_PROPNODENAME '=' propdata ';'
164                 {
165                         $$ = build_property($1, $3);
166                 }
167         | DT_PROPNODENAME ';'
168                 {
169                         $$ = build_property($1, empty_data);
170                 }
171         | DT_LABEL propdef
172                 {
173                         add_label(&$2->labels, $1);
174                         $$ = $2;
175                 }
176         ;
177
178 propdata:
179           propdataprefix DT_STRING
180                 {
181                         $$ = data_merge($1, $2);
182                 }
183         | propdataprefix '<' celllist '>'
184                 {
185                         $$ = data_merge($1, $3);
186                 }
187         | propdataprefix '[' bytestring ']'
188                 {
189                         $$ = data_merge($1, $3);
190                 }
191         | propdataprefix DT_REF
192                 {
193                         $$ = data_add_marker($1, REF_PATH, $2);
194                 }
195         | propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')'
196                 {
197                         FILE *f = srcfile_relative_open($4.val, NULL);
198                         struct data d;
199
200                         if ($6 != 0)
201                                 if (fseek(f, $6, SEEK_SET) != 0)
202                                         print_error("Couldn't seek to offset %llu in \"%s\": %s",
203                                                      (unsigned long long)$6,
204                                                      $4.val,
205                                                      strerror(errno));
206
207                         d = data_copy_file(f, $8);
208
209                         $$ = data_merge($1, d);
210                         fclose(f);
211                 }
212         | propdataprefix DT_INCBIN '(' DT_STRING ')'
213                 {
214                         FILE *f = srcfile_relative_open($4.val, NULL);
215                         struct data d = empty_data;
216
217                         d = data_copy_file(f, -1);
218
219                         $$ = data_merge($1, d);
220                         fclose(f);
221                 }
222         | propdata DT_LABEL
223                 {
224                         $$ = data_add_marker($1, LABEL, $2);
225                 }
226         ;
227
228 propdataprefix:
229           /* empty */
230                 {
231                         $$ = empty_data;
232                 }
233         | propdata ','
234                 {
235                         $$ = $1;
236                 }
237         | propdataprefix DT_LABEL
238                 {
239                         $$ = data_add_marker($1, LABEL, $2);
240                 }
241         ;
242
243 celllist:
244           /* empty */
245                 {
246                         $$ = empty_data;
247                 }
248         | celllist cellval
249                 {
250                         $$ = data_append_cell($1, $2);
251                 }
252         | celllist DT_REF
253                 {
254                         $$ = data_append_cell(data_add_marker($1, REF_PHANDLE,
255                                                               $2), -1);
256                 }
257         | celllist DT_LABEL
258                 {
259                         $$ = data_add_marker($1, LABEL, $2);
260                 }
261         ;
262
263 cellval:
264           DT_LITERAL
265                 {
266                         $$ = eval_literal($1, 0, 32);
267                 }
268         ;
269
270 bytestring:
271           /* empty */
272                 {
273                         $$ = empty_data;
274                 }
275         | bytestring DT_BYTE
276                 {
277                         $$ = data_append_byte($1, $2);
278                 }
279         | bytestring DT_LABEL
280                 {
281                         $$ = data_add_marker($1, LABEL, $2);
282                 }
283         ;
284
285 subnodes:
286           /* empty */
287                 {
288                         $$ = NULL;
289                 }
290         | subnode subnodes
291                 {
292                         $$ = chain_node($1, $2);
293                 }
294         | subnode propdef
295                 {
296                         print_error("syntax error: properties must precede subnodes");
297                         YYERROR;
298                 }
299         ;
300
301 subnode:
302           DT_PROPNODENAME nodedef
303                 {
304                         $$ = name_node($2, $1);
305                 }
306         | DT_LABEL subnode
307                 {
308                         add_label(&$2->labels, $1);
309                         $$ = $2;
310                 }
311         ;
312
313 %%
314
315 void print_error(char const *fmt, ...)
316 {
317         va_list va;
318
319         va_start(va, fmt);
320         srcpos_verror(&yylloc, fmt, va);
321         va_end(va);
322
323         treesource_error = 1;
324 }
325
326 void yyerror(char const *s) {
327         print_error("%s", s);
328 }
329
330 static unsigned long long eval_literal(const char *s, int base, int bits)
331 {
332         unsigned long long val;
333         char *e;
334
335         errno = 0;
336         val = strtoull(s, &e, base);
337         if (*e)
338                 print_error("bad characters in literal");
339         else if ((errno == ERANGE)
340                  || ((bits < 64) && (val >= (1ULL << bits))))
341                 print_error("literal out of range");
342         else if (errno != 0)
343                 print_error("bad literal");
344         return val;
345 }