dtc-parser.y revision 302408
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
27YYLTYPE yylloc;
28
29extern int yylex(void);
30extern void print_error(char const *fmt, ...);
31extern void yyerror(char const *s);
32
33extern struct boot_info *the_boot_info;
34extern bool treesource_error;
35%}
36
37%union {
38	char *propnodename;
39	char *labelref;
40	unsigned int cbase;
41	uint8_t byte;
42	struct data data;
43
44	struct {
45		struct data	data;
46		int		bits;
47	} array;
48
49	struct property *prop;
50	struct property *proplist;
51	struct node *node;
52	struct node *nodelist;
53	struct reserve_info *re;
54	uint64_t integer;
55}
56
57%token DT_V1
58%token DT_MEMRESERVE
59%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
60%token DT_BITS
61%token DT_DEL_PROP
62%token DT_DEL_NODE
63%token <propnodename> DT_PROPNODENAME
64%token <integer> DT_LITERAL
65%token <integer> DT_CHAR_LITERAL
66%token <cbase> DT_BASE
67%token <byte> DT_BYTE
68%token <data> DT_STRING
69%token <labelref> DT_LABEL
70%token <labelref> DT_REF
71%token DT_INCBIN
72
73%type <data> propdata
74%type <data> propdataprefix
75%type <re> memreserve
76%type <re> memreserves
77%type <array> arrayprefix
78%type <data> bytestring
79%type <prop> propdef
80%type <proplist> proplist
81
82%type <node> devicetree
83%type <node> nodedef
84%type <node> subnode
85%type <nodelist> subnodes
86
87%type <integer> integer_prim
88%type <integer> integer_unary
89%type <integer> integer_mul
90%type <integer> integer_add
91%type <integer> integer_shift
92%type <integer> integer_rela
93%type <integer> integer_eq
94%type <integer> integer_bitand
95%type <integer> integer_bitxor
96%type <integer> integer_bitor
97%type <integer> integer_and
98%type <integer> integer_or
99%type <integer> integer_trinary
100%type <integer> integer_expr
101
102%%
103
104sourcefile:
105	  DT_V1 ';' memreserves devicetree
106		{
107			the_boot_info = build_boot_info($3, $4,
108							guess_boot_cpuid($4));
109		}
110	;
111
112memreserves:
113	  /* empty */
114		{
115			$$ = NULL;
116		}
117	| memreserve memreserves
118		{
119			$$ = chain_reserve_entry($1, $2);
120		}
121	;
122
123memreserve:
124	  DT_MEMRESERVE integer_prim integer_prim ';'
125		{
126			$$ = build_reserve_entry($2, $3);
127		}
128	| DT_LABEL memreserve
129		{
130			add_label(&$2->labels, $1);
131			$$ = $2;
132		}
133	;
134
135devicetree:
136	  '/' nodedef
137		{
138			$$ = name_node($2, "");
139		}
140	| devicetree '/' nodedef
141		{
142			$$ = merge_nodes($1, $3);
143		}
144	| devicetree DT_REF nodedef
145		{
146			struct node *target = get_node_by_ref($1, $2);
147
148			if (target)
149				merge_nodes(target, $3);
150			else
151				print_error("label or path, '%s', not found", $2);
152			$$ = $1;
153		}
154	| devicetree DT_DEL_NODE DT_REF ';'
155		{
156			struct node *target = get_node_by_ref($1, $3);
157
158			if (!target)
159				print_error("label or path, '%s', not found", $3);
160			else
161				delete_node(target);
162
163			$$ = $1;
164		}
165	;
166
167nodedef:
168	  '{' proplist subnodes '}' ';'
169		{
170			$$ = build_node($2, $3);
171		}
172	;
173
174proplist:
175	  /* empty */
176		{
177			$$ = NULL;
178		}
179	| proplist propdef
180		{
181			$$ = chain_property($2, $1);
182		}
183	;
184
185propdef:
186	  DT_PROPNODENAME '=' propdata ';'
187		{
188			$$ = build_property($1, $3);
189		}
190	| DT_PROPNODENAME ';'
191		{
192			$$ = build_property($1, empty_data);
193		}
194	| DT_DEL_PROP DT_PROPNODENAME ';'
195		{
196			$$ = build_property_delete($2);
197		}
198	| DT_LABEL propdef
199		{
200			add_label(&$2->labels, $1);
201			$$ = $2;
202		}
203	;
204
205propdata:
206	  propdataprefix DT_STRING
207		{
208			$$ = data_merge($1, $2);
209		}
210	| propdataprefix arrayprefix '>'
211		{
212			$$ = data_merge($1, $2.data);
213		}
214	| propdataprefix '[' bytestring ']'
215		{
216			$$ = data_merge($1, $3);
217		}
218	| propdataprefix DT_REF
219		{
220			$$ = data_add_marker($1, REF_PATH, $2);
221		}
222	| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
223		{
224			FILE *f = srcfile_relative_open($4.val, NULL);
225			struct data d;
226
227			if ($6 != 0)
228				if (fseek(f, $6, SEEK_SET) != 0)
229					die("Couldn't seek to offset %llu in \"%s\": %s",
230					    (unsigned long long)$6, $4.val,
231					    strerror(errno));
232
233			d = data_copy_file(f, $8);
234
235			$$ = data_merge($1, d);
236			fclose(f);
237		}
238	| propdataprefix DT_INCBIN '(' DT_STRING ')'
239		{
240			FILE *f = srcfile_relative_open($4.val, NULL);
241			struct data d = empty_data;
242
243			d = data_copy_file(f, -1);
244
245			$$ = data_merge($1, d);
246			fclose(f);
247		}
248	| propdata DT_LABEL
249		{
250			$$ = data_add_marker($1, LABEL, $2);
251		}
252	;
253
254propdataprefix:
255	  /* empty */
256		{
257			$$ = empty_data;
258		}
259	| propdata ','
260		{
261			$$ = $1;
262		}
263	| propdataprefix DT_LABEL
264		{
265			$$ = data_add_marker($1, LABEL, $2);
266		}
267	;
268
269arrayprefix:
270	DT_BITS DT_LITERAL '<'
271		{
272			unsigned long long bits;
273
274			bits = $2;
275
276			if ((bits !=  8) && (bits != 16) &&
277			    (bits != 32) && (bits != 64))
278			{
279				print_error("Only 8, 16, 32 and 64-bit elements"
280					    " are currently supported");
281				bits = 32;
282			}
283
284			$$.data = empty_data;
285			$$.bits = bits;
286		}
287	| '<'
288		{
289			$$.data = empty_data;
290			$$.bits = 32;
291		}
292	| arrayprefix integer_prim
293		{
294			if ($1.bits < 64) {
295				uint64_t mask = (1ULL << $1.bits) - 1;
296				/*
297				 * Bits above mask must either be all zero
298				 * (positive within range of mask) or all one
299				 * (negative and sign-extended). The second
300				 * condition is true if when we set all bits
301				 * within the mask to one (i.e. | in the
302				 * mask), all bits are one.
303				 */
304				if (($2 > mask) && (($2 | mask) != -1ULL))
305					print_error(
306						"integer value out of range "
307						"%016lx (%d bits)", $1.bits);
308			}
309
310			$$.data = data_append_integer($1.data, $2, $1.bits);
311		}
312	| arrayprefix DT_REF
313		{
314			uint64_t val = ~0ULL >> (64 - $1.bits);
315
316			if ($1.bits == 32)
317				$1.data = data_add_marker($1.data,
318							  REF_PHANDLE,
319							  $2);
320			else
321				print_error("References are only allowed in "
322					    "arrays with 32-bit elements.");
323
324			$$.data = data_append_integer($1.data, val, $1.bits);
325		}
326	| arrayprefix DT_LABEL
327		{
328			$$.data = data_add_marker($1.data, LABEL, $2);
329		}
330	;
331
332integer_prim:
333	  DT_LITERAL
334	| DT_CHAR_LITERAL
335	| '(' integer_expr ')'
336		{
337			$$ = $2;
338		}
339	;
340
341integer_expr:
342	integer_trinary
343	;
344
345integer_trinary:
346	  integer_or
347	| integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
348	;
349
350integer_or:
351	  integer_and
352	| integer_or DT_OR integer_and { $$ = $1 || $3; }
353	;
354
355integer_and:
356	  integer_bitor
357	| integer_and DT_AND integer_bitor { $$ = $1 && $3; }
358	;
359
360integer_bitor:
361	  integer_bitxor
362	| integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
363	;
364
365integer_bitxor:
366	  integer_bitand
367	| integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
368	;
369
370integer_bitand:
371	  integer_eq
372	| integer_bitand '&' integer_eq { $$ = $1 & $3; }
373	;
374
375integer_eq:
376	  integer_rela
377	| integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
378	| integer_eq DT_NE integer_rela { $$ = $1 != $3; }
379	;
380
381integer_rela:
382	  integer_shift
383	| integer_rela '<' integer_shift { $$ = $1 < $3; }
384	| integer_rela '>' integer_shift { $$ = $1 > $3; }
385	| integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
386	| integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
387	;
388
389integer_shift:
390	  integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
391	| integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
392	| integer_add
393	;
394
395integer_add:
396	  integer_add '+' integer_mul { $$ = $1 + $3; }
397	| integer_add '-' integer_mul { $$ = $1 - $3; }
398	| integer_mul
399	;
400
401integer_mul:
402	  integer_mul '*' integer_unary { $$ = $1 * $3; }
403	| integer_mul '/' integer_unary { $$ = $1 / $3; }
404	| integer_mul '%' integer_unary { $$ = $1 % $3; }
405	| integer_unary
406	;
407
408integer_unary:
409	  integer_prim
410	| '-' integer_unary { $$ = -$2; }
411	| '~' integer_unary { $$ = ~$2; }
412	| '!' integer_unary { $$ = !$2; }
413	;
414
415bytestring:
416	  /* empty */
417		{
418			$$ = empty_data;
419		}
420	| bytestring DT_BYTE
421		{
422			$$ = data_append_byte($1, $2);
423		}
424	| bytestring DT_LABEL
425		{
426			$$ = data_add_marker($1, LABEL, $2);
427		}
428	;
429
430subnodes:
431	  /* empty */
432		{
433			$$ = NULL;
434		}
435	| subnode subnodes
436		{
437			$$ = chain_node($1, $2);
438		}
439	| subnode propdef
440		{
441			print_error("syntax error: properties must precede subnodes");
442			YYERROR;
443		}
444	;
445
446subnode:
447	  DT_PROPNODENAME nodedef
448		{
449			$$ = name_node($2, $1);
450		}
451	| DT_DEL_NODE DT_PROPNODENAME ';'
452		{
453			$$ = name_node(build_node_delete(), $2);
454		}
455	| DT_LABEL subnode
456		{
457			add_label(&$2->labels, $1);
458			$$ = $2;
459		}
460	;
461
462%%
463
464void print_error(char const *fmt, ...)
465{
466	va_list va;
467
468	va_start(va, fmt);
469	srcpos_verror(&yylloc, "Error", fmt, va);
470	va_end(va);
471
472	treesource_error = true;
473}
474
475void yyerror(char const *s) {
476	print_error("%s", s);
477}
478