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