]> asedeno.scripts.mit.edu Git - linux.git/blob - scripts/dtc/dtc-parser.y
Merge tag 'powerpc-4.20-2' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux
[linux.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                         $1 = data_add_marker($1, TYPE_STRING, $2);
291                         $$ = data_add_marker($1, REF_PATH, $2);
292                 }
293         | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
294                 {
295                         FILE *f = srcfile_relative_open($4.val, NULL);
296                         struct data d;
297
298                         if ($6 != 0)
299                                 if (fseek(f, $6, SEEK_SET) != 0)
300                                         die("Couldn't seek to offset %llu in \"%s\": %s",
301                                             (unsigned long long)$6, $4.val,
302                                             strerror(errno));
303
304                         d = data_copy_file(f, $8);
305
306                         $$ = data_merge($1, d);
307                         fclose(f);
308                 }
309         | propdataprefix DT_INCBIN '(' DT_STRING ')'
310                 {
311                         FILE *f = srcfile_relative_open($4.val, NULL);
312                         struct data d = empty_data;
313
314                         d = data_copy_file(f, -1);
315
316                         $$ = data_merge($1, d);
317                         fclose(f);
318                 }
319         | propdata DT_LABEL
320                 {
321                         $$ = data_add_marker($1, LABEL, $2);
322                 }
323         ;
324
325 propdataprefix:
326           /* empty */
327                 {
328                         $$ = empty_data;
329                 }
330         | propdata ','
331                 {
332                         $$ = $1;
333                 }
334         | propdataprefix DT_LABEL
335                 {
336                         $$ = data_add_marker($1, LABEL, $2);
337                 }
338         ;
339
340 arrayprefix:
341         DT_BITS DT_LITERAL '<'
342                 {
343                         unsigned long long bits;
344                         enum markertype type = TYPE_UINT32;
345
346                         bits = $2;
347
348                         switch (bits) {
349                         case 8: type = TYPE_UINT8; break;
350                         case 16: type = TYPE_UINT16; break;
351                         case 32: type = TYPE_UINT32; break;
352                         case 64: type = TYPE_UINT64; break;
353                         default:
354                                 ERROR(&@2, "Array elements must be"
355                                       " 8, 16, 32 or 64-bits");
356                                 bits = 32;
357                         }
358
359                         $$.data = data_add_marker(empty_data, type, NULL);
360                         $$.bits = bits;
361                 }
362         | '<'
363                 {
364                         $$.data = data_add_marker(empty_data, TYPE_UINT32, NULL);
365                         $$.bits = 32;
366                 }
367         | arrayprefix integer_prim
368                 {
369                         if ($1.bits < 64) {
370                                 uint64_t mask = (1ULL << $1.bits) - 1;
371                                 /*
372                                  * Bits above mask must either be all zero
373                                  * (positive within range of mask) or all one
374                                  * (negative and sign-extended). The second
375                                  * condition is true if when we set all bits
376                                  * within the mask to one (i.e. | in the
377                                  * mask), all bits are one.
378                                  */
379                                 if (($2 > mask) && (($2 | mask) != -1ULL))
380                                         ERROR(&@2, "Value out of range for"
381                                               " %d-bit array element", $1.bits);
382                         }
383
384                         $$.data = data_append_integer($1.data, $2, $1.bits);
385                 }
386         | arrayprefix DT_REF
387                 {
388                         uint64_t val = ~0ULL >> (64 - $1.bits);
389
390                         if ($1.bits == 32)
391                                 $1.data = data_add_marker($1.data,
392                                                           REF_PHANDLE,
393                                                           $2);
394                         else
395                                 ERROR(&@2, "References are only allowed in "
396                                             "arrays with 32-bit elements.");
397
398                         $$.data = data_append_integer($1.data, val, $1.bits);
399                 }
400         | arrayprefix DT_LABEL
401                 {
402                         $$.data = data_add_marker($1.data, LABEL, $2);
403                 }
404         ;
405
406 integer_prim:
407           DT_LITERAL
408         | DT_CHAR_LITERAL
409         | '(' integer_expr ')'
410                 {
411                         $$ = $2;
412                 }
413         ;
414
415 integer_expr:
416         integer_trinary
417         ;
418
419 integer_trinary:
420           integer_or
421         | integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
422         ;
423
424 integer_or:
425           integer_and
426         | integer_or DT_OR integer_and { $$ = $1 || $3; }
427         ;
428
429 integer_and:
430           integer_bitor
431         | integer_and DT_AND integer_bitor { $$ = $1 && $3; }
432         ;
433
434 integer_bitor:
435           integer_bitxor
436         | integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
437         ;
438
439 integer_bitxor:
440           integer_bitand
441         | integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
442         ;
443
444 integer_bitand:
445           integer_eq
446         | integer_bitand '&' integer_eq { $$ = $1 & $3; }
447         ;
448
449 integer_eq:
450           integer_rela
451         | integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
452         | integer_eq DT_NE integer_rela { $$ = $1 != $3; }
453         ;
454
455 integer_rela:
456           integer_shift
457         | integer_rela '<' integer_shift { $$ = $1 < $3; }
458         | integer_rela '>' integer_shift { $$ = $1 > $3; }
459         | integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
460         | integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
461         ;
462
463 integer_shift:
464           integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
465         | integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
466         | integer_add
467         ;
468
469 integer_add:
470           integer_add '+' integer_mul { $$ = $1 + $3; }
471         | integer_add '-' integer_mul { $$ = $1 - $3; }
472         | integer_mul
473         ;
474
475 integer_mul:
476           integer_mul '*' integer_unary { $$ = $1 * $3; }
477         | integer_mul '/' integer_unary
478                 {
479                         if ($3 != 0) {
480                                 $$ = $1 / $3;
481                         } else {
482                                 ERROR(&@$, "Division by zero");
483                                 $$ = 0;
484                         }
485                 }
486         | integer_mul '%' integer_unary
487                 {
488                         if ($3 != 0) {
489                                 $$ = $1 % $3;
490                         } else {
491                                 ERROR(&@$, "Division by zero");
492                                 $$ = 0;
493                         }
494                 }
495         | integer_unary
496         ;
497
498 integer_unary:
499           integer_prim
500         | '-' integer_unary { $$ = -$2; }
501         | '~' integer_unary { $$ = ~$2; }
502         | '!' integer_unary { $$ = !$2; }
503         ;
504
505 bytestring:
506           /* empty */
507                 {
508                         $$ = data_add_marker(empty_data, TYPE_UINT8, NULL);
509                 }
510         | bytestring DT_BYTE
511                 {
512                         $$ = data_append_byte($1, $2);
513                 }
514         | bytestring DT_LABEL
515                 {
516                         $$ = data_add_marker($1, LABEL, $2);
517                 }
518         ;
519
520 subnodes:
521           /* empty */
522                 {
523                         $$ = NULL;
524                 }
525         | subnode subnodes
526                 {
527                         $$ = chain_node($1, $2);
528                 }
529         | subnode propdef
530                 {
531                         ERROR(&@2, "Properties must precede subnodes");
532                         YYERROR;
533                 }
534         ;
535
536 subnode:
537           DT_PROPNODENAME nodedef
538                 {
539                         $$ = name_node($2, $1);
540                 }
541         | DT_DEL_NODE DT_PROPNODENAME ';'
542                 {
543                         $$ = name_node(build_node_delete(), $2);
544                 }
545         | DT_OMIT_NO_REF subnode
546                 {
547                         $$ = omit_node_if_unused($2);
548                 }
549         | DT_LABEL subnode
550                 {
551                         add_label(&$2->labels, $1);
552                         $$ = $2;
553                 }
554         ;
555
556 %%
557
558 void yyerror(char const *s)
559 {
560         ERROR(&yylloc, "%s", s);
561 }