1204431Sraj/*
2204431Sraj * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
3204431Sraj *
4204431Sraj *
5204431Sraj * This program is free software; you can redistribute it and/or
6204431Sraj * modify it under the terms of the GNU General Public License as
7204431Sraj * published by the Free Software Foundation; either version 2 of the
8204431Sraj * License, or (at your option) any later version.
9204431Sraj *
10204431Sraj *  This program is distributed in the hope that it will be useful,
11204431Sraj *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12204431Sraj *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13204431Sraj *  General Public License for more details.
14204431Sraj *
15204431Sraj *  You should have received a copy of the GNU General Public License
16204431Sraj *  along with this program; if not, write to the Free Software
17204431Sraj *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18204431Sraj *                                                                   USA
19204431Sraj */
20204431Sraj
21238742Simp%option noyywrap nounput noinput never-interactive
22204431Sraj
23204431Sraj%x BYTESTRING
24204431Sraj%x PROPNODENAME
25204431Sraj%s V1
26204431Sraj
27204431SrajPROPNODECHAR	[a-zA-Z0-9,._+*#?@-]
28204431SrajPATHCHAR	({PROPNODECHAR}|[/])
29204431SrajLABEL		[a-zA-Z_][a-zA-Z0-9_]*
30204431SrajSTRING		\"([^\\"]|\\.)*\"
31238742SimpCHAR_LITERAL	'([^']|\\')*'
32204431SrajWS		[[:space:]]
33204431SrajCOMMENT		"/*"([^*]|\*+[^*/])*\*+"/"
34204431SrajLINECOMMENT	"//".*\n
35204431Sraj
36204431Sraj%{
37204431Sraj#include "dtc.h"
38204431Sraj#include "srcpos.h"
39204431Sraj#include "dtc-parser.tab.h"
40204431Sraj
41238742Simp#define MAX_INCLUDE_NESTING 100
42238742SimpYY_BUFFER_STATE include_stack[MAX_INCLUDE_NESTING];
43238742Simpint include_stack_pointer = 0;
44238742Simp
45366135Skevansextern YYLTYPE yylloc;
46261215Simpextern bool treesource_error;
47204489Sraj
48238742Simp/* CAUTION: this will stop working if we ever use yyless() or yyunput() */
49204433Sraj#define	YY_USER_ACTION \
50204433Sraj	{ \
51238742Simp		srcpos_update(&yylloc, yytext, yyleng); \
52204433Sraj	}
53204431Sraj
54204431Sraj/*#define LEXDEBUG	1*/
55204431Sraj
56204431Sraj#ifdef LEXDEBUG
57204431Sraj#define DPRINT(fmt, ...)	fprintf(stderr, fmt, ##__VA_ARGS__)
58204431Sraj#else
59204431Sraj#define DPRINT(fmt, ...)	do { } while (0)
60204431Sraj#endif
61204431Sraj
62204433Srajstatic int dts_version = 1;
63204431Sraj
64204433Sraj#define BEGIN_DEFAULT()		DPRINT("<V1>\n"); \
65204431Sraj				BEGIN(V1); \
66204431Sraj
67204431Srajstatic void push_input_file(const char *filename);
68261215Simpstatic bool pop_input_file(void);
69318102Sgonzo#ifdef __GNUC__
70318102Sgonzostatic void lexical_error(const char *fmt, ...)
71318102Sgonzo	__attribute__((format (printf, 1, 2)));
72318102Sgonzo#else
73261215Simpstatic void lexical_error(const char *fmt, ...);
74318102Sgonzo#endif
75318102Sgonzo
76204431Sraj%}
77204431Sraj
78204431Sraj%%
79204431Sraj<*>"/include/"{WS}*{STRING} {
80204431Sraj			char *name = strchr(yytext, '\"') + 1;
81204431Sraj			yytext[yyleng-1] = '\0';
82204431Sraj			push_input_file(name);
83204431Sraj		}
84204431Sraj
85261215Simp<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? {
86318102Sgonzo			char *line, *fnstart, *fnend;
87318102Sgonzo			struct data fn;
88261215Simp			/* skip text before line # */
89261215Simp			line = yytext;
90261215Simp			while (!isdigit((unsigned char)*line))
91261215Simp				line++;
92318102Sgonzo
93318102Sgonzo			/* regexp ensures that first and list "
94318102Sgonzo			 * in the whole yytext are those at
95318102Sgonzo			 * beginning and end of the filename string */
96318102Sgonzo			fnstart = memchr(yytext, '"', yyleng);
97318102Sgonzo			for (fnend = yytext + yyleng - 1;
98318102Sgonzo			     *fnend != '"'; fnend--)
99318102Sgonzo				;
100318102Sgonzo			assert(fnstart && fnend && (fnend > fnstart));
101318102Sgonzo
102318102Sgonzo			fn = data_copy_escape_string(fnstart + 1,
103318102Sgonzo						     fnend - fnstart - 1);
104318102Sgonzo
105318102Sgonzo			/* Don't allow nuls in filenames */
106318102Sgonzo			if (memchr(fn.val, '\0', fn.len - 1))
107318102Sgonzo				lexical_error("nul in line number directive");
108318102Sgonzo
109261215Simp			/* -1 since #line is the number of the next line */
110318102Sgonzo			srcpos_set_line(xstrdup(fn.val), atoi(line) - 1);
111318102Sgonzo			data_free(fn);
112261215Simp		}
113261215Simp
114204431Sraj<*><<EOF>>		{
115204431Sraj			if (!pop_input_file()) {
116204431Sraj				yyterminate();
117204431Sraj			}
118204431Sraj		}
119204431Sraj
120204431Sraj<*>{STRING}	{
121204431Sraj			DPRINT("String: %s\n", yytext);
122204431Sraj			yylval.data = data_copy_escape_string(yytext+1,
123204431Sraj					yyleng-2);
124204431Sraj			return DT_STRING;
125204431Sraj		}
126204431Sraj
127204431Sraj<*>"/dts-v1/"	{
128204431Sraj			DPRINT("Keyword: /dts-v1/\n");
129204431Sraj			dts_version = 1;
130204431Sraj			BEGIN_DEFAULT();
131204431Sraj			return DT_V1;
132204431Sraj		}
133204431Sraj
134318102Sgonzo<*>"/plugin/"	{
135318102Sgonzo			DPRINT("Keyword: /plugin/\n");
136318102Sgonzo			return DT_PLUGIN;
137318102Sgonzo		}
138318102Sgonzo
139204431Sraj<*>"/memreserve/"	{
140204431Sraj			DPRINT("Keyword: /memreserve/\n");
141204431Sraj			BEGIN_DEFAULT();
142204431Sraj			return DT_MEMRESERVE;
143204431Sraj		}
144204431Sraj
145238742Simp<*>"/bits/"	{
146238742Simp			DPRINT("Keyword: /bits/\n");
147238742Simp			BEGIN_DEFAULT();
148238742Simp			return DT_BITS;
149238742Simp		}
150238742Simp
151261215Simp<*>"/delete-property/"	{
152261215Simp			DPRINT("Keyword: /delete-property/\n");
153261215Simp			DPRINT("<PROPNODENAME>\n");
154261215Simp			BEGIN(PROPNODENAME);
155261215Simp			return DT_DEL_PROP;
156261215Simp		}
157261215Simp
158261215Simp<*>"/delete-node/"	{
159261215Simp			DPRINT("Keyword: /delete-node/\n");
160261215Simp			DPRINT("<PROPNODENAME>\n");
161261215Simp			BEGIN(PROPNODENAME);
162261215Simp			return DT_DEL_NODE;
163261215Simp		}
164261215Simp
165204431Sraj<*>{LABEL}:	{
166204431Sraj			DPRINT("Label: %s\n", yytext);
167204433Sraj			yylval.labelref = xstrdup(yytext);
168204431Sraj			yylval.labelref[yyleng-1] = '\0';
169204431Sraj			return DT_LABEL;
170204431Sraj		}
171204431Sraj
172238742Simp<V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? {
173261215Simp			char *e;
174261215Simp			DPRINT("Integer Literal: '%s'\n", yytext);
175261215Simp
176261215Simp			errno = 0;
177261215Simp			yylval.integer = strtoull(yytext, &e, 0);
178261215Simp
179318102Sgonzo			if (*e && e[strspn(e, "UL")]) {
180318102Sgonzo				lexical_error("Bad integer literal '%s'",
181318102Sgonzo					      yytext);
182318102Sgonzo			}
183261215Simp
184261215Simp			if (errno == ERANGE)
185261215Simp				lexical_error("Integer literal '%s' out of range",
186261215Simp					      yytext);
187261215Simp			else
188261215Simp				/* ERANGE is the only strtoull error triggerable
189261215Simp				 *  by strings matching the pattern */
190261215Simp				assert(errno == 0);
191204431Sraj			return DT_LITERAL;
192204431Sraj		}
193204431Sraj
194238742Simp<*>{CHAR_LITERAL}	{
195261215Simp			struct data d;
196261215Simp			DPRINT("Character literal: %s\n", yytext);
197261215Simp
198261215Simp			d = data_copy_escape_string(yytext+1, yyleng-2);
199261215Simp			if (d.len == 1) {
200261215Simp				lexical_error("Empty character literal");
201261215Simp				yylval.integer = 0;
202318102Sgonzo			} else {
203318102Sgonzo				yylval.integer = (unsigned char)d.val[0];
204318102Sgonzo
205318102Sgonzo				if (d.len > 2)
206318102Sgonzo					lexical_error("Character literal has %d"
207318102Sgonzo						      " characters instead of 1",
208318102Sgonzo						      d.len - 1);
209261215Simp			}
210261215Simp
211318102Sgonzo			data_free(d);
212238742Simp			return DT_CHAR_LITERAL;
213238742Simp		}
214238742Simp
215238742Simp<*>\&{LABEL}	{	/* label reference */
216204431Sraj			DPRINT("Ref: %s\n", yytext+1);
217204433Sraj			yylval.labelref = xstrdup(yytext+1);
218204431Sraj			return DT_REF;
219204431Sraj		}
220204431Sraj
221318102Sgonzo<*>"&{/"{PATHCHAR}*\}	{	/* new-style path reference */
222204431Sraj			yytext[yyleng-1] = '\0';
223204431Sraj			DPRINT("Ref: %s\n", yytext+2);
224204433Sraj			yylval.labelref = xstrdup(yytext+2);
225204431Sraj			return DT_REF;
226204431Sraj		}
227204431Sraj
228204431Sraj<BYTESTRING>[0-9a-fA-F]{2} {
229204431Sraj			yylval.byte = strtol(yytext, NULL, 16);
230204431Sraj			DPRINT("Byte: %02x\n", (int)yylval.byte);
231204431Sraj			return DT_BYTE;
232204431Sraj		}
233204431Sraj
234204431Sraj<BYTESTRING>"]"	{
235204431Sraj			DPRINT("/BYTESTRING\n");
236204431Sraj			BEGIN_DEFAULT();
237204431Sraj			return ']';
238204431Sraj		}
239204431Sraj
240261215Simp<PROPNODENAME>\\?{PROPNODECHAR}+ {
241204431Sraj			DPRINT("PropNodeName: %s\n", yytext);
242261215Simp			yylval.propnodename = xstrdup((yytext[0] == '\\') ?
243261215Simp							yytext + 1 : yytext);
244204431Sraj			BEGIN_DEFAULT();
245204431Sraj			return DT_PROPNODENAME;
246204431Sraj		}
247204431Sraj
248204431Sraj"/incbin/"	{
249204431Sraj			DPRINT("Binary Include\n");
250204431Sraj			return DT_INCBIN;
251204431Sraj		}
252204431Sraj
253204431Sraj<*>{WS}+	/* eat whitespace */
254204431Sraj<*>{COMMENT}+	/* eat C-style comments */
255204431Sraj<*>{LINECOMMENT}+ /* eat C++-style comments */
256204431Sraj
257238742Simp<*>"<<"		{ return DT_LSHIFT; };
258238742Simp<*>">>"		{ return DT_RSHIFT; };
259238742Simp<*>"<="		{ return DT_LE; };
260238742Simp<*>">="		{ return DT_GE; };
261238742Simp<*>"=="		{ return DT_EQ; };
262238742Simp<*>"!="		{ return DT_NE; };
263238742Simp<*>"&&"		{ return DT_AND; };
264238742Simp<*>"||"		{ return DT_OR; };
265238742Simp
266204431Sraj<*>.		{
267204431Sraj			DPRINT("Char: %c (\\x%02x)\n", yytext[0],
268204431Sraj				(unsigned)yytext[0]);
269204431Sraj			if (yytext[0] == '[') {
270204431Sraj				DPRINT("<BYTESTRING>\n");
271204431Sraj				BEGIN(BYTESTRING);
272204431Sraj			}
273204431Sraj			if ((yytext[0] == '{')
274204431Sraj			    || (yytext[0] == ';')) {
275204431Sraj				DPRINT("<PROPNODENAME>\n");
276204431Sraj				BEGIN(PROPNODENAME);
277204431Sraj			}
278204431Sraj			return yytext[0];
279204431Sraj		}
280204431Sraj
281204431Sraj%%
282204431Sraj
283204431Srajstatic void push_input_file(const char *filename)
284204431Sraj{
285204431Sraj	assert(filename);
286204431Sraj
287239998Sandrew	assert(include_stack_pointer < MAX_INCLUDE_NESTING);
288204431Sraj
289238742Simp	srcfile_push(filename);
290204431Sraj
291238742Simp	yyin = current_srcfile->f;
292204431Sraj
293238742Simp	include_stack[include_stack_pointer++] = YY_CURRENT_BUFFER;
294204431Sraj
295204431Sraj	yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
296204431Sraj}
297204431Sraj
298204431Sraj
299261215Simpstatic bool pop_input_file(void)
300204431Sraj{
301238742Simp	if (srcfile_pop() == 0)
302261215Simp		return false;
303204431Sraj
304238742Simp	assert(include_stack_pointer > 0);
305204431Sraj
306238742Simp	yy_delete_buffer( YY_CURRENT_BUFFER );
307204431Sraj
308238742Simp	yy_switch_to_buffer( include_stack[--include_stack_pointer] );
309204431Sraj
310238742Simp	yyin = current_srcfile->f;
311204431Sraj
312261215Simp	return true;
313204431Sraj}
314261215Simp
315261215Simpstatic void lexical_error(const char *fmt, ...)
316261215Simp{
317261215Simp	va_list ap;
318261215Simp
319261215Simp	va_start(ap, fmt);
320261215Simp	srcpos_verror(&yylloc, "Lexical error", fmt, ap);
321261215Simp	va_end(ap);
322261215Simp
323261215Simp	treesource_error = true;
324261215Simp}
325