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