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