xref: /linux/scripts/dtc/dtc-lexer.l (revision 5a09df20872c1897506351636fdafbcda97ff2c0)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
4  */
5 
6 %option noyywrap nounput noinput never-interactive
7 
8 %x BYTESTRING
9 %x PROPNODENAME
10 %s V1
11 
12 PROPNODECHAR	[a-zA-Z0-9,._+*#?@-]
13 PATHCHAR	({PROPNODECHAR}|[/])
14 LABEL		[a-zA-Z_][a-zA-Z0-9_]*
15 STRING		\"([^\\"]|\\.)*\"
16 CHAR_LITERAL	'([^']|\\')*'
17 WS		[[:space:]]
18 COMMENT		"/*"([^*]|\*+[^*/])*\*+"/"
19 LINECOMMENT	"//".*\n
20 
21 %{
22 #include "dtc.h"
23 #include "srcpos.h"
24 #include "dtc-parser.tab.h"
25 
26 extern bool treesource_error;
27 
28 /* CAUTION: this will stop working if we ever use yyless() or yyunput() */
29 #define	YY_USER_ACTION \
30 	{ \
31 		srcpos_update(&yylloc, yytext, yyleng); \
32 	}
33 
34 /*#define LEXDEBUG	1*/
35 
36 #ifdef LEXDEBUG
37 #define DPRINT(fmt, ...)	fprintf(stderr, fmt, ##__VA_ARGS__)
38 #else
39 #define DPRINT(fmt, ...)	do { } while (0)
40 #endif
41 
42 #define BEGIN_DEFAULT()		DPRINT("<V1>\n"); \
43 				BEGIN(V1); \
44 
45 static void push_input_file(const char *filename);
46 static bool pop_input_file(void);
47 static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
48 
49 %}
50 
51 %%
52 <*>"/include/"{WS}*{STRING} {
53 			char *name = strchr(yytext, '\"') + 1;
54 			yytext[yyleng-1] = '\0';
55 			push_input_file(name);
56 		}
57 
58 <*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)* {
59 			char *line, *fnstart, *fnend;
60 			struct data fn;
61 			/* skip text before line # */
62 			line = yytext;
63 			while (!isdigit((unsigned char)*line))
64 				line++;
65 
66 			/* regexp ensures that first and list "
67 			 * in the whole yytext are those at
68 			 * beginning and end of the filename string */
69 			fnstart = memchr(yytext, '"', yyleng);
70 			for (fnend = yytext + yyleng - 1;
71 			     *fnend != '"'; fnend--)
72 				;
73 			assert(fnstart && fnend && (fnend > fnstart));
74 
75 			fn = data_copy_escape_string(fnstart + 1,
76 						     fnend - fnstart - 1);
77 
78 			/* Don't allow nuls in filenames */
79 			if (memchr(fn.val, '\0', fn.len - 1))
80 				lexical_error("nul in line number directive");
81 
82 			/* -1 since #line is the number of the next line */
83 			srcpos_set_line(xstrdup(fn.val), atoi(line) - 1);
84 			data_free(fn);
85 		}
86 
87 <*><<EOF>>		{
88 			if (!pop_input_file()) {
89 				yyterminate();
90 			}
91 		}
92 
93 <*>{STRING}	{
94 			DPRINT("String: %s\n", yytext);
95 			yylval.data = data_copy_escape_string(yytext+1,
96 					yyleng-2);
97 			return DT_STRING;
98 		}
99 
100 <*>"/dts-v1/"	{
101 			DPRINT("Keyword: /dts-v1/\n");
102 			BEGIN_DEFAULT();
103 			return DT_V1;
104 		}
105 
106 <*>"/plugin/"	{
107 			DPRINT("Keyword: /plugin/\n");
108 			return DT_PLUGIN;
109 		}
110 
111 <*>"/memreserve/"	{
112 			DPRINT("Keyword: /memreserve/\n");
113 			BEGIN_DEFAULT();
114 			return DT_MEMRESERVE;
115 		}
116 
117 <*>"/bits/"	{
118 			DPRINT("Keyword: /bits/\n");
119 			BEGIN_DEFAULT();
120 			return DT_BITS;
121 		}
122 
123 <*>"/delete-property/"	{
124 			DPRINT("Keyword: /delete-property/\n");
125 			DPRINT("<PROPNODENAME>\n");
126 			BEGIN(PROPNODENAME);
127 			return DT_DEL_PROP;
128 		}
129 
130 <*>"/delete-node/"	{
131 			DPRINT("Keyword: /delete-node/\n");
132 			DPRINT("<PROPNODENAME>\n");
133 			BEGIN(PROPNODENAME);
134 			return DT_DEL_NODE;
135 		}
136 
137 <*>"/omit-if-no-ref/"	{
138 			DPRINT("Keyword: /omit-if-no-ref/\n");
139 			DPRINT("<PROPNODENAME>\n");
140 			BEGIN(PROPNODENAME);
141 			return DT_OMIT_NO_REF;
142 		}
143 
144 <*>{LABEL}:	{
145 			DPRINT("Label: %s\n", yytext);
146 			yylval.labelref = xstrdup(yytext);
147 			yylval.labelref[yyleng-1] = '\0';
148 			return DT_LABEL;
149 		}
150 
151 <V1>{LABEL} 	{
152 			/* Missed includes or macro definitions while
153 			 * preprocessing can lead to unexpected identifiers in
154 			 * the input. Report a slightly more informative error
155 			 * in this case */
156 
157 			lexical_error("Unexpected '%s'", yytext);
158 
159 			/* Treat it as a literal which often generates further
160 			 * useful error messages */
161 
162 			yylval.integer = 0;
163 			return DT_LITERAL;
164 		}
165 
166 <V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? {
167 			char *e;
168 			DPRINT("Integer Literal: '%s'\n", yytext);
169 
170 			errno = 0;
171 			yylval.integer = strtoull(yytext, &e, 0);
172 
173 			if (*e && e[strspn(e, "UL")]) {
174 				lexical_error("Bad integer literal '%s'",
175 					      yytext);
176 			}
177 
178 			if (errno == ERANGE)
179 				lexical_error("Integer literal '%s' out of range",
180 					      yytext);
181 			else
182 				/* ERANGE is the only strtoull error triggerable
183 				 *  by strings matching the pattern */
184 				assert(errno == 0);
185 			return DT_LITERAL;
186 		}
187 
188 <*>{CHAR_LITERAL}	{
189 			struct data d;
190 			DPRINT("Character literal: %s\n", yytext);
191 
192 			d = data_copy_escape_string(yytext+1, yyleng-2);
193 			if (d.len == 1) {
194 				lexical_error("Empty character literal");
195 				yylval.integer = 0;
196 			} else {
197 				yylval.integer = (unsigned char)d.val[0];
198 
199 				if (d.len > 2)
200 					lexical_error("Character literal has %d"
201 						      " characters instead of 1",
202 						      d.len - 1);
203 			}
204 
205 			data_free(d);
206 			return DT_CHAR_LITERAL;
207 		}
208 
209 <*>\&{LABEL}	{	/* label reference */
210 			DPRINT("Ref: %s\n", yytext+1);
211 			yylval.labelref = xstrdup(yytext+1);
212 			return DT_LABEL_REF;
213 		}
214 
215 <*>"&{"{PATHCHAR}*\}	{	/* new-style path reference */
216 			yytext[yyleng-1] = '\0';
217 			DPRINT("Ref: %s\n", yytext+2);
218 			yylval.labelref = xstrdup(yytext+2);
219 			return DT_PATH_REF;
220 		}
221 
222 <BYTESTRING>[0-9a-fA-F]{2} {
223 			yylval.byte = strtol(yytext, NULL, 16);
224 			DPRINT("Byte: %02x\n", (int)yylval.byte);
225 			return DT_BYTE;
226 		}
227 
228 <BYTESTRING>"]"	{
229 			DPRINT("/BYTESTRING\n");
230 			BEGIN_DEFAULT();
231 			return ']';
232 		}
233 
234 <PROPNODENAME>\\?{PROPNODECHAR}+ {
235 			DPRINT("PropNodeName: %s\n", yytext);
236 			yylval.propnodename = xstrdup((yytext[0] == '\\') ?
237 							yytext + 1 : yytext);
238 			BEGIN_DEFAULT();
239 			return DT_PROPNODENAME;
240 		}
241 
242 "/incbin/"	{
243 			DPRINT("Binary Include\n");
244 			return DT_INCBIN;
245 		}
246 
247 <*>{WS}+	/* eat whitespace */
248 <*>{COMMENT}+	/* eat C-style comments */
249 <*>{LINECOMMENT}+ /* eat C++-style comments */
250 
251 <*>"<<"		{ return DT_LSHIFT; };
252 <*>">>"		{ return DT_RSHIFT; };
253 <*>"<="		{ return DT_LE; };
254 <*>">="		{ return DT_GE; };
255 <*>"=="		{ return DT_EQ; };
256 <*>"!="		{ return DT_NE; };
257 <*>"&&"		{ return DT_AND; };
258 <*>"||"		{ return DT_OR; };
259 
260 <*>.		{
261 			DPRINT("Char: %c (\\x%02x)\n", yytext[0],
262 				(unsigned)yytext[0]);
263 			if (yytext[0] == '[') {
264 				DPRINT("<BYTESTRING>\n");
265 				BEGIN(BYTESTRING);
266 			}
267 			if ((yytext[0] == '{')
268 			    || (yytext[0] == ';')) {
269 				DPRINT("<PROPNODENAME>\n");
270 				BEGIN(PROPNODENAME);
271 			}
272 			return yytext[0];
273 		}
274 
275 %%
276 
277 static void push_input_file(const char *filename)
278 {
279 	assert(filename);
280 
281 	srcfile_push(filename);
282 
283 	yyin = current_srcfile->f;
284 
285 	yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
286 }
287 
288 
289 static bool pop_input_file(void)
290 {
291 	if (srcfile_pop() == 0)
292 		return false;
293 
294 	yypop_buffer_state();
295 	yyin = current_srcfile->f;
296 
297 	return true;
298 }
299 
300 static void lexical_error(const char *fmt, ...)
301 {
302 	va_list ap;
303 
304 	va_start(ap, fmt);
305 	srcpos_verror(&yylloc, "Lexical error", fmt, ap);
306 	va_end(ap);
307 
308 	treesource_error = true;
309 }
310