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