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