diff options
Diffstat (limited to 'scripts/dtc/dtc-parser.y')
-rw-r--r-- | scripts/dtc/dtc-parser.y | 379 |
1 files changed, 379 insertions, 0 deletions
diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y new file mode 100644 index 000000000000..b2ab562420ea --- /dev/null +++ b/scripts/dtc/dtc-parser.y | |||
@@ -0,0 +1,379 @@ | |||
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 | } | ||