]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/dtc/dtc-parser.y
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / 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 %{
22 #include <stdio.h>
23
24 #include "dtc.h"
25 #include "srcpos.h"
26
27 YYLTYPE yylloc;
28
29 extern int yylex(void);
30 extern void print_error(char const *fmt, ...);
31 extern void yyerror(char const *s);
32
33 extern struct boot_info *the_boot_info;
34 extern 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
104 sourcefile:
105           DT_V1 ';' memreserves devicetree
106                 {
107                         the_boot_info = build_boot_info($3, $4,
108                                                         guess_boot_cpuid($4));
109                 }
110         ;
111
112 memreserves:
113           /* empty */
114                 {
115                         $$ = NULL;
116                 }
117         | memreserve memreserves
118                 {
119                         $$ = chain_reserve_entry($1, $2);
120                 }
121         ;
122
123 memreserve:
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
135 devicetree:
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
167 nodedef:
168           '{' proplist subnodes '}' ';'
169                 {
170                         $$ = build_node($2, $3);
171                 }
172         ;
173
174 proplist:
175           /* empty */
176                 {
177                         $$ = NULL;
178                 }
179         | proplist propdef
180                 {
181                         $$ = chain_property($2, $1);
182                 }
183         ;
184
185 propdef:
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
205 propdata:
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
254 propdataprefix:
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
269 arrayprefix:
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
332 integer_prim:
333           DT_LITERAL
334         | DT_CHAR_LITERAL
335         | '(' integer_expr ')'
336                 {
337                         $$ = $2;
338                 }
339         ;
340
341 integer_expr:
342         integer_trinary
343         ;
344
345 integer_trinary:
346           integer_or
347         | integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
348         ;
349
350 integer_or:
351           integer_and
352         | integer_or DT_OR integer_and { $$ = $1 || $3; }
353         ;
354
355 integer_and:
356           integer_bitor
357         | integer_and DT_AND integer_bitor { $$ = $1 && $3; }
358         ;
359
360 integer_bitor:
361           integer_bitxor
362         | integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
363         ;
364
365 integer_bitxor:
366           integer_bitand
367         | integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
368         ;
369
370 integer_bitand:
371           integer_eq
372         | integer_bitand '&' integer_eq { $$ = $1 & $3; }
373         ;
374
375 integer_eq:
376           integer_rela
377         | integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
378         | integer_eq DT_NE integer_rela { $$ = $1 != $3; }
379         ;
380
381 integer_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
389 integer_shift:
390           integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
391         | integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
392         | integer_add
393         ;
394
395 integer_add:
396           integer_add '+' integer_mul { $$ = $1 + $3; }
397         | integer_add '-' integer_mul { $$ = $1 - $3; }
398         | integer_mul
399         ;
400
401 integer_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
408 integer_unary:
409           integer_prim
410         | '-' integer_unary { $$ = -$2; }
411         | '~' integer_unary { $$ = ~$2; }
412         | '!' integer_unary { $$ = !$2; }
413         ;
414
415 bytestring:
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
430 subnodes:
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
446 subnode:
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
464 void 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
475 void yyerror(char const *s) {
476         print_error("%s", s);
477 }