xref: /openbmc/u-boot/scripts/dtc/dtc-parser.y (revision 3eceff64)
1c0e032e0STom Rini /*
2c0e032e0STom Rini  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
3c0e032e0STom Rini  *
4c0e032e0STom Rini  *
5c0e032e0STom Rini  * This program is free software; you can redistribute it and/or
6c0e032e0STom Rini  * modify it under the terms of the GNU General Public License as
7c0e032e0STom Rini  * published by the Free Software Foundation; either version 2 of the
8c0e032e0STom Rini  * License, or (at your option) any later version.
9c0e032e0STom Rini  *
10c0e032e0STom Rini  *  This program is distributed in the hope that it will be useful,
11c0e032e0STom Rini  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12c0e032e0STom Rini  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13c0e032e0STom Rini  *  General Public License for more details.
14c0e032e0STom Rini  *
15c0e032e0STom Rini  *  You should have received a copy of the GNU General Public License
16c0e032e0STom Rini  *  along with this program; if not, write to the Free Software
17c0e032e0STom Rini  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18c0e032e0STom Rini  *                                                                   USA
19c0e032e0STom Rini  */
20c0e032e0STom Rini %{
21c0e032e0STom Rini #include <stdio.h>
22c0e032e0STom Rini #include <inttypes.h>
23c0e032e0STom Rini 
24c0e032e0STom Rini #include "dtc.h"
25c0e032e0STom Rini #include "srcpos.h"
26c0e032e0STom Rini 
27c0e032e0STom Rini extern int yylex(void);
28c0e032e0STom Rini extern void yyerror(char const *s);
29c0e032e0STom Rini #define ERROR(loc, ...) \
30c0e032e0STom Rini 	do { \
31c0e032e0STom Rini 		srcpos_error((loc), "Error", __VA_ARGS__); \
32c0e032e0STom Rini 		treesource_error = true; \
33c0e032e0STom Rini 	} while (0)
34c0e032e0STom Rini 
35c0e032e0STom Rini extern struct dt_info *parser_output;
36c0e032e0STom Rini extern bool treesource_error;
37c0e032e0STom Rini %}
38c0e032e0STom Rini 
39c0e032e0STom Rini %union {
40c0e032e0STom Rini 	char *propnodename;
41c0e032e0STom Rini 	char *labelref;
42c0e032e0STom Rini 	uint8_t byte;
43c0e032e0STom Rini 	struct data data;
44c0e032e0STom Rini 
45c0e032e0STom Rini 	struct {
46c0e032e0STom Rini 		struct data	data;
47c0e032e0STom Rini 		int		bits;
48c0e032e0STom Rini 	} array;
49c0e032e0STom Rini 
50c0e032e0STom Rini 	struct property *prop;
51c0e032e0STom Rini 	struct property *proplist;
52c0e032e0STom Rini 	struct node *node;
53c0e032e0STom Rini 	struct node *nodelist;
54c0e032e0STom Rini 	struct reserve_info *re;
55c0e032e0STom Rini 	uint64_t integer;
56c0e032e0STom Rini 	unsigned int flags;
57c0e032e0STom Rini }
58c0e032e0STom Rini 
59c0e032e0STom Rini %token DT_V1
60c0e032e0STom Rini %token DT_PLUGIN
61c0e032e0STom Rini %token DT_MEMRESERVE
62c0e032e0STom Rini %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
63c0e032e0STom Rini %token DT_BITS
64c0e032e0STom Rini %token DT_DEL_PROP
65c0e032e0STom Rini %token DT_DEL_NODE
66c0e032e0STom Rini %token <propnodename> DT_PROPNODENAME
67c0e032e0STom Rini %token <integer> DT_LITERAL
68c0e032e0STom Rini %token <integer> DT_CHAR_LITERAL
69c0e032e0STom Rini %token <byte> DT_BYTE
70c0e032e0STom Rini %token <data> DT_STRING
71c0e032e0STom Rini %token <labelref> DT_LABEL
72c0e032e0STom Rini %token <labelref> DT_REF
73c0e032e0STom Rini %token DT_INCBIN
74c0e032e0STom Rini 
75c0e032e0STom Rini %type <data> propdata
76c0e032e0STom Rini %type <data> propdataprefix
77c0e032e0STom Rini %type <flags> header
78c0e032e0STom Rini %type <flags> headers
79c0e032e0STom Rini %type <re> memreserve
80c0e032e0STom Rini %type <re> memreserves
81c0e032e0STom Rini %type <array> arrayprefix
82c0e032e0STom Rini %type <data> bytestring
83c0e032e0STom Rini %type <prop> propdef
84c0e032e0STom Rini %type <proplist> proplist
85c0e032e0STom Rini 
86c0e032e0STom Rini %type <node> devicetree
87c0e032e0STom Rini %type <node> nodedef
88c0e032e0STom Rini %type <node> subnode
89c0e032e0STom Rini %type <nodelist> subnodes
90c0e032e0STom Rini 
91c0e032e0STom Rini %type <integer> integer_prim
92c0e032e0STom Rini %type <integer> integer_unary
93c0e032e0STom Rini %type <integer> integer_mul
94c0e032e0STom Rini %type <integer> integer_add
95c0e032e0STom Rini %type <integer> integer_shift
96c0e032e0STom Rini %type <integer> integer_rela
97c0e032e0STom Rini %type <integer> integer_eq
98c0e032e0STom Rini %type <integer> integer_bitand
99c0e032e0STom Rini %type <integer> integer_bitxor
100c0e032e0STom Rini %type <integer> integer_bitor
101c0e032e0STom Rini %type <integer> integer_and
102c0e032e0STom Rini %type <integer> integer_or
103c0e032e0STom Rini %type <integer> integer_trinary
104c0e032e0STom Rini %type <integer> integer_expr
105c0e032e0STom Rini 
106c0e032e0STom Rini %%
107c0e032e0STom Rini 
108c0e032e0STom Rini sourcefile:
109c0e032e0STom Rini 	  headers memreserves devicetree
110c0e032e0STom Rini 		{
111c0e032e0STom Rini 			parser_output = build_dt_info($1, $2, $3,
112c0e032e0STom Rini 			                              guess_boot_cpuid($3));
113c0e032e0STom Rini 		}
114c0e032e0STom Rini 	;
115c0e032e0STom Rini 
116c0e032e0STom Rini header:
117c0e032e0STom Rini 	  DT_V1 ';'
118c0e032e0STom Rini 		{
119c0e032e0STom Rini 			$$ = DTSF_V1;
120c0e032e0STom Rini 		}
121c0e032e0STom Rini 	| DT_V1 ';' DT_PLUGIN ';'
122c0e032e0STom Rini 		{
123c0e032e0STom Rini 			$$ = DTSF_V1 | DTSF_PLUGIN;
124c0e032e0STom Rini 		}
125c0e032e0STom Rini 	;
126c0e032e0STom Rini 
127c0e032e0STom Rini headers:
128c0e032e0STom Rini 	  header
129c0e032e0STom Rini 	| header headers
130c0e032e0STom Rini 		{
131c0e032e0STom Rini 			if ($2 != $1)
132c0e032e0STom Rini 				ERROR(&@2, "Header flags don't match earlier ones");
133c0e032e0STom Rini 			$$ = $1;
134c0e032e0STom Rini 		}
135c0e032e0STom Rini 	;
136c0e032e0STom Rini 
137c0e032e0STom Rini memreserves:
138c0e032e0STom Rini 	  /* empty */
139c0e032e0STom Rini 		{
140c0e032e0STom Rini 			$$ = NULL;
141c0e032e0STom Rini 		}
142c0e032e0STom Rini 	| memreserve memreserves
143c0e032e0STom Rini 		{
144c0e032e0STom Rini 			$$ = chain_reserve_entry($1, $2);
145c0e032e0STom Rini 		}
146c0e032e0STom Rini 	;
147c0e032e0STom Rini 
148c0e032e0STom Rini memreserve:
149c0e032e0STom Rini 	  DT_MEMRESERVE integer_prim integer_prim ';'
150c0e032e0STom Rini 		{
151c0e032e0STom Rini 			$$ = build_reserve_entry($2, $3);
152c0e032e0STom Rini 		}
153c0e032e0STom Rini 	| DT_LABEL memreserve
154c0e032e0STom Rini 		{
155c0e032e0STom Rini 			add_label(&$2->labels, $1);
156c0e032e0STom Rini 			$$ = $2;
157c0e032e0STom Rini 		}
158c0e032e0STom Rini 	;
159c0e032e0STom Rini 
160c0e032e0STom Rini devicetree:
161c0e032e0STom Rini 	  '/' nodedef
162c0e032e0STom Rini 		{
163c0e032e0STom Rini 			$$ = name_node($2, "");
164c0e032e0STom Rini 		}
165c0e032e0STom Rini 	| devicetree '/' nodedef
166c0e032e0STom Rini 		{
167c0e032e0STom Rini 			$$ = merge_nodes($1, $3);
168c0e032e0STom Rini 		}
169*db405d19SRob Herring 	| DT_REF nodedef
170*db405d19SRob Herring 		{
171*db405d19SRob Herring 			/*
172*db405d19SRob Herring 			 * We rely on the rule being always:
173*db405d19SRob Herring 			 *   versioninfo plugindecl memreserves devicetree
174*db405d19SRob Herring 			 * so $-1 is what we want (plugindecl)
175*db405d19SRob Herring 			 */
176*db405d19SRob Herring 			if (!($<flags>-1 & DTSF_PLUGIN))
177*db405d19SRob Herring 				ERROR(&@2, "Label or path %s not found", $1);
178*db405d19SRob Herring 			$$ = add_orphan_node(name_node(build_node(NULL, NULL), ""), $2, $1);
179*db405d19SRob Herring 		}
180c0e032e0STom Rini 	| devicetree DT_LABEL DT_REF nodedef
181c0e032e0STom Rini 		{
182c0e032e0STom Rini 			struct node *target = get_node_by_ref($1, $3);
183c0e032e0STom Rini 
184c0e032e0STom Rini 			if (target) {
185c0e032e0STom Rini 				add_label(&target->labels, $2);
186c0e032e0STom Rini 				merge_nodes(target, $4);
187c0e032e0STom Rini 			} else
188c0e032e0STom Rini 				ERROR(&@3, "Label or path %s not found", $3);
189c0e032e0STom Rini 			$$ = $1;
190c0e032e0STom Rini 		}
191c0e032e0STom Rini 	| devicetree DT_REF nodedef
192c0e032e0STom Rini 		{
193c0e032e0STom Rini 			struct node *target = get_node_by_ref($1, $2);
194c0e032e0STom Rini 
195999a78d5SMasahiro Yamada 			if (target) {
196c0e032e0STom Rini 				merge_nodes(target, $3);
197999a78d5SMasahiro Yamada 			} else {
198999a78d5SMasahiro Yamada 				/*
199999a78d5SMasahiro Yamada 				 * We rely on the rule being always:
200999a78d5SMasahiro Yamada 				 *   versioninfo plugindecl memreserves devicetree
201999a78d5SMasahiro Yamada 				 * so $-1 is what we want (plugindecl)
202999a78d5SMasahiro Yamada 				 */
203999a78d5SMasahiro Yamada 				if ($<flags>-1 & DTSF_PLUGIN)
204999a78d5SMasahiro Yamada 					add_orphan_node($1, $3, $2);
205c0e032e0STom Rini 				else
206c0e032e0STom Rini 					ERROR(&@2, "Label or path %s not found", $2);
207999a78d5SMasahiro Yamada 			}
208c0e032e0STom Rini 			$$ = $1;
209c0e032e0STom Rini 		}
210c0e032e0STom Rini 	| devicetree DT_DEL_NODE DT_REF ';'
211c0e032e0STom Rini 		{
212c0e032e0STom Rini 			struct node *target = get_node_by_ref($1, $3);
213c0e032e0STom Rini 
214c0e032e0STom Rini 			if (target)
215c0e032e0STom Rini 				delete_node(target);
216c0e032e0STom Rini 			else
217c0e032e0STom Rini 				ERROR(&@3, "Label or path %s not found", $3);
218c0e032e0STom Rini 
219c0e032e0STom Rini 
220c0e032e0STom Rini 			$$ = $1;
221c0e032e0STom Rini 		}
222c0e032e0STom Rini 	;
223c0e032e0STom Rini 
224c0e032e0STom Rini nodedef:
225c0e032e0STom Rini 	  '{' proplist subnodes '}' ';'
226c0e032e0STom Rini 		{
227c0e032e0STom Rini 			$$ = build_node($2, $3);
228c0e032e0STom Rini 		}
229c0e032e0STom Rini 	;
230c0e032e0STom Rini 
231c0e032e0STom Rini proplist:
232c0e032e0STom Rini 	  /* empty */
233c0e032e0STom Rini 		{
234c0e032e0STom Rini 			$$ = NULL;
235c0e032e0STom Rini 		}
236c0e032e0STom Rini 	| proplist propdef
237c0e032e0STom Rini 		{
238c0e032e0STom Rini 			$$ = chain_property($2, $1);
239c0e032e0STom Rini 		}
240c0e032e0STom Rini 	;
241c0e032e0STom Rini 
242c0e032e0STom Rini propdef:
243c0e032e0STom Rini 	  DT_PROPNODENAME '=' propdata ';'
244c0e032e0STom Rini 		{
245c0e032e0STom Rini 			$$ = build_property($1, $3);
246c0e032e0STom Rini 		}
247c0e032e0STom Rini 	| DT_PROPNODENAME ';'
248c0e032e0STom Rini 		{
249c0e032e0STom Rini 			$$ = build_property($1, empty_data);
250c0e032e0STom Rini 		}
251c0e032e0STom Rini 	| DT_DEL_PROP DT_PROPNODENAME ';'
252c0e032e0STom Rini 		{
253c0e032e0STom Rini 			$$ = build_property_delete($2);
254c0e032e0STom Rini 		}
255c0e032e0STom Rini 	| DT_LABEL propdef
256c0e032e0STom Rini 		{
257c0e032e0STom Rini 			add_label(&$2->labels, $1);
258c0e032e0STom Rini 			$$ = $2;
259c0e032e0STom Rini 		}
260c0e032e0STom Rini 	;
261c0e032e0STom Rini 
262c0e032e0STom Rini propdata:
263c0e032e0STom Rini 	  propdataprefix DT_STRING
264c0e032e0STom Rini 		{
265c0e032e0STom Rini 			$$ = data_merge($1, $2);
266c0e032e0STom Rini 		}
267c0e032e0STom Rini 	| propdataprefix arrayprefix '>'
268c0e032e0STom Rini 		{
269c0e032e0STom Rini 			$$ = data_merge($1, $2.data);
270c0e032e0STom Rini 		}
271c0e032e0STom Rini 	| propdataprefix '[' bytestring ']'
272c0e032e0STom Rini 		{
273c0e032e0STom Rini 			$$ = data_merge($1, $3);
274c0e032e0STom Rini 		}
275c0e032e0STom Rini 	| propdataprefix DT_REF
276c0e032e0STom Rini 		{
277c0e032e0STom Rini 			$$ = data_add_marker($1, REF_PATH, $2);
278c0e032e0STom Rini 		}
279c0e032e0STom Rini 	| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
280c0e032e0STom Rini 		{
281c0e032e0STom Rini 			FILE *f = srcfile_relative_open($4.val, NULL);
282c0e032e0STom Rini 			struct data d;
283c0e032e0STom Rini 
284c0e032e0STom Rini 			if ($6 != 0)
285c0e032e0STom Rini 				if (fseek(f, $6, SEEK_SET) != 0)
286c0e032e0STom Rini 					die("Couldn't seek to offset %llu in \"%s\": %s",
287c0e032e0STom Rini 					    (unsigned long long)$6, $4.val,
288c0e032e0STom Rini 					    strerror(errno));
289c0e032e0STom Rini 
290c0e032e0STom Rini 			d = data_copy_file(f, $8);
291c0e032e0STom Rini 
292c0e032e0STom Rini 			$$ = data_merge($1, d);
293c0e032e0STom Rini 			fclose(f);
294c0e032e0STom Rini 		}
295c0e032e0STom Rini 	| propdataprefix DT_INCBIN '(' DT_STRING ')'
296c0e032e0STom Rini 		{
297c0e032e0STom Rini 			FILE *f = srcfile_relative_open($4.val, NULL);
298c0e032e0STom Rini 			struct data d = empty_data;
299c0e032e0STom Rini 
300c0e032e0STom Rini 			d = data_copy_file(f, -1);
301c0e032e0STom Rini 
302c0e032e0STom Rini 			$$ = data_merge($1, d);
303c0e032e0STom Rini 			fclose(f);
304c0e032e0STom Rini 		}
305c0e032e0STom Rini 	| propdata DT_LABEL
306c0e032e0STom Rini 		{
307c0e032e0STom Rini 			$$ = data_add_marker($1, LABEL, $2);
308c0e032e0STom Rini 		}
309c0e032e0STom Rini 	;
310c0e032e0STom Rini 
311c0e032e0STom Rini propdataprefix:
312c0e032e0STom Rini 	  /* empty */
313c0e032e0STom Rini 		{
314c0e032e0STom Rini 			$$ = empty_data;
315c0e032e0STom Rini 		}
316c0e032e0STom Rini 	| propdata ','
317c0e032e0STom Rini 		{
318c0e032e0STom Rini 			$$ = $1;
319c0e032e0STom Rini 		}
320c0e032e0STom Rini 	| propdataprefix DT_LABEL
321c0e032e0STom Rini 		{
322c0e032e0STom Rini 			$$ = data_add_marker($1, LABEL, $2);
323c0e032e0STom Rini 		}
324c0e032e0STom Rini 	;
325c0e032e0STom Rini 
326c0e032e0STom Rini arrayprefix:
327c0e032e0STom Rini 	DT_BITS DT_LITERAL '<'
328c0e032e0STom Rini 		{
329c0e032e0STom Rini 			unsigned long long bits;
330c0e032e0STom Rini 
331c0e032e0STom Rini 			bits = $2;
332c0e032e0STom Rini 
333c0e032e0STom Rini 			if ((bits !=  8) && (bits != 16) &&
334c0e032e0STom Rini 			    (bits != 32) && (bits != 64)) {
335c0e032e0STom Rini 				ERROR(&@2, "Array elements must be"
336c0e032e0STom Rini 				      " 8, 16, 32 or 64-bits");
337c0e032e0STom Rini 				bits = 32;
338c0e032e0STom Rini 			}
339c0e032e0STom Rini 
340c0e032e0STom Rini 			$$.data = empty_data;
341c0e032e0STom Rini 			$$.bits = bits;
342c0e032e0STom Rini 		}
343c0e032e0STom Rini 	| '<'
344c0e032e0STom Rini 		{
345c0e032e0STom Rini 			$$.data = empty_data;
346c0e032e0STom Rini 			$$.bits = 32;
347c0e032e0STom Rini 		}
348c0e032e0STom Rini 	| arrayprefix integer_prim
349c0e032e0STom Rini 		{
350c0e032e0STom Rini 			if ($1.bits < 64) {
351c0e032e0STom Rini 				uint64_t mask = (1ULL << $1.bits) - 1;
352c0e032e0STom Rini 				/*
353c0e032e0STom Rini 				 * Bits above mask must either be all zero
354c0e032e0STom Rini 				 * (positive within range of mask) or all one
355c0e032e0STom Rini 				 * (negative and sign-extended). The second
356c0e032e0STom Rini 				 * condition is true if when we set all bits
357c0e032e0STom Rini 				 * within the mask to one (i.e. | in the
358c0e032e0STom Rini 				 * mask), all bits are one.
359c0e032e0STom Rini 				 */
360c0e032e0STom Rini 				if (($2 > mask) && (($2 | mask) != -1ULL))
361c0e032e0STom Rini 					ERROR(&@2, "Value out of range for"
362c0e032e0STom Rini 					      " %d-bit array element", $1.bits);
363c0e032e0STom Rini 			}
364c0e032e0STom Rini 
365c0e032e0STom Rini 			$$.data = data_append_integer($1.data, $2, $1.bits);
366c0e032e0STom Rini 		}
367c0e032e0STom Rini 	| arrayprefix DT_REF
368c0e032e0STom Rini 		{
369c0e032e0STom Rini 			uint64_t val = ~0ULL >> (64 - $1.bits);
370c0e032e0STom Rini 
371c0e032e0STom Rini 			if ($1.bits == 32)
372c0e032e0STom Rini 				$1.data = data_add_marker($1.data,
373c0e032e0STom Rini 							  REF_PHANDLE,
374c0e032e0STom Rini 							  $2);
375c0e032e0STom Rini 			else
376c0e032e0STom Rini 				ERROR(&@2, "References are only allowed in "
377c0e032e0STom Rini 					    "arrays with 32-bit elements.");
378c0e032e0STom Rini 
379c0e032e0STom Rini 			$$.data = data_append_integer($1.data, val, $1.bits);
380c0e032e0STom Rini 		}
381c0e032e0STom Rini 	| arrayprefix DT_LABEL
382c0e032e0STom Rini 		{
383c0e032e0STom Rini 			$$.data = data_add_marker($1.data, LABEL, $2);
384c0e032e0STom Rini 		}
385c0e032e0STom Rini 	;
386c0e032e0STom Rini 
387c0e032e0STom Rini integer_prim:
388c0e032e0STom Rini 	  DT_LITERAL
389c0e032e0STom Rini 	| DT_CHAR_LITERAL
390c0e032e0STom Rini 	| '(' integer_expr ')'
391c0e032e0STom Rini 		{
392c0e032e0STom Rini 			$$ = $2;
393c0e032e0STom Rini 		}
394c0e032e0STom Rini 	;
395c0e032e0STom Rini 
396c0e032e0STom Rini integer_expr:
397c0e032e0STom Rini 	integer_trinary
398c0e032e0STom Rini 	;
399c0e032e0STom Rini 
400c0e032e0STom Rini integer_trinary:
401c0e032e0STom Rini 	  integer_or
402c0e032e0STom Rini 	| integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
403c0e032e0STom Rini 	;
404c0e032e0STom Rini 
405c0e032e0STom Rini integer_or:
406c0e032e0STom Rini 	  integer_and
407c0e032e0STom Rini 	| integer_or DT_OR integer_and { $$ = $1 || $3; }
408c0e032e0STom Rini 	;
409c0e032e0STom Rini 
410c0e032e0STom Rini integer_and:
411c0e032e0STom Rini 	  integer_bitor
412c0e032e0STom Rini 	| integer_and DT_AND integer_bitor { $$ = $1 && $3; }
413c0e032e0STom Rini 	;
414c0e032e0STom Rini 
415c0e032e0STom Rini integer_bitor:
416c0e032e0STom Rini 	  integer_bitxor
417c0e032e0STom Rini 	| integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
418c0e032e0STom Rini 	;
419c0e032e0STom Rini 
420c0e032e0STom Rini integer_bitxor:
421c0e032e0STom Rini 	  integer_bitand
422c0e032e0STom Rini 	| integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
423c0e032e0STom Rini 	;
424c0e032e0STom Rini 
425c0e032e0STom Rini integer_bitand:
426c0e032e0STom Rini 	  integer_eq
427c0e032e0STom Rini 	| integer_bitand '&' integer_eq { $$ = $1 & $3; }
428c0e032e0STom Rini 	;
429c0e032e0STom Rini 
430c0e032e0STom Rini integer_eq:
431c0e032e0STom Rini 	  integer_rela
432c0e032e0STom Rini 	| integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
433c0e032e0STom Rini 	| integer_eq DT_NE integer_rela { $$ = $1 != $3; }
434c0e032e0STom Rini 	;
435c0e032e0STom Rini 
436c0e032e0STom Rini integer_rela:
437c0e032e0STom Rini 	  integer_shift
438c0e032e0STom Rini 	| integer_rela '<' integer_shift { $$ = $1 < $3; }
439c0e032e0STom Rini 	| integer_rela '>' integer_shift { $$ = $1 > $3; }
440c0e032e0STom Rini 	| integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
441c0e032e0STom Rini 	| integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
442c0e032e0STom Rini 	;
443c0e032e0STom Rini 
444c0e032e0STom Rini integer_shift:
445c0e032e0STom Rini 	  integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
446c0e032e0STom Rini 	| integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
447c0e032e0STom Rini 	| integer_add
448c0e032e0STom Rini 	;
449c0e032e0STom Rini 
450c0e032e0STom Rini integer_add:
451c0e032e0STom Rini 	  integer_add '+' integer_mul { $$ = $1 + $3; }
452c0e032e0STom Rini 	| integer_add '-' integer_mul { $$ = $1 - $3; }
453c0e032e0STom Rini 	| integer_mul
454c0e032e0STom Rini 	;
455c0e032e0STom Rini 
456c0e032e0STom Rini integer_mul:
457c0e032e0STom Rini 	  integer_mul '*' integer_unary { $$ = $1 * $3; }
458c0e032e0STom Rini 	| integer_mul '/' integer_unary
459c0e032e0STom Rini 		{
460c0e032e0STom Rini 			if ($3 != 0) {
461c0e032e0STom Rini 				$$ = $1 / $3;
462c0e032e0STom Rini 			} else {
463c0e032e0STom Rini 				ERROR(&@$, "Division by zero");
464c0e032e0STom Rini 				$$ = 0;
465c0e032e0STom Rini 			}
466c0e032e0STom Rini 		}
467c0e032e0STom Rini 	| integer_mul '%' integer_unary
468c0e032e0STom Rini 		{
469c0e032e0STom Rini 			if ($3 != 0) {
470c0e032e0STom Rini 				$$ = $1 % $3;
471c0e032e0STom Rini 			} else {
472c0e032e0STom Rini 				ERROR(&@$, "Division by zero");
473c0e032e0STom Rini 				$$ = 0;
474c0e032e0STom Rini 			}
475c0e032e0STom Rini 		}
476c0e032e0STom Rini 	| integer_unary
477c0e032e0STom Rini 	;
478c0e032e0STom Rini 
479c0e032e0STom Rini integer_unary:
480c0e032e0STom Rini 	  integer_prim
481c0e032e0STom Rini 	| '-' integer_unary { $$ = -$2; }
482c0e032e0STom Rini 	| '~' integer_unary { $$ = ~$2; }
483c0e032e0STom Rini 	| '!' integer_unary { $$ = !$2; }
484c0e032e0STom Rini 	;
485c0e032e0STom Rini 
486c0e032e0STom Rini bytestring:
487c0e032e0STom Rini 	  /* empty */
488c0e032e0STom Rini 		{
489c0e032e0STom Rini 			$$ = empty_data;
490c0e032e0STom Rini 		}
491c0e032e0STom Rini 	| bytestring DT_BYTE
492c0e032e0STom Rini 		{
493c0e032e0STom Rini 			$$ = data_append_byte($1, $2);
494c0e032e0STom Rini 		}
495c0e032e0STom Rini 	| bytestring DT_LABEL
496c0e032e0STom Rini 		{
497c0e032e0STom Rini 			$$ = data_add_marker($1, LABEL, $2);
498c0e032e0STom Rini 		}
499c0e032e0STom Rini 	;
500c0e032e0STom Rini 
501c0e032e0STom Rini subnodes:
502c0e032e0STom Rini 	  /* empty */
503c0e032e0STom Rini 		{
504c0e032e0STom Rini 			$$ = NULL;
505c0e032e0STom Rini 		}
506c0e032e0STom Rini 	| subnode subnodes
507c0e032e0STom Rini 		{
508c0e032e0STom Rini 			$$ = chain_node($1, $2);
509c0e032e0STom Rini 		}
510c0e032e0STom Rini 	| subnode propdef
511c0e032e0STom Rini 		{
512c0e032e0STom Rini 			ERROR(&@2, "Properties must precede subnodes");
513c0e032e0STom Rini 			YYERROR;
514c0e032e0STom Rini 		}
515c0e032e0STom Rini 	;
516c0e032e0STom Rini 
517c0e032e0STom Rini subnode:
518c0e032e0STom Rini 	  DT_PROPNODENAME nodedef
519c0e032e0STom Rini 		{
520c0e032e0STom Rini 			$$ = name_node($2, $1);
521c0e032e0STom Rini 		}
522c0e032e0STom Rini 	| DT_DEL_NODE DT_PROPNODENAME ';'
523c0e032e0STom Rini 		{
524c0e032e0STom Rini 			$$ = name_node(build_node_delete(), $2);
525c0e032e0STom Rini 		}
526c0e032e0STom Rini 	| DT_LABEL subnode
527c0e032e0STom Rini 		{
528c0e032e0STom Rini 			add_label(&$2->labels, $1);
529c0e032e0STom Rini 			$$ = $2;
530c0e032e0STom Rini 		}
531c0e032e0STom Rini 	;
532c0e032e0STom Rini 
533c0e032e0STom Rini %%
534c0e032e0STom Rini 
535c0e032e0STom Rini void yyerror(char const *s)
536c0e032e0STom Rini {
537c0e032e0STom Rini 	ERROR(&yylloc, "%s", s);
538c0e032e0STom Rini }
539