dtc-parser.y 8.9 KB
Newer Older
D
David Gibson 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
 *
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 *                                                                   USA
 */
%{
21 22
#include <stdio.h>

D
David Gibson 已提交
23 24 25
#include "dtc.h"
#include "srcpos.h"

26
extern int yylex(void);
27
extern void yyerror(char const *s);
28 29 30 31 32
#define ERROR(loc, ...) \
	do { \
		srcpos_error((loc), "Error", __VA_ARGS__); \
		treesource_error = true; \
	} while (0)
D
David Gibson 已提交
33 34

extern struct boot_info *the_boot_info;
35
extern bool treesource_error;
D
David Gibson 已提交
36 37 38 39 40
%}

%union {
	char *propnodename;
	char *labelref;
41
	uint8_t byte;
D
David Gibson 已提交
42 43
	struct data data;

S
Stephen Warren 已提交
44 45 46 47 48
	struct {
		struct data	data;
		int		bits;
	} array;

D
David Gibson 已提交
49 50 51 52 53
	struct property *prop;
	struct property *proplist;
	struct node *node;
	struct node *nodelist;
	struct reserve_info *re;
S
Stephen Warren 已提交
54
	uint64_t integer;
D
David Gibson 已提交
55 56 57 58
}

%token DT_V1
%token DT_MEMRESERVE
S
Stephen Warren 已提交
59 60 61 62
%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
%token DT_BITS
%token DT_DEL_PROP
%token DT_DEL_NODE
D
David Gibson 已提交
63
%token <propnodename> DT_PROPNODENAME
64 65
%token <integer> DT_LITERAL
%token <integer> DT_CHAR_LITERAL
D
David Gibson 已提交
66 67 68 69
%token <byte> DT_BYTE
%token <data> DT_STRING
%token <labelref> DT_LABEL
%token <labelref> DT_REF
70
%token DT_INCBIN
D
David Gibson 已提交
71 72 73 74 75

%type <data> propdata
%type <data> propdataprefix
%type <re> memreserve
%type <re> memreserves
S
Stephen Warren 已提交
76
%type <array> arrayprefix
D
David Gibson 已提交
77 78 79 80 81 82 83 84 85
%type <data> bytestring
%type <prop> propdef
%type <proplist> proplist

%type <node> devicetree
%type <node> nodedef
%type <node> subnode
%type <nodelist> subnodes

S
Stephen Warren 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
%type <integer> integer_prim
%type <integer> integer_unary
%type <integer> integer_mul
%type <integer> integer_add
%type <integer> integer_shift
%type <integer> integer_rela
%type <integer> integer_eq
%type <integer> integer_bitand
%type <integer> integer_bitxor
%type <integer> integer_bitor
%type <integer> integer_and
%type <integer> integer_or
%type <integer> integer_trinary
%type <integer> integer_expr

D
David Gibson 已提交
101 102 103 104 105
%%

sourcefile:
	  DT_V1 ';' memreserves devicetree
		{
106 107
			the_boot_info = build_boot_info($3, $4,
							guess_boot_cpuid($4));
D
David Gibson 已提交
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
		}
	;

memreserves:
	  /* empty */
		{
			$$ = NULL;
		}
	| memreserve memreserves
		{
			$$ = chain_reserve_entry($1, $2);
		}
	;

memreserve:
S
Stephen Warren 已提交
123
	  DT_MEMRESERVE integer_prim integer_prim ';'
D
David Gibson 已提交
124
		{
125
			$$ = build_reserve_entry($2, $3);
D
David Gibson 已提交
126
		}
127
	| DT_LABEL memreserve
D
David Gibson 已提交
128
		{
129 130
			add_label(&$2->labels, $1);
			$$ = $2;
D
David Gibson 已提交
131 132 133 134 135 136
		}
	;

devicetree:
	  '/' nodedef
		{
137 138 139 140 141 142
			$$ = name_node($2, "");
		}
	| devicetree '/' nodedef
		{
			$$ = merge_nodes($1, $3);
		}
143 144 145 146 147 148 149 150 151 152 153 154

	| devicetree DT_LABEL DT_REF nodedef
		{
			struct node *target = get_node_by_ref($1, $3);

			add_label(&target->labels, $2);
			if (target)
				merge_nodes(target, $4);
			else
				ERROR(&@3, "Label or path %s not found", $3);
			$$ = $1;
		}
155 156 157 158 159 160 161
	| devicetree DT_REF nodedef
		{
			struct node *target = get_node_by_ref($1, $2);

			if (target)
				merge_nodes(target, $3);
			else
162
				ERROR(&@2, "Label or path %s not found", $2);
163
			$$ = $1;
D
David Gibson 已提交
164
		}
S
Stephen Warren 已提交
165 166 167 168
	| devicetree DT_DEL_NODE DT_REF ';'
		{
			struct node *target = get_node_by_ref($1, $3);

169
			if (target)
S
Stephen Warren 已提交
170
				delete_node(target);
171 172 173
			else
				ERROR(&@3, "Label or path %s not found", $3);

S
Stephen Warren 已提交
174 175 176

			$$ = $1;
		}
D
David Gibson 已提交
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
	;

nodedef:
	  '{' proplist subnodes '}' ';'
		{
			$$ = build_node($2, $3);
		}
	;

proplist:
	  /* empty */
		{
			$$ = NULL;
		}
	| proplist propdef
		{
			$$ = chain_property($2, $1);
		}
	;

propdef:
198 199 200 201 202
	  DT_PROPNODENAME '=' propdata ';'
		{
			$$ = build_property($1, $3);
		}
	| DT_PROPNODENAME ';'
D
David Gibson 已提交
203
		{
204
			$$ = build_property($1, empty_data);
D
David Gibson 已提交
205
		}
S
Stephen Warren 已提交
206 207 208 209
	| DT_DEL_PROP DT_PROPNODENAME ';'
		{
			$$ = build_property_delete($2);
		}
210
	| DT_LABEL propdef
D
David Gibson 已提交
211
		{
212 213
			add_label(&$2->labels, $1);
			$$ = $2;
D
David Gibson 已提交
214 215 216 217 218 219 220 221
		}
	;

propdata:
	  propdataprefix DT_STRING
		{
			$$ = data_merge($1, $2);
		}
S
Stephen Warren 已提交
222
	| propdataprefix arrayprefix '>'
D
David Gibson 已提交
223
		{
S
Stephen Warren 已提交
224
			$$ = data_merge($1, $2.data);
D
David Gibson 已提交
225 226 227 228 229 230 231 232 233
		}
	| propdataprefix '[' bytestring ']'
		{
			$$ = data_merge($1, $3);
		}
	| propdataprefix DT_REF
		{
			$$ = data_add_marker($1, REF_PATH, $2);
		}
S
Stephen Warren 已提交
234
	| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
235
		{
236 237
			FILE *f = srcfile_relative_open($4.val, NULL);
			struct data d;
238 239

			if ($6 != 0)
240
				if (fseek(f, $6, SEEK_SET) != 0)
241 242 243
					die("Couldn't seek to offset %llu in \"%s\": %s",
					    (unsigned long long)$6, $4.val,
					    strerror(errno));
244

245
			d = data_copy_file(f, $8);
246 247

			$$ = data_merge($1, d);
248
			fclose(f);
249 250 251
		}
	| propdataprefix DT_INCBIN '(' DT_STRING ')'
		{
252
			FILE *f = srcfile_relative_open($4.val, NULL);
253 254
			struct data d = empty_data;

255
			d = data_copy_file(f, -1);
256 257

			$$ = data_merge($1, d);
258
			fclose(f);
259
		}
D
David Gibson 已提交
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
	| propdata DT_LABEL
		{
			$$ = data_add_marker($1, LABEL, $2);
		}
	;

propdataprefix:
	  /* empty */
		{
			$$ = empty_data;
		}
	| propdata ','
		{
			$$ = $1;
		}
	| propdataprefix DT_LABEL
		{
			$$ = data_add_marker($1, LABEL, $2);
		}
	;

S
Stephen Warren 已提交
281 282 283
arrayprefix:
	DT_BITS DT_LITERAL '<'
		{
284 285 286 287 288 289 290 291 292
			unsigned long long bits;

			bits = $2;

			if ((bits !=  8) && (bits != 16) &&
			    (bits != 32) && (bits != 64)) {
				ERROR(&@2, "Array elements must be"
				      " 8, 16, 32 or 64-bits");
				bits = 32;
S
Stephen Warren 已提交
293
			}
294 295 296

			$$.data = empty_data;
			$$.bits = bits;
S
Stephen Warren 已提交
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
		}
	| '<'
		{
			$$.data = empty_data;
			$$.bits = 32;
		}
	| arrayprefix integer_prim
		{
			if ($1.bits < 64) {
				uint64_t mask = (1ULL << $1.bits) - 1;
				/*
				 * Bits above mask must either be all zero
				 * (positive within range of mask) or all one
				 * (negative and sign-extended). The second
				 * condition is true if when we set all bits
				 * within the mask to one (i.e. | in the
				 * mask), all bits are one.
				 */
				if (($2 > mask) && (($2 | mask) != -1ULL))
316 317
					ERROR(&@2, "Value out of range for"
					      " %d-bit array element", $1.bits);
S
Stephen Warren 已提交
318 319 320 321 322 323 324 325 326 327 328 329 330
			}

			$$.data = data_append_integer($1.data, $2, $1.bits);
		}
	| arrayprefix DT_REF
		{
			uint64_t val = ~0ULL >> (64 - $1.bits);

			if ($1.bits == 32)
				$1.data = data_add_marker($1.data,
							  REF_PHANDLE,
							  $2);
			else
331
				ERROR(&@2, "References are only allowed in "
S
Stephen Warren 已提交
332 333 334 335 336
					    "arrays with 32-bit elements.");

			$$.data = data_append_integer($1.data, val, $1.bits);
		}
	| arrayprefix DT_LABEL
D
David Gibson 已提交
337
		{
S
Stephen Warren 已提交
338
			$$.data = data_add_marker($1.data, LABEL, $2);
D
David Gibson 已提交
339
		}
S
Stephen Warren 已提交
340 341 342 343 344 345
	;

integer_prim:
	  DT_LITERAL
	| DT_CHAR_LITERAL
	| '(' integer_expr ')'
D
David Gibson 已提交
346
		{
S
Stephen Warren 已提交
347
			$$ = $2;
D
David Gibson 已提交
348 349 350
		}
	;

S
Stephen Warren 已提交
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
integer_expr:
	integer_trinary
	;

integer_trinary:
	  integer_or
	| integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
	;

integer_or:
	  integer_and
	| integer_or DT_OR integer_and { $$ = $1 || $3; }
	;

integer_and:
	  integer_bitor
	| integer_and DT_AND integer_bitor { $$ = $1 && $3; }
	;

integer_bitor:
	  integer_bitxor
	| integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
	;

integer_bitxor:
	  integer_bitand
	| integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
	;

integer_bitand:
	  integer_eq
	| integer_bitand '&' integer_eq { $$ = $1 & $3; }
	;

integer_eq:
	  integer_rela
	| integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
	| integer_eq DT_NE integer_rela { $$ = $1 != $3; }
	;

integer_rela:
	  integer_shift
	| integer_rela '<' integer_shift { $$ = $1 < $3; }
	| integer_rela '>' integer_shift { $$ = $1 > $3; }
	| integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
	| integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
	;

integer_shift:
	  integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
	| integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
	| integer_add
	;

integer_add:
	  integer_add '+' integer_mul { $$ = $1 + $3; }
	| integer_add '-' integer_mul { $$ = $1 - $3; }
	| integer_mul
	;

integer_mul:
	  integer_mul '*' integer_unary { $$ = $1 * $3; }
	| integer_mul '/' integer_unary { $$ = $1 / $3; }
	| integer_mul '%' integer_unary { $$ = $1 % $3; }
	| integer_unary
	;

integer_unary:
	  integer_prim
	| '-' integer_unary { $$ = -$2; }
	| '~' integer_unary { $$ = ~$2; }
	| '!' integer_unary { $$ = !$2; }
D
David Gibson 已提交
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
	;

bytestring:
	  /* empty */
		{
			$$ = empty_data;
		}
	| bytestring DT_BYTE
		{
			$$ = data_append_byte($1, $2);
		}
	| bytestring DT_LABEL
		{
			$$ = data_add_marker($1, LABEL, $2);
		}
	;

subnodes:
	  /* empty */
		{
			$$ = NULL;
		}
445
	| subnode subnodes
D
David Gibson 已提交
446 447 448 449 450
		{
			$$ = chain_node($1, $2);
		}
	| subnode propdef
		{
451
			ERROR(&@2, "Properties must precede subnodes");
D
David Gibson 已提交
452 453 454 455 456
			YYERROR;
		}
	;

subnode:
457
	  DT_PROPNODENAME nodedef
D
David Gibson 已提交
458
		{
459
			$$ = name_node($2, $1);
D
David Gibson 已提交
460
		}
S
Stephen Warren 已提交
461 462 463 464
	| DT_DEL_NODE DT_PROPNODENAME ';'
		{
			$$ = name_node(build_node_delete(), $2);
		}
465
	| DT_LABEL subnode
D
David Gibson 已提交
466
		{
467 468
			add_label(&$2->labels, $1);
			$$ = $2;
D
David Gibson 已提交
469 470 471 472 473
		}
	;

%%

474
void yyerror(char const *s)
S
Stephen Warren 已提交
475
{
476
	ERROR(&yylloc, "%s", s);
S
Stephen Warren 已提交
477
}