dtc-parser.y 10.1 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 21
/*
 * (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
 */

%{
22 23
#include <stdio.h>

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

27 28
YYLTYPE yylloc;

29
extern int yylex(void);
30 31
extern void print_error(char const *fmt, ...);
extern void yyerror(char const *s);
D
David Gibson 已提交
32 33

extern struct boot_info *the_boot_info;
34
extern int treesource_error;
D
David Gibson 已提交
35

36
static unsigned long long eval_literal(const char *s, int base, int bits);
S
Stephen Warren 已提交
37
static unsigned char eval_char_literal(const char *s);
D
David Gibson 已提交
38 39 40 41 42 43 44
%}

%union {
	char *propnodename;
	char *literal;
	char *labelref;
	unsigned int cbase;
45
	uint8_t byte;
D
David Gibson 已提交
46 47
	struct data data;

S
Stephen Warren 已提交
48 49 50 51 52
	struct {
		struct data	data;
		int		bits;
	} array;

D
David Gibson 已提交
53 54 55 56 57
	struct property *prop;
	struct property *proplist;
	struct node *node;
	struct node *nodelist;
	struct reserve_info *re;
S
Stephen Warren 已提交
58
	uint64_t integer;
D
David Gibson 已提交
59 60 61 62
}

%token DT_V1
%token DT_MEMRESERVE
S
Stephen Warren 已提交
63 64 65 66
%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 已提交
67 68
%token <propnodename> DT_PROPNODENAME
%token <literal> DT_LITERAL
S
Stephen Warren 已提交
69
%token <literal> DT_CHAR_LITERAL
D
David Gibson 已提交
70 71 72 73 74
%token <cbase> DT_BASE
%token <byte> DT_BYTE
%token <data> DT_STRING
%token <labelref> DT_LABEL
%token <labelref> DT_REF
75
%token DT_INCBIN
D
David Gibson 已提交
76 77 78 79 80

%type <data> propdata
%type <data> propdataprefix
%type <re> memreserve
%type <re> memreserves
S
Stephen Warren 已提交
81
%type <array> arrayprefix
D
David Gibson 已提交
82 83 84 85 86 87 88 89 90
%type <data> bytestring
%type <prop> propdef
%type <proplist> proplist

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

S
Stephen Warren 已提交
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
%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 已提交
106 107 108 109 110
%%

sourcefile:
	  DT_V1 ';' memreserves devicetree
		{
111 112
			the_boot_info = build_boot_info($3, $4,
							guess_boot_cpuid($4));
D
David Gibson 已提交
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
		}
	;

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

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

devicetree:
	  '/' nodedef
		{
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
			$$ = name_node($2, "");
		}
	| devicetree '/' nodedef
		{
			$$ = merge_nodes($1, $3);
		}
	| devicetree DT_REF nodedef
		{
			struct node *target = get_node_by_ref($1, $2);

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

			if (!target)
				print_error("label or path, '%s', not found", $3);
			else
				delete_node(target);

			$$ = $1;
		}
D
David Gibson 已提交
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
	;

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

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

propdef:
190 191 192 193 194
	  DT_PROPNODENAME '=' propdata ';'
		{
			$$ = build_property($1, $3);
		}
	| DT_PROPNODENAME ';'
D
David Gibson 已提交
195
		{
196
			$$ = build_property($1, empty_data);
D
David Gibson 已提交
197
		}
S
Stephen Warren 已提交
198 199 200 201
	| DT_DEL_PROP DT_PROPNODENAME ';'
		{
			$$ = build_property_delete($2);
		}
202
	| DT_LABEL propdef
D
David Gibson 已提交
203
		{
204 205
			add_label(&$2->labels, $1);
			$$ = $2;
D
David Gibson 已提交
206 207 208 209 210 211 212 213
		}
	;

propdata:
	  propdataprefix DT_STRING
		{
			$$ = data_merge($1, $2);
		}
S
Stephen Warren 已提交
214
	| propdataprefix arrayprefix '>'
D
David Gibson 已提交
215
		{
S
Stephen Warren 已提交
216
			$$ = data_merge($1, $2.data);
D
David Gibson 已提交
217 218 219 220 221 222 223 224 225
		}
	| propdataprefix '[' bytestring ']'
		{
			$$ = data_merge($1, $3);
		}
	| propdataprefix DT_REF
		{
			$$ = data_add_marker($1, REF_PATH, $2);
		}
S
Stephen Warren 已提交
226
	| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
227
		{
228 229
			FILE *f = srcfile_relative_open($4.val, NULL);
			struct data d;
230 231

			if ($6 != 0)
232 233 234 235 236
				if (fseek(f, $6, SEEK_SET) != 0)
					print_error("Couldn't seek to offset %llu in \"%s\": %s",
						     (unsigned long long)$6,
						     $4.val,
						     strerror(errno));
237

238
			d = data_copy_file(f, $8);
239 240

			$$ = data_merge($1, d);
241
			fclose(f);
242 243 244
		}
	| propdataprefix DT_INCBIN '(' DT_STRING ')'
		{
245
			FILE *f = srcfile_relative_open($4.val, NULL);
246 247
			struct data d = empty_data;

248
			d = data_copy_file(f, -1);
249 250

			$$ = data_merge($1, d);
251
			fclose(f);
252
		}
D
David Gibson 已提交
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
	| 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 已提交
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
arrayprefix:
	DT_BITS DT_LITERAL '<'
		{
			$$.data = empty_data;
			$$.bits = eval_literal($2, 0, 7);

			if (($$.bits !=  8) &&
			    ($$.bits != 16) &&
			    ($$.bits != 32) &&
			    ($$.bits != 64))
			{
				print_error("Only 8, 16, 32 and 64-bit elements"
					    " are currently supported");
				$$.bits = 32;
			}
		}
	| '<'
		{
			$$.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))
					print_error(
						"integer value out of range "
						"%016lx (%d bits)", $1.bits);
			}

			$$.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
				print_error("References are only allowed in "
					    "arrays with 32-bit elements.");

			$$.data = data_append_integer($1.data, val, $1.bits);
		}
	| arrayprefix DT_LABEL
D
David Gibson 已提交
330
		{
S
Stephen Warren 已提交
331
			$$.data = data_add_marker($1.data, LABEL, $2);
D
David Gibson 已提交
332
		}
S
Stephen Warren 已提交
333 334 335 336
	;

integer_prim:
	  DT_LITERAL
D
David Gibson 已提交
337
		{
S
Stephen Warren 已提交
338
			$$ = eval_literal($1, 0, 64);
D
David Gibson 已提交
339
		}
S
Stephen Warren 已提交
340
	| DT_CHAR_LITERAL
D
David Gibson 已提交
341
		{
S
Stephen Warren 已提交
342
			$$ = eval_char_literal($1);
D
David Gibson 已提交
343
		}
S
Stephen Warren 已提交
344
	| '(' integer_expr ')'
D
David Gibson 已提交
345
		{
S
Stephen Warren 已提交
346
			$$ = $2;
D
David Gibson 已提交
347 348 349
		}
	;

S
Stephen Warren 已提交
350 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
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 已提交
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
	;

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

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

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

%%

473
void print_error(char const *fmt, ...)
D
David Gibson 已提交
474
{
475
	va_list va;
D
David Gibson 已提交
476

477 478 479
	va_start(va, fmt);
	srcpos_verror(&yylloc, fmt, va);
	va_end(va);
480 481 482 483

	treesource_error = 1;
}

484 485
void yyerror(char const *s) {
	print_error("%s", s);
D
David Gibson 已提交
486 487
}

488
static unsigned long long eval_literal(const char *s, int base, int bits)
D
David Gibson 已提交
489 490 491 492 493 494
{
	unsigned long long val;
	char *e;

	errno = 0;
	val = strtoull(s, &e, base);
S
Stephen Warren 已提交
495 496 497 498 499 500
	if (*e) {
		size_t uls = strspn(e, "UL");
		if (e[uls])
			print_error("bad characters in literal");
	}
	if ((errno == ERANGE)
D
David Gibson 已提交
501
		 || ((bits < 64) && (val >= (1ULL << bits))))
502
		print_error("literal out of range");
D
David Gibson 已提交
503
	else if (errno != 0)
504
		print_error("bad literal");
D
David Gibson 已提交
505 506
	return val;
}
S
Stephen Warren 已提交
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532

static unsigned char eval_char_literal(const char *s)
{
	int i = 1;
	char c = s[0];

	if (c == '\0')
	{
		print_error("empty character literal");
		return 0;
	}

	/*
	 * If the first character in the character literal is a \ then process
	 * the remaining characters as an escape encoding. If the first
	 * character is neither an escape or a terminator it should be the only
	 * character in the literal and will be returned.
	 */
	if (c == '\\')
		c = get_escape_char(s, &i);

	if (s[i] != '\0')
		print_error("malformed character literal");

	return c;
}