xref: /freebsd/usr.bin/dtc/input_buffer.cc (revision 4dfbc03d6492d9fccb781700cc17d58111dff456)
1af0dd31fSDavid Chisnall /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
4af0dd31fSDavid Chisnall  * Copyright (c) 2013 David Chisnall
5af0dd31fSDavid Chisnall  * All rights reserved.
6af0dd31fSDavid Chisnall  *
7af0dd31fSDavid Chisnall  * This software was developed by SRI International and the University of
8af0dd31fSDavid Chisnall  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
9af0dd31fSDavid Chisnall  * ("CTSRD"), as part of the DARPA CRASH research programme.
10af0dd31fSDavid Chisnall  *
11af0dd31fSDavid Chisnall  * Redistribution and use in source and binary forms, with or without
12af0dd31fSDavid Chisnall  * modification, are permitted provided that the following conditions
13af0dd31fSDavid Chisnall  * are met:
14af0dd31fSDavid Chisnall  * 1. Redistributions of source code must retain the above copyright
15af0dd31fSDavid Chisnall  *    notice, this list of conditions and the following disclaimer.
16af0dd31fSDavid Chisnall  * 2. Redistributions in binary form must reproduce the above copyright
17af0dd31fSDavid Chisnall  *    notice, this list of conditions and the following disclaimer in the
18af0dd31fSDavid Chisnall  *    documentation and/or other materials provided with the distribution.
19af0dd31fSDavid Chisnall  *
20af0dd31fSDavid Chisnall  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21af0dd31fSDavid Chisnall  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22af0dd31fSDavid Chisnall  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23af0dd31fSDavid Chisnall  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24af0dd31fSDavid Chisnall  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25af0dd31fSDavid Chisnall  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26af0dd31fSDavid Chisnall  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27af0dd31fSDavid Chisnall  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28af0dd31fSDavid Chisnall  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29af0dd31fSDavid Chisnall  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30af0dd31fSDavid Chisnall  * SUCH DAMAGE.
31af0dd31fSDavid Chisnall  */
32af0dd31fSDavid Chisnall 
33af0dd31fSDavid Chisnall #include "input_buffer.hh"
34009f7b42SDavid Chisnall #include <ctype.h>
3523cba92bSDimitry Andric #include <errno.h>
36af0dd31fSDavid Chisnall #include <stdint.h>
37009f7b42SDavid Chisnall #include <stdio.h>
38009f7b42SDavid Chisnall #include <stdlib.h>
39009f7b42SDavid Chisnall #include <string.h>
40c64a3eafSDavid Chisnall #include <functional>
41c64a3eafSDavid Chisnall #ifndef NDEBUG
42c64a3eafSDavid Chisnall #include <iostream>
43c64a3eafSDavid Chisnall #endif
441c44d2bfSJohn Baldwin #include <limits>
45009f7b42SDavid Chisnall 
46af0dd31fSDavid Chisnall 
47af0dd31fSDavid Chisnall #include <sys/stat.h>
48af0dd31fSDavid Chisnall #include <sys/mman.h>
49af0dd31fSDavid Chisnall #include <assert.h>
50bbe31b70SEd Maste #include <fcntl.h>
51bbe31b70SEd Maste #include <unistd.h>
52af0dd31fSDavid Chisnall 
53eaef137cSUlrich Spörlein #ifndef MAP_PREFAULT_READ
54eaef137cSUlrich Spörlein #define MAP_PREFAULT_READ 0
55eaef137cSUlrich Spörlein #endif
56eaef137cSUlrich Spörlein 
57bbe31b70SEd Maste using std::string;
58bbe31b70SEd Maste 
59bbe31b70SEd Maste namespace
60bbe31b70SEd Maste {
61bbe31b70SEd Maste /**
62bbe31b70SEd Maste  * Subclass of input_buffer that mmap()s a file and owns the resulting memory.
63bbe31b70SEd Maste  * When this object is destroyed, the memory is unmapped.
64bbe31b70SEd Maste  */
65bbe31b70SEd Maste struct mmap_input_buffer : public dtc::input_buffer
66bbe31b70SEd Maste {
67bbe31b70SEd Maste 	string fn;
filename__anon3998a5d80111::mmap_input_buffer68bbe31b70SEd Maste 	const string &filename() const override
69bbe31b70SEd Maste 	{
70bbe31b70SEd Maste 		return fn;
71bbe31b70SEd Maste 	}
72bbe31b70SEd Maste 	/**
73bbe31b70SEd Maste 	 * Constructs a new buffer from the file passed in as a file
74bbe31b70SEd Maste 	 * descriptor.
75bbe31b70SEd Maste 	 */
76bbe31b70SEd Maste 	mmap_input_buffer(int fd, string &&filename);
77bbe31b70SEd Maste 	/**
78bbe31b70SEd Maste 	 * Unmaps the buffer, if one exists.
79bbe31b70SEd Maste 	 */
80bbe31b70SEd Maste 	virtual ~mmap_input_buffer();
81bbe31b70SEd Maste };
82bbe31b70SEd Maste /**
83bbe31b70SEd Maste  * Input buffer read from standard input.  This is used for reading device tree
84bbe31b70SEd Maste  * blobs and source from standard input.  It reads the entire input into
85bbe31b70SEd Maste  * malloc'd memory, so will be very slow for large inputs.  DTS and DTB files
86bbe31b70SEd Maste  * are very rarely more than 10KB though, so this is probably not a problem.
87bbe31b70SEd Maste  */
88bbe31b70SEd Maste struct stream_input_buffer : public dtc::input_buffer
89bbe31b70SEd Maste {
filename__anon3998a5d80111::stream_input_buffer90bbe31b70SEd Maste 	const string &filename() const override
91bbe31b70SEd Maste 	{
92bbe31b70SEd Maste 		static string n = "<standard input>";
93bbe31b70SEd Maste 		return n;
94bbe31b70SEd Maste 	}
95bbe31b70SEd Maste 	/**
96bbe31b70SEd Maste 	 * The buffer that will store the data read from the standard input.
97bbe31b70SEd Maste 	 */
98bbe31b70SEd Maste 	std::vector<char> b;
99bbe31b70SEd Maste 	/**
100bbe31b70SEd Maste 	 * Constructs a new buffer from the standard input.
101bbe31b70SEd Maste 	 */
102bbe31b70SEd Maste 	stream_input_buffer();
103bbe31b70SEd Maste };
104bbe31b70SEd Maste 
mmap_input_buffer(int fd,string && filename)10521d5d37bSEd Maste mmap_input_buffer::mmap_input_buffer(int fd, string &&filename)
106bbe31b70SEd Maste 	: input_buffer(0, 0), fn(filename)
107bbe31b70SEd Maste {
108bbe31b70SEd Maste 	struct stat sb;
109bbe31b70SEd Maste 	if (fstat(fd, &sb))
110bbe31b70SEd Maste 	{
111bbe31b70SEd Maste 		perror("Failed to stat file");
112bbe31b70SEd Maste 	}
113bbe31b70SEd Maste 	size = sb.st_size;
114bbe31b70SEd Maste 	buffer = (const char*)mmap(0, size, PROT_READ, MAP_PRIVATE |
115bbe31b70SEd Maste 			MAP_PREFAULT_READ, fd, 0);
116bbe31b70SEd Maste 	if (buffer == MAP_FAILED)
117bbe31b70SEd Maste 	{
118bbe31b70SEd Maste 		perror("Failed to mmap file");
119bbe31b70SEd Maste 		exit(EXIT_FAILURE);
120bbe31b70SEd Maste 	}
121bbe31b70SEd Maste }
122bbe31b70SEd Maste 
~mmap_input_buffer()123bbe31b70SEd Maste mmap_input_buffer::~mmap_input_buffer()
124bbe31b70SEd Maste {
125bbe31b70SEd Maste 	if (buffer != 0)
126bbe31b70SEd Maste 	{
127d37eb02eSKyle Evans 		munmap(const_cast<char*>(buffer), size);
128bbe31b70SEd Maste 	}
129bbe31b70SEd Maste }
130bbe31b70SEd Maste 
stream_input_buffer()131bbe31b70SEd Maste stream_input_buffer::stream_input_buffer() : input_buffer(0, 0)
132bbe31b70SEd Maste {
133bbe31b70SEd Maste 	int c;
134bbe31b70SEd Maste 	while ((c = fgetc(stdin)) != EOF)
135bbe31b70SEd Maste 	{
136bbe31b70SEd Maste 		b.push_back(c);
137bbe31b70SEd Maste 	}
138bbe31b70SEd Maste 	buffer = b.data();
139bbe31b70SEd Maste 	size = b.size();
140bbe31b70SEd Maste }
141bbe31b70SEd Maste 
142bbe31b70SEd Maste } // Anonymous namespace
143bbe31b70SEd Maste 
144bbe31b70SEd Maste 
145af0dd31fSDavid Chisnall namespace dtc
146af0dd31fSDavid Chisnall {
147bbe31b70SEd Maste 
148af0dd31fSDavid Chisnall void
skip_to(char c)149bbe31b70SEd Maste input_buffer::skip_to(char c)
150af0dd31fSDavid Chisnall {
151bbe31b70SEd Maste 	while ((cursor < size) && (buffer[cursor] != c))
152bbe31b70SEd Maste 	{
153bbe31b70SEd Maste 		cursor++;
154bbe31b70SEd Maste 	}
155bbe31b70SEd Maste }
156bbe31b70SEd Maste 
157bbe31b70SEd Maste void
skip_to(char c)158bbe31b70SEd Maste text_input_buffer::skip_to(char c)
159bbe31b70SEd Maste {
160bbe31b70SEd Maste 	while (!finished() && (*(*this) != c))
161bbe31b70SEd Maste 	{
162bbe31b70SEd Maste 		++(*this);
163bbe31b70SEd Maste 	}
164bbe31b70SEd Maste }
165bbe31b70SEd Maste 
166bbe31b70SEd Maste void
skip_spaces()167bbe31b70SEd Maste text_input_buffer::skip_spaces()
168bbe31b70SEd Maste {
169bbe31b70SEd Maste 	if (finished()) { return; }
170bbe31b70SEd Maste 	char c = *(*this);
171bbe31b70SEd Maste 	bool last_nl = false;
172af0dd31fSDavid Chisnall 	while ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\f')
173af0dd31fSDavid Chisnall 	       || (c == '\v') || (c == '\r'))
174af0dd31fSDavid Chisnall 	{
175bbe31b70SEd Maste 		last_nl = ((c == '\n') || (c == '\r'));
176bbe31b70SEd Maste 		++(*this);
177bbe31b70SEd Maste 		if (finished())
178af0dd31fSDavid Chisnall 		{
179af0dd31fSDavid Chisnall 			c = '\0';
180af0dd31fSDavid Chisnall 		}
181af0dd31fSDavid Chisnall 		else
182af0dd31fSDavid Chisnall 		{
183bbe31b70SEd Maste 			c = *(*this);
184af0dd31fSDavid Chisnall 		}
185af0dd31fSDavid Chisnall 	}
186bbe31b70SEd Maste 	// Skip C preprocessor leftovers
187bbe31b70SEd Maste 	if ((c == '#') && ((cursor == 0) || last_nl))
188bbe31b70SEd Maste 	{
189bbe31b70SEd Maste 		skip_to('\n');
190bbe31b70SEd Maste 		skip_spaces();
191bbe31b70SEd Maste 	}
192bbe31b70SEd Maste 	if (consume("/include/"))
193bbe31b70SEd Maste 	{
194bbe31b70SEd Maste 		handle_include();
195bbe31b70SEd Maste 		skip_spaces();
196bbe31b70SEd Maste 	}
197bbe31b70SEd Maste }
198bbe31b70SEd Maste 
199bbe31b70SEd Maste void
handle_include()200bbe31b70SEd Maste text_input_buffer::handle_include()
201bbe31b70SEd Maste {
202bbe31b70SEd Maste 	bool reallyInclude = true;
203bbe31b70SEd Maste 	if (consume("if "))
204bbe31b70SEd Maste 	{
205bbe31b70SEd Maste 		next_token();
206bbe31b70SEd Maste 		string name = parse_property_name();
207ca84c67cSKyle Evans 		if (defines.count(name) == 0)
208bbe31b70SEd Maste 		{
209ca84c67cSKyle Evans 			reallyInclude = false;
210bbe31b70SEd Maste 		}
211bbe31b70SEd Maste 		consume('/');
212bbe31b70SEd Maste 	}
213bbe31b70SEd Maste 	next_token();
214bbe31b70SEd Maste 	if (!consume('"'))
215bbe31b70SEd Maste 	{
216bbe31b70SEd Maste 		parse_error("Expected quoted filename");
217bbe31b70SEd Maste 		return;
218bbe31b70SEd Maste 	}
21921d5d37bSEd Maste 	auto loc = location();
220bbe31b70SEd Maste 	string file = parse_to('"');
221bbe31b70SEd Maste 	consume('"');
222bbe31b70SEd Maste 	if (!reallyInclude)
223bbe31b70SEd Maste 	{
224bbe31b70SEd Maste 		return;
225bbe31b70SEd Maste 	}
226bbe31b70SEd Maste 	string include_file = dir + '/' + file;
227bbe31b70SEd Maste 	auto include_buffer = input_buffer::buffer_for_file(include_file, false);
228bbe31b70SEd Maste 	if (include_buffer == 0)
229bbe31b70SEd Maste 	{
230bbe31b70SEd Maste 		for (auto i : include_paths)
231bbe31b70SEd Maste 		{
232bbe31b70SEd Maste 			include_file = i + '/' + file;
233bbe31b70SEd Maste 			include_buffer = input_buffer::buffer_for_file(include_file, false);
234bbe31b70SEd Maste 			if (include_buffer != 0)
235bbe31b70SEd Maste 			{
236bbe31b70SEd Maste 				break;
237bbe31b70SEd Maste 			}
238bbe31b70SEd Maste 		}
239bbe31b70SEd Maste 	}
240bbe31b70SEd Maste 	if (depfile)
241bbe31b70SEd Maste 	{
242bbe31b70SEd Maste 		putc(' ', depfile);
243bbe31b70SEd Maste 		fputs(include_file.c_str(), depfile);
244bbe31b70SEd Maste 	}
245bbe31b70SEd Maste 	if (!include_buffer)
246bbe31b70SEd Maste 	{
24721d5d37bSEd Maste 		loc.report_error("Unable to locate input file");
248bbe31b70SEd Maste 		return;
249bbe31b70SEd Maste 	}
250bbe31b70SEd Maste 	input_stack.push(std::move(include_buffer));
251af0dd31fSDavid Chisnall }
252af0dd31fSDavid Chisnall 
read_binary_file(const std::string & filename,byte_buffer & b)253ca84c67cSKyle Evans bool text_input_buffer::read_binary_file(const std::string &filename, byte_buffer &b)
254ca84c67cSKyle Evans {
255ca84c67cSKyle Evans 	bool try_include_paths = true;
256ca84c67cSKyle Evans 	string include_file;
257ca84c67cSKyle Evans 	if (filename[0] == '/')
258ca84c67cSKyle Evans 	{
259ca84c67cSKyle Evans 		include_file = filename;
260ca84c67cSKyle Evans 		// Don't try include paths if we're given an absolute path.
261ca84c67cSKyle Evans 		// Failing is better so that we don't accidentally do the wrong thing,
262ca84c67cSKyle Evans 		// but make it seem like everything is alright.
263ca84c67cSKyle Evans 		try_include_paths = false;
264ca84c67cSKyle Evans 	}
265ca84c67cSKyle Evans 	else
266ca84c67cSKyle Evans 	{
267ca84c67cSKyle Evans 		include_file = dir + '/' + filename;
268ca84c67cSKyle Evans 	}
269ca84c67cSKyle Evans 	auto include_buffer = input_buffer::buffer_for_file(include_file, false);
270ca84c67cSKyle Evans 	if (include_buffer == 0 && try_include_paths)
271ca84c67cSKyle Evans 	{
272ca84c67cSKyle Evans 		for (auto i : include_paths)
273ca84c67cSKyle Evans 		{
274ca84c67cSKyle Evans 			include_file = i + '/' + filename;
275ca84c67cSKyle Evans 			include_buffer = input_buffer::buffer_for_file(include_file, false);
276ca84c67cSKyle Evans 			if (include_buffer != 0)
277ca84c67cSKyle Evans 			{
278ca84c67cSKyle Evans 				break;
279ca84c67cSKyle Evans 			}
280ca84c67cSKyle Evans 		}
281ca84c67cSKyle Evans 	}
282ca84c67cSKyle Evans 	if (!include_buffer)
283ca84c67cSKyle Evans 	{
284ca84c67cSKyle Evans 		return false;
285ca84c67cSKyle Evans 	}
286ca84c67cSKyle Evans 	if (depfile)
287ca84c67cSKyle Evans 	{
288ca84c67cSKyle Evans 		putc(' ', depfile);
289ca84c67cSKyle Evans 		fputs(include_file.c_str(), depfile);
290ca84c67cSKyle Evans 	}
291ca84c67cSKyle Evans 	b.insert(b.begin(), include_buffer->begin(), include_buffer->end());
292ca84c67cSKyle Evans 	return true;
293ca84c67cSKyle Evans }
294ca84c67cSKyle Evans 
295af0dd31fSDavid Chisnall input_buffer
buffer_from_offset(int offset,int s)296af0dd31fSDavid Chisnall input_buffer::buffer_from_offset(int offset, int s)
297af0dd31fSDavid Chisnall {
298bbe31b70SEd Maste 	if (offset < 0)
299bbe31b70SEd Maste 	{
300bbe31b70SEd Maste 		return input_buffer();
301bbe31b70SEd Maste 	}
302af0dd31fSDavid Chisnall 	if (s == 0)
303af0dd31fSDavid Chisnall 	{
304af0dd31fSDavid Chisnall 		s = size - offset;
305af0dd31fSDavid Chisnall 	}
306af0dd31fSDavid Chisnall 	if (offset > size)
307af0dd31fSDavid Chisnall 	{
308af0dd31fSDavid Chisnall 		return input_buffer();
309af0dd31fSDavid Chisnall 	}
310af0dd31fSDavid Chisnall 	if (s > (size-offset))
311af0dd31fSDavid Chisnall 	{
312af0dd31fSDavid Chisnall 		return input_buffer();
313af0dd31fSDavid Chisnall 	}
314af0dd31fSDavid Chisnall 	return input_buffer(&buffer[offset], s);
315af0dd31fSDavid Chisnall }
316af0dd31fSDavid Chisnall 
317af0dd31fSDavid Chisnall bool
consume(const char * str)318af0dd31fSDavid Chisnall input_buffer::consume(const char *str)
319af0dd31fSDavid Chisnall {
320af0dd31fSDavid Chisnall 	int len = strlen(str);
321af0dd31fSDavid Chisnall 	if (len > size - cursor)
322af0dd31fSDavid Chisnall 	{
323af0dd31fSDavid Chisnall 		return false;
324af0dd31fSDavid Chisnall 	}
325af0dd31fSDavid Chisnall 	else
326af0dd31fSDavid Chisnall 	{
327af0dd31fSDavid Chisnall 		for (int i=0 ; i<len ; ++i)
328af0dd31fSDavid Chisnall 		{
329bbe31b70SEd Maste 			if (str[i] != (*this)[i])
330af0dd31fSDavid Chisnall 			{
331af0dd31fSDavid Chisnall 				return false;
332af0dd31fSDavid Chisnall 			}
333af0dd31fSDavid Chisnall 		}
334af0dd31fSDavid Chisnall 		cursor += len;
335af0dd31fSDavid Chisnall 		return true;
336af0dd31fSDavid Chisnall 	}
337af0dd31fSDavid Chisnall 	return false;
338af0dd31fSDavid Chisnall }
339af0dd31fSDavid Chisnall 
340af0dd31fSDavid Chisnall bool
consume_char_literal(unsigned long long & outInt)341*4dfbc03dSJose Luis Duran input_buffer::consume_char_literal(unsigned long long &outInt)
342*4dfbc03dSJose Luis Duran {
343*4dfbc03dSJose Luis Duran 	outInt = (unsigned char)((*this)[0]);
344*4dfbc03dSJose Luis Duran 	cursor++;
345*4dfbc03dSJose Luis Duran 
346*4dfbc03dSJose Luis Duran 	if(outInt != '\\')
347*4dfbc03dSJose Luis Duran 	{
348*4dfbc03dSJose Luis Duran 		return true;
349*4dfbc03dSJose Luis Duran 	}
350*4dfbc03dSJose Luis Duran 	else if(cursor >= size)
351*4dfbc03dSJose Luis Duran 	{
352*4dfbc03dSJose Luis Duran 		return false;
353*4dfbc03dSJose Luis Duran 	}
354*4dfbc03dSJose Luis Duran 
355*4dfbc03dSJose Luis Duran 	outInt = (unsigned char)((*this)[0]);
356*4dfbc03dSJose Luis Duran 	cursor++;
357*4dfbc03dSJose Luis Duran 
358*4dfbc03dSJose Luis Duran 	switch (outInt) {
359*4dfbc03dSJose Luis Duran 		default:
360*4dfbc03dSJose Luis Duran 			return false;
361*4dfbc03dSJose Luis Duran 		case 'n':
362*4dfbc03dSJose Luis Duran 			outInt = (unsigned char)'\n';
363*4dfbc03dSJose Luis Duran 			break;
364*4dfbc03dSJose Luis Duran 		case 'r':
365*4dfbc03dSJose Luis Duran 			outInt = (unsigned char)'\r';
366*4dfbc03dSJose Luis Duran 			break;
367*4dfbc03dSJose Luis Duran 		case 't':
368*4dfbc03dSJose Luis Duran 			outInt = (unsigned char)'\t';
369*4dfbc03dSJose Luis Duran 			break;
370*4dfbc03dSJose Luis Duran 		case '0':
371*4dfbc03dSJose Luis Duran 			outInt = 0;
372*4dfbc03dSJose Luis Duran 			break;
373*4dfbc03dSJose Luis Duran 		case '\'':
374*4dfbc03dSJose Luis Duran 		case '\\':
375*4dfbc03dSJose Luis Duran 			break;
376*4dfbc03dSJose Luis Duran 	}
377*4dfbc03dSJose Luis Duran 
378*4dfbc03dSJose Luis Duran 	return true;
379*4dfbc03dSJose Luis Duran }
380*4dfbc03dSJose Luis Duran 
381*4dfbc03dSJose Luis Duran bool
consume_integer(unsigned long long & outInt)382a0706eb4SDavid Chisnall input_buffer::consume_integer(unsigned long long &outInt)
383af0dd31fSDavid Chisnall {
384af0dd31fSDavid Chisnall 	// The first character must be a digit.  Hex and octal strings
385af0dd31fSDavid Chisnall 	// are prefixed by 0 and 0x, respectively.
386af0dd31fSDavid Chisnall 	if (!isdigit((*this)[0]))
387af0dd31fSDavid Chisnall 	{
388af0dd31fSDavid Chisnall 		return false;
389af0dd31fSDavid Chisnall 	}
390bbe31b70SEd Maste 	char *end= const_cast<char*>(&buffer[size]);
39189f5bc46SJessica Clarke 	errno = 0;
392a0706eb4SDavid Chisnall 	outInt = strtoull(&buffer[cursor], &end, 0);
39389f5bc46SJessica Clarke 	if (end == &buffer[cursor] ||
39489f5bc46SJessica Clarke 	    (outInt == std::numeric_limits<unsigned long long>::max() &&
39589f5bc46SJessica Clarke 	     errno == ERANGE))
396af0dd31fSDavid Chisnall 	{
397af0dd31fSDavid Chisnall 		return false;
398af0dd31fSDavid Chisnall 	}
399af0dd31fSDavid Chisnall 	cursor = end - buffer;
400af0dd31fSDavid Chisnall 	return true;
401af0dd31fSDavid Chisnall }
402af0dd31fSDavid Chisnall 
403c64a3eafSDavid Chisnall namespace {
404c64a3eafSDavid Chisnall 
405c64a3eafSDavid Chisnall /**
406c64a3eafSDavid Chisnall  * Convenience typedef for the type that we use for all values.
407c64a3eafSDavid Chisnall  */
408c64a3eafSDavid Chisnall typedef unsigned long long valty;
409c64a3eafSDavid Chisnall 
410c64a3eafSDavid Chisnall /**
411c64a3eafSDavid Chisnall  * Expression tree currently being parsed.
412c64a3eafSDavid Chisnall  */
413c64a3eafSDavid Chisnall struct expression
414c64a3eafSDavid Chisnall {
415bbe31b70SEd Maste 	typedef text_input_buffer::source_location source_location;
416bbe31b70SEd Maste 	/**
417bbe31b70SEd Maste 	 * The type that is returned when computing the result.  The boolean value
418bbe31b70SEd Maste 	 * indicates whether this is a valid expression.
419bbe31b70SEd Maste 	 *
420bbe31b70SEd Maste 	 * FIXME: Once we can use C++17, this should be `std::optional`.
421bbe31b70SEd Maste 	 */
422bbe31b70SEd Maste 	typedef std::pair<valty, bool> result;
423c64a3eafSDavid Chisnall 	/**
424c64a3eafSDavid Chisnall 	 * Evaluate this node, taking into account operator precedence.
425c64a3eafSDavid Chisnall 	 */
426bbe31b70SEd Maste 	virtual result operator()() = 0;
427c64a3eafSDavid Chisnall 	/**
428c64a3eafSDavid Chisnall 	 * Returns the precedence of this node.  Lower values indicate higher
429c64a3eafSDavid Chisnall 	 * precedence.
430c64a3eafSDavid Chisnall 	 */
431c64a3eafSDavid Chisnall 	virtual int precedence() = 0;
432bbe31b70SEd Maste 	/**
433bbe31b70SEd Maste 	 * Constructs an expression, storing the location where it was created.
434bbe31b70SEd Maste 	 */
expressiondtc::__anon3998a5d80211::expression435bbe31b70SEd Maste 	expression(source_location l) : loc(l) {}
~expressiondtc::__anon3998a5d80211::expression436c64a3eafSDavid Chisnall 	virtual ~expression() {}
437c64a3eafSDavid Chisnall #ifndef NDEBUG
438c64a3eafSDavid Chisnall 	/**
439c64a3eafSDavid Chisnall 	 * Dumps this expression to `std::cerr`, appending a newline if `nl` is
440c64a3eafSDavid Chisnall 	 * `true`.
441c64a3eafSDavid Chisnall 	 */
dumpdtc::__anon3998a5d80211::expression442c64a3eafSDavid Chisnall 	void dump(bool nl=false)
443c64a3eafSDavid Chisnall 	{
444bbe31b70SEd Maste 		void *ptr = this;
445bbe31b70SEd Maste 		if (ptr == nullptr)
446c64a3eafSDavid Chisnall 		{
447c64a3eafSDavid Chisnall 			std::cerr << "{nullptr}\n";
448c64a3eafSDavid Chisnall 			return;
449c64a3eafSDavid Chisnall 		}
450c64a3eafSDavid Chisnall 		dump_impl();
451c64a3eafSDavid Chisnall 		if (nl)
452c64a3eafSDavid Chisnall 		{
453c64a3eafSDavid Chisnall 			std::cerr << '\n';
454c64a3eafSDavid Chisnall 		}
455c64a3eafSDavid Chisnall 	}
456c64a3eafSDavid Chisnall 	private:
457c64a3eafSDavid Chisnall 	/**
458c64a3eafSDavid Chisnall 	 * Method that sublcasses override to implement the behaviour of `dump()`.
459c64a3eafSDavid Chisnall 	 */
460c64a3eafSDavid Chisnall 	virtual void dump_impl() = 0;
461c64a3eafSDavid Chisnall #endif
462bbe31b70SEd Maste 	protected:
463bbe31b70SEd Maste 	source_location loc;
464c64a3eafSDavid Chisnall };
465c64a3eafSDavid Chisnall 
466c64a3eafSDavid Chisnall /**
467c64a3eafSDavid Chisnall  * Expression wrapping a single integer.  Leaf nodes in the expression tree.
468c64a3eafSDavid Chisnall  */
469c64a3eafSDavid Chisnall class terminal_expr : public expression
470c64a3eafSDavid Chisnall {
471c64a3eafSDavid Chisnall 	/**
472c64a3eafSDavid Chisnall 	 * The value that this wraps.
473c64a3eafSDavid Chisnall 	 */
474c64a3eafSDavid Chisnall 	valty val;
475c64a3eafSDavid Chisnall 	/**
476c64a3eafSDavid Chisnall 	 * Evaluate.  Trivially returns the value that this class wraps.
477c64a3eafSDavid Chisnall 	 */
operator ()()478bbe31b70SEd Maste 	result operator()() override
479c64a3eafSDavid Chisnall 	{
480bbe31b70SEd Maste 		return {val, true};
481c64a3eafSDavid Chisnall 	}
precedence()482c64a3eafSDavid Chisnall 	int precedence() override
483c64a3eafSDavid Chisnall 	{
484c64a3eafSDavid Chisnall 		return 0;
485c64a3eafSDavid Chisnall 	}
486c64a3eafSDavid Chisnall 	public:
487c64a3eafSDavid Chisnall 	/**
488c64a3eafSDavid Chisnall 	 * Constructor.
489c64a3eafSDavid Chisnall 	 */
terminal_expr(source_location l,valty v)490bbe31b70SEd Maste 	terminal_expr(source_location l, valty v) : expression(l), val(v) {}
491c64a3eafSDavid Chisnall #ifndef NDEBUG
dump_impl()492c64a3eafSDavid Chisnall 	void dump_impl() override { std::cerr << val; }
493c64a3eafSDavid Chisnall #endif
494c64a3eafSDavid Chisnall };
495c64a3eafSDavid Chisnall 
496c64a3eafSDavid Chisnall /**
497c64a3eafSDavid Chisnall  * Parenthetical expression.  Exists to make the contents opaque.
498c64a3eafSDavid Chisnall  */
499c64a3eafSDavid Chisnall struct paren_expression : public expression
500c64a3eafSDavid Chisnall {
501c64a3eafSDavid Chisnall 	/**
502c64a3eafSDavid Chisnall 	 * The expression within the parentheses.
503c64a3eafSDavid Chisnall 	 */
504c64a3eafSDavid Chisnall 	expression_ptr subexpr;
505c64a3eafSDavid Chisnall 	/**
506c64a3eafSDavid Chisnall 	 * Constructor.  Takes the child expression as the only argument.
507c64a3eafSDavid Chisnall 	 */
paren_expressiondtc::__anon3998a5d80211::paren_expression508bbe31b70SEd Maste 	paren_expression(source_location l, expression_ptr p) : expression(l),
509bbe31b70SEd Maste 	subexpr(std::move(p)) {}
precedencedtc::__anon3998a5d80211::paren_expression510c64a3eafSDavid Chisnall 	int precedence() override
511c64a3eafSDavid Chisnall 	{
512c64a3eafSDavid Chisnall 		return 0;
513c64a3eafSDavid Chisnall 	}
514c64a3eafSDavid Chisnall 	/**
515c64a3eafSDavid Chisnall 	 * Evaluate - just forwards to the underlying expression.
516c64a3eafSDavid Chisnall 	 */
operator ()dtc::__anon3998a5d80211::paren_expression517bbe31b70SEd Maste 	result operator()() override
518c64a3eafSDavid Chisnall 	{
519c64a3eafSDavid Chisnall 		return (*subexpr)();
520c64a3eafSDavid Chisnall 	}
521c64a3eafSDavid Chisnall #ifndef NDEBUG
dump_impldtc::__anon3998a5d80211::paren_expression522c64a3eafSDavid Chisnall 	void dump_impl() override
523c64a3eafSDavid Chisnall 	{
524c64a3eafSDavid Chisnall 		std::cerr << " (";
525c64a3eafSDavid Chisnall 		subexpr->dump();
526c64a3eafSDavid Chisnall 		std::cerr << ") ";
527c64a3eafSDavid Chisnall 	}
528c64a3eafSDavid Chisnall #endif
529c64a3eafSDavid Chisnall };
530c64a3eafSDavid Chisnall 
531c64a3eafSDavid Chisnall /**
532c64a3eafSDavid Chisnall  * Template class for unary operators.  The `OpChar` template parameter is
533c64a3eafSDavid Chisnall  * solely for debugging and makes it easy to print the expression.  The `Op`
534c64a3eafSDavid Chisnall  * template parameter is a function object that implements the operator that
535c64a3eafSDavid Chisnall  * this class provides.  Most of these are provided by the `<functional>`
536c64a3eafSDavid Chisnall  * header.
537c64a3eafSDavid Chisnall  */
538c64a3eafSDavid Chisnall template<char OpChar, class Op>
539c64a3eafSDavid Chisnall class unary_operator : public expression
540c64a3eafSDavid Chisnall {
541c64a3eafSDavid Chisnall 	/**
542c64a3eafSDavid Chisnall 	 * The subexpression for this unary operator.
543c64a3eafSDavid Chisnall 	 */
544c64a3eafSDavid Chisnall 	expression_ptr subexpr;
operator ()()545bbe31b70SEd Maste 	result operator()() override
546c64a3eafSDavid Chisnall 	{
547c64a3eafSDavid Chisnall 		Op op;
548bbe31b70SEd Maste 		result s = (*subexpr)();
549bbe31b70SEd Maste 		if (!s.second)
550bbe31b70SEd Maste 		{
551bbe31b70SEd Maste 			return s;
552bbe31b70SEd Maste 		}
553bbe31b70SEd Maste 		return {op(s.first), true};
554c64a3eafSDavid Chisnall 	}
555c64a3eafSDavid Chisnall 	/**
556c64a3eafSDavid Chisnall 	 * All unary operators have the same precedence.  They are all evaluated
557c64a3eafSDavid Chisnall 	 * before binary expressions, but after parentheses.
558c64a3eafSDavid Chisnall 	 */
precedence()559c64a3eafSDavid Chisnall 	int precedence() override
560c64a3eafSDavid Chisnall 	{
561c64a3eafSDavid Chisnall 		return 3;
562c64a3eafSDavid Chisnall 	}
563c64a3eafSDavid Chisnall 	public:
unary_operator(source_location l,expression_ptr p)564bbe31b70SEd Maste 	unary_operator(source_location l, expression_ptr p) :
565bbe31b70SEd Maste 		expression(l), subexpr(std::move(p)) {}
566c64a3eafSDavid Chisnall #ifndef NDEBUG
dump_impl()567c64a3eafSDavid Chisnall 	void dump_impl() override
568c64a3eafSDavid Chisnall 	{
569c64a3eafSDavid Chisnall 		std::cerr << OpChar;
570c64a3eafSDavid Chisnall 		subexpr->dump();
571c64a3eafSDavid Chisnall 	}
572c64a3eafSDavid Chisnall #endif
573c64a3eafSDavid Chisnall };
574c64a3eafSDavid Chisnall 
575c64a3eafSDavid Chisnall /**
576c64a3eafSDavid Chisnall  * Abstract base class for binary operators.  Allows the tree to be modified
577c64a3eafSDavid Chisnall  * without knowing what the operations actually are.
578c64a3eafSDavid Chisnall  */
579c64a3eafSDavid Chisnall struct binary_operator_base : public expression
580c64a3eafSDavid Chisnall {
581bbe31b70SEd Maste 	using expression::expression;
582c64a3eafSDavid Chisnall 	/**
583c64a3eafSDavid Chisnall 	 * The left side of the expression.
584c64a3eafSDavid Chisnall 	 */
585c64a3eafSDavid Chisnall 	expression_ptr lhs;
586c64a3eafSDavid Chisnall 	/**
587c64a3eafSDavid Chisnall 	 * The right side of the expression.
588c64a3eafSDavid Chisnall 	 */
589c64a3eafSDavid Chisnall 	expression_ptr rhs;
590c64a3eafSDavid Chisnall 	/**
591c64a3eafSDavid Chisnall 	 * Insert a node somewhere down the path of left children, until it would
592c64a3eafSDavid Chisnall 	 * be preempting something that should execute first.
593c64a3eafSDavid Chisnall 	 */
insert_leftdtc::__anon3998a5d80211::binary_operator_base594c64a3eafSDavid Chisnall 	void insert_left(binary_operator_base *new_left)
595c64a3eafSDavid Chisnall 	{
596c64a3eafSDavid Chisnall 		if (lhs->precedence() < new_left->precedence())
597c64a3eafSDavid Chisnall 		{
598c64a3eafSDavid Chisnall 			new_left->rhs = std::move(lhs);
599c64a3eafSDavid Chisnall 			lhs.reset(new_left);
600c64a3eafSDavid Chisnall 		}
601c64a3eafSDavid Chisnall 		else
602c64a3eafSDavid Chisnall 		{
603c64a3eafSDavid Chisnall 			static_cast<binary_operator_base*>(lhs.get())->insert_left(new_left);
604c64a3eafSDavid Chisnall 		}
605c64a3eafSDavid Chisnall 	}
606c64a3eafSDavid Chisnall };
607c64a3eafSDavid Chisnall 
608c64a3eafSDavid Chisnall /**
609c64a3eafSDavid Chisnall  * Template class for binary operators.  The precedence and the operation are
610c64a3eafSDavid Chisnall  * provided as template parameters.
611c64a3eafSDavid Chisnall  */
612c64a3eafSDavid Chisnall template<int Precedence, class Op>
613c64a3eafSDavid Chisnall struct binary_operator : public binary_operator_base
614c64a3eafSDavid Chisnall {
operator ()dtc::__anon3998a5d80211::binary_operator615bbe31b70SEd Maste 	result operator()() override
616c64a3eafSDavid Chisnall 	{
617c64a3eafSDavid Chisnall 		Op op;
618bbe31b70SEd Maste 		result l = (*lhs)();
619bbe31b70SEd Maste 		result r = (*rhs)();
620bbe31b70SEd Maste 		if (!(l.second && r.second))
621bbe31b70SEd Maste 		{
622bbe31b70SEd Maste 			return {0, false};
623bbe31b70SEd Maste 		}
624bbe31b70SEd Maste 		return {op(l.first, r.first), true};
625c64a3eafSDavid Chisnall 	}
precedencedtc::__anon3998a5d80211::binary_operator626c64a3eafSDavid Chisnall 	int precedence() override
627c64a3eafSDavid Chisnall 	{
628c64a3eafSDavid Chisnall 		return Precedence;
629c64a3eafSDavid Chisnall 	}
630c64a3eafSDavid Chisnall #ifdef NDEBUG
631c64a3eafSDavid Chisnall 	/**
632c64a3eafSDavid Chisnall 	 * Constructor.  Takes the name of the operator as an argument, for
633c64a3eafSDavid Chisnall 	 * debugging.  Only stores it in debug mode.
634c64a3eafSDavid Chisnall 	 */
binary_operatordtc::__anon3998a5d80211::binary_operator63523cba92bSDimitry Andric 	binary_operator(source_location l, const char *) :
63623cba92bSDimitry Andric 		binary_operator_base(l) {}
637c64a3eafSDavid Chisnall #else
638c64a3eafSDavid Chisnall 	const char *opName;
binary_operatordtc::__anon3998a5d80211::binary_operator639bbe31b70SEd Maste 	binary_operator(source_location l, const char *o) :
640bbe31b70SEd Maste 		binary_operator_base(l), opName(o) {}
dump_impldtc::__anon3998a5d80211::binary_operator641c64a3eafSDavid Chisnall 	void dump_impl() override
642c64a3eafSDavid Chisnall 	{
643c64a3eafSDavid Chisnall 		lhs->dump();
644c64a3eafSDavid Chisnall 		std::cerr << opName;
645c64a3eafSDavid Chisnall 		rhs->dump();
646c64a3eafSDavid Chisnall 	}
647c64a3eafSDavid Chisnall #endif
648c64a3eafSDavid Chisnall };
649c64a3eafSDavid Chisnall 
650c64a3eafSDavid Chisnall /**
651c64a3eafSDavid Chisnall  * Ternary conditional operators (`cond ? true : false`) are a special case -
652c64a3eafSDavid Chisnall  * there are no other ternary operators.
653c64a3eafSDavid Chisnall  */
654c64a3eafSDavid Chisnall class ternary_conditional_operator : public expression
655c64a3eafSDavid Chisnall {
656c64a3eafSDavid Chisnall 	/**
657c64a3eafSDavid Chisnall 	 * The condition for the clause.
658c64a3eafSDavid Chisnall 	 */
659c64a3eafSDavid Chisnall 	expression_ptr cond;
660c64a3eafSDavid Chisnall 	/**
661c64a3eafSDavid Chisnall 	 * The expression that this evaluates to if the condition is true.
662c64a3eafSDavid Chisnall 	 */
663c64a3eafSDavid Chisnall 	expression_ptr lhs;
664c64a3eafSDavid Chisnall 	/**
665c64a3eafSDavid Chisnall 	 * The expression that this evaluates to if the condition is false.
666c64a3eafSDavid Chisnall 	 */
667c64a3eafSDavid Chisnall 	expression_ptr rhs;
operator ()()668bbe31b70SEd Maste 	result operator()() override
669c64a3eafSDavid Chisnall 	{
670bbe31b70SEd Maste 		result c = (*cond)();
671bbe31b70SEd Maste 		result l = (*lhs)();
672bbe31b70SEd Maste 		result r = (*rhs)();
673bbe31b70SEd Maste 		if (!(l.second && r.second && c.second))
674bbe31b70SEd Maste 		{
675bbe31b70SEd Maste 			return {0, false};
676bbe31b70SEd Maste 		}
677bbe31b70SEd Maste 		return c.first ? l : r;
678c64a3eafSDavid Chisnall 	}
precedence()679c64a3eafSDavid Chisnall 	int precedence() override
680c64a3eafSDavid Chisnall 	{
681c64a3eafSDavid Chisnall 		// The actual precedence of a ternary conditional operator is 15, but
682c64a3eafSDavid Chisnall 		// its associativity is the opposite way around to the other operators,
683c64a3eafSDavid Chisnall 		// so we fudge it slightly.
684c64a3eafSDavid Chisnall 		return 3;
685c64a3eafSDavid Chisnall 	}
686c64a3eafSDavid Chisnall #ifndef NDEBUG
dump_impl()687c64a3eafSDavid Chisnall 	void dump_impl() override
688c64a3eafSDavid Chisnall 	{
689c64a3eafSDavid Chisnall 		cond->dump();
690c64a3eafSDavid Chisnall 		std::cerr << " ? ";
691c64a3eafSDavid Chisnall 		lhs->dump();
692c64a3eafSDavid Chisnall 		std::cerr << " : ";
693c64a3eafSDavid Chisnall 		rhs->dump();
694c64a3eafSDavid Chisnall 	}
695c64a3eafSDavid Chisnall #endif
696c64a3eafSDavid Chisnall 	public:
ternary_conditional_operator(source_location sl,expression_ptr c,expression_ptr l,expression_ptr r)697bbe31b70SEd Maste 	ternary_conditional_operator(source_location sl,
698bbe31b70SEd Maste 	                             expression_ptr c,
699c64a3eafSDavid Chisnall 	                             expression_ptr l,
700c64a3eafSDavid Chisnall 	                             expression_ptr r) :
701bbe31b70SEd Maste 		expression(sl), cond(std::move(c)), lhs(std::move(l)),
702bbe31b70SEd Maste 		rhs(std::move(r)) {}
703c64a3eafSDavid Chisnall };
704c64a3eafSDavid Chisnall 
705c64a3eafSDavid Chisnall template<typename T>
706c64a3eafSDavid Chisnall struct lshift
707c64a3eafSDavid Chisnall {
operator ()dtc::__anon3998a5d80211::lshift708c64a3eafSDavid Chisnall 	constexpr T operator()(const T &lhs, const T &rhs) const
709c64a3eafSDavid Chisnall 	{
710c64a3eafSDavid Chisnall 		return lhs << rhs;
711c64a3eafSDavid Chisnall 	}
712c64a3eafSDavid Chisnall };
713c64a3eafSDavid Chisnall template<typename T>
714c64a3eafSDavid Chisnall struct rshift
715c64a3eafSDavid Chisnall {
operator ()dtc::__anon3998a5d80211::rshift716c64a3eafSDavid Chisnall 	constexpr T operator()(const T &lhs, const T &rhs) const
717c64a3eafSDavid Chisnall 	{
718c64a3eafSDavid Chisnall 		return lhs >> rhs;
719c64a3eafSDavid Chisnall 	}
720c64a3eafSDavid Chisnall };
721c64a3eafSDavid Chisnall template<typename T>
722c64a3eafSDavid Chisnall struct unary_plus
723c64a3eafSDavid Chisnall {
operator ()dtc::__anon3998a5d80211::unary_plus724c64a3eafSDavid Chisnall 	constexpr T operator()(const T &val) const
725c64a3eafSDavid Chisnall 	{
726c64a3eafSDavid Chisnall 		return +val;
727c64a3eafSDavid Chisnall 	}
728c64a3eafSDavid Chisnall };
729c64a3eafSDavid Chisnall // TODO: Replace with std::bit_not once we can guarantee C++14 as a baseline.
730c64a3eafSDavid Chisnall template<typename T>
731c64a3eafSDavid Chisnall struct bit_not
732c64a3eafSDavid Chisnall {
operator ()dtc::__anon3998a5d80211::bit_not733c64a3eafSDavid Chisnall 	constexpr T operator()(const T &val) const
734c64a3eafSDavid Chisnall 	{
735c64a3eafSDavid Chisnall 		return ~val;
736c64a3eafSDavid Chisnall 	}
737c64a3eafSDavid Chisnall };
738c64a3eafSDavid Chisnall 
739bbe31b70SEd Maste template<typename T>
740bbe31b70SEd Maste struct divmod : public binary_operator<5, T>
741bbe31b70SEd Maste {
742bbe31b70SEd Maste 	using binary_operator<5, T>::binary_operator;
7438b4debd2SEmmanuel Vadot 	using typename binary_operator_base::result;
operator ()dtc::__anon3998a5d80211::divmod744bbe31b70SEd Maste 	result operator()() override
745bbe31b70SEd Maste 	{
746bbe31b70SEd Maste 		result r = (*binary_operator_base::rhs)();
747bbe31b70SEd Maste 		if (r.second && (r.first == 0))
748bbe31b70SEd Maste 		{
749bbe31b70SEd Maste 			expression::loc.report_error("Division by zero");
750bbe31b70SEd Maste 			return {0, false};
751bbe31b70SEd Maste 		}
752bbe31b70SEd Maste 		return binary_operator<5, T>::operator()();
753bbe31b70SEd Maste 	}
754bbe31b70SEd Maste };
755bbe31b70SEd Maste 
756c64a3eafSDavid Chisnall } // anonymous namespace
757c64a3eafSDavid Chisnall 
758c64a3eafSDavid Chisnall 
parse_binary_expression(expression_ptr lhs)759bbe31b70SEd Maste expression_ptr text_input_buffer::parse_binary_expression(expression_ptr lhs)
760c64a3eafSDavid Chisnall {
761c64a3eafSDavid Chisnall 	next_token();
762c64a3eafSDavid Chisnall 	binary_operator_base *expr = nullptr;
763bbe31b70SEd Maste 	char op = *(*this);
764bbe31b70SEd Maste 	source_location l = location();
765c64a3eafSDavid Chisnall 	switch (op)
766c64a3eafSDavid Chisnall 	{
767c64a3eafSDavid Chisnall 		default:
768c64a3eafSDavid Chisnall 			return lhs;
769c64a3eafSDavid Chisnall 		case '+':
770bbe31b70SEd Maste 			expr = new binary_operator<6, std::plus<valty>>(l, "+");
771c64a3eafSDavid Chisnall 			break;
772c64a3eafSDavid Chisnall 		case '-':
773bbe31b70SEd Maste 			expr = new binary_operator<6, std::minus<valty>>(l, "-");
774c64a3eafSDavid Chisnall 			break;
775c64a3eafSDavid Chisnall 		case '%':
776bbe31b70SEd Maste 			expr = new divmod<std::modulus<valty>>(l, "/");
777c64a3eafSDavid Chisnall 			break;
778c64a3eafSDavid Chisnall 		case '*':
779bbe31b70SEd Maste 			expr = new binary_operator<5, std::multiplies<valty>>(l, "*");
780c64a3eafSDavid Chisnall 			break;
781c64a3eafSDavid Chisnall 		case '/':
782bbe31b70SEd Maste 			expr = new divmod<std::divides<valty>>(l, "/");
783c64a3eafSDavid Chisnall 			break;
784c64a3eafSDavid Chisnall 		case '<':
785bbe31b70SEd Maste 			switch (peek())
786c64a3eafSDavid Chisnall 			{
787c64a3eafSDavid Chisnall 				default:
788c64a3eafSDavid Chisnall 					parse_error("Invalid operator");
789c64a3eafSDavid Chisnall 					return nullptr;
790c64a3eafSDavid Chisnall 				case ' ':
791c64a3eafSDavid Chisnall 				case '(':
792c64a3eafSDavid Chisnall 				case '0'...'9':
793bbe31b70SEd Maste 					expr = new binary_operator<8, std::less<valty>>(l, "<");
794c64a3eafSDavid Chisnall 					break;
795c64a3eafSDavid Chisnall 				case '=':
796bbe31b70SEd Maste 					++(*this);
797bbe31b70SEd Maste 					expr = new binary_operator<8, std::less_equal<valty>>(l, "<=");
798c64a3eafSDavid Chisnall 					break;
799c64a3eafSDavid Chisnall 				case '<':
800bbe31b70SEd Maste 					++(*this);
801bbe31b70SEd Maste 					expr = new binary_operator<7, lshift<valty>>(l, "<<");
802c64a3eafSDavid Chisnall 					break;
803c64a3eafSDavid Chisnall 			}
804c64a3eafSDavid Chisnall 			break;
805c64a3eafSDavid Chisnall 		case '>':
806bbe31b70SEd Maste 			switch (peek())
807c64a3eafSDavid Chisnall 			{
808c64a3eafSDavid Chisnall 				default:
809c64a3eafSDavid Chisnall 					parse_error("Invalid operator");
810c64a3eafSDavid Chisnall 					return nullptr;
811c64a3eafSDavid Chisnall 				case '(':
812c64a3eafSDavid Chisnall 				case ' ':
813c64a3eafSDavid Chisnall 				case '0'...'9':
814bbe31b70SEd Maste 					expr = new binary_operator<8, std::greater<valty>>(l, ">");
815c64a3eafSDavid Chisnall 					break;
816c64a3eafSDavid Chisnall 				case '=':
817bbe31b70SEd Maste 					++(*this);
818bbe31b70SEd Maste 					expr = new binary_operator<8, std::greater_equal<valty>>(l, ">=");
819c64a3eafSDavid Chisnall 					break;
820c64a3eafSDavid Chisnall 				case '>':
821bbe31b70SEd Maste 					++(*this);
822bbe31b70SEd Maste 					expr = new binary_operator<7, rshift<valty>>(l, ">>");
823c64a3eafSDavid Chisnall 					break;
824c64a3eafSDavid Chisnall 					return lhs;
825c64a3eafSDavid Chisnall 			}
826c64a3eafSDavid Chisnall 			break;
827c64a3eafSDavid Chisnall 		case '=':
828bbe31b70SEd Maste 			if (peek() != '=')
829c64a3eafSDavid Chisnall 			{
830c64a3eafSDavid Chisnall 				parse_error("Invalid operator");
831c64a3eafSDavid Chisnall 				return nullptr;
832c64a3eafSDavid Chisnall 			}
833bbe31b70SEd Maste 			expr = new binary_operator<9, std::equal_to<valty>>(l, "==");
834c64a3eafSDavid Chisnall 			break;
835c64a3eafSDavid Chisnall 		case '!':
836bbe31b70SEd Maste 			if (peek() != '=')
837c64a3eafSDavid Chisnall 			{
838c64a3eafSDavid Chisnall 				parse_error("Invalid operator");
839c64a3eafSDavid Chisnall 				return nullptr;
840c64a3eafSDavid Chisnall 			}
841c64a3eafSDavid Chisnall 			cursor++;
842bbe31b70SEd Maste 			expr = new binary_operator<9, std::not_equal_to<valty>>(l, "!=");
843c64a3eafSDavid Chisnall 			break;
844c64a3eafSDavid Chisnall 		case '&':
845bbe31b70SEd Maste 			if (peek() == '&')
846c64a3eafSDavid Chisnall 			{
847bbe31b70SEd Maste 				expr = new binary_operator<13, std::logical_and<valty>>(l, "&&");
848c64a3eafSDavid Chisnall 			}
849c64a3eafSDavid Chisnall 			else
850c64a3eafSDavid Chisnall 			{
851bbe31b70SEd Maste 				expr = new binary_operator<10, std::bit_and<valty>>(l, "&");
852c64a3eafSDavid Chisnall 			}
853c64a3eafSDavid Chisnall 			break;
854c64a3eafSDavid Chisnall 		case '|':
855bbe31b70SEd Maste 			if (peek() == '|')
856c64a3eafSDavid Chisnall 			{
857bbe31b70SEd Maste 				expr = new binary_operator<12, std::logical_or<valty>>(l, "||");
858c64a3eafSDavid Chisnall 			}
859c64a3eafSDavid Chisnall 			else
860c64a3eafSDavid Chisnall 			{
861bbe31b70SEd Maste 				expr = new binary_operator<14, std::bit_or<valty>>(l, "|");
862c64a3eafSDavid Chisnall 			}
863c64a3eafSDavid Chisnall 			break;
864c64a3eafSDavid Chisnall 		case '?':
865c64a3eafSDavid Chisnall 		{
866c64a3eafSDavid Chisnall 			consume('?');
867c64a3eafSDavid Chisnall 			expression_ptr true_case = parse_expression();
868c64a3eafSDavid Chisnall 			next_token();
869c64a3eafSDavid Chisnall 			if (!true_case || !consume(':'))
870c64a3eafSDavid Chisnall 			{
871c64a3eafSDavid Chisnall 				parse_error("Expected : in ternary conditional operator");
872c64a3eafSDavid Chisnall 				return nullptr;
873c64a3eafSDavid Chisnall 			}
874c64a3eafSDavid Chisnall 			expression_ptr false_case = parse_expression();
875c64a3eafSDavid Chisnall 			if (!false_case)
876c64a3eafSDavid Chisnall 			{
877c64a3eafSDavid Chisnall 				parse_error("Expected false condition for ternary operator");
878c64a3eafSDavid Chisnall 				return nullptr;
879c64a3eafSDavid Chisnall 			}
880bbe31b70SEd Maste 			return expression_ptr(new ternary_conditional_operator(l, std::move(lhs),
881c64a3eafSDavid Chisnall 						std::move(true_case), std::move(false_case)));
882c64a3eafSDavid Chisnall 		}
883c64a3eafSDavid Chisnall 	}
884bbe31b70SEd Maste 	++(*this);
885c64a3eafSDavid Chisnall 	next_token();
886c64a3eafSDavid Chisnall 	expression_ptr e(expr);
887c64a3eafSDavid Chisnall 	expression_ptr rhs(parse_expression());
888c64a3eafSDavid Chisnall 	if (!rhs)
889c64a3eafSDavid Chisnall 	{
890c64a3eafSDavid Chisnall 		return nullptr;
891c64a3eafSDavid Chisnall 	}
892c64a3eafSDavid Chisnall 	expr->lhs = std::move(lhs);
893c64a3eafSDavid Chisnall 	if (rhs->precedence() < expr->precedence())
894c64a3eafSDavid Chisnall 	{
895c64a3eafSDavid Chisnall 		expr->rhs = std::move(rhs);
896c64a3eafSDavid Chisnall 	}
897c64a3eafSDavid Chisnall 	else
898c64a3eafSDavid Chisnall 	{
899c64a3eafSDavid Chisnall 		// If we're a normal left-to-right expression, then we need to insert
900c64a3eafSDavid Chisnall 		// this as the far-left child node of the rhs expression
901c64a3eafSDavid Chisnall 		binary_operator_base *rhs_op =
902c64a3eafSDavid Chisnall 			static_cast<binary_operator_base*>(rhs.get());
903c64a3eafSDavid Chisnall 		rhs_op->insert_left(expr);
904c64a3eafSDavid Chisnall 		e.release();
905c64a3eafSDavid Chisnall 		return rhs;
906c64a3eafSDavid Chisnall 	}
907c64a3eafSDavid Chisnall 	return e;
908c64a3eafSDavid Chisnall }
909c64a3eafSDavid Chisnall 
parse_expression(bool stopAtParen)910bbe31b70SEd Maste expression_ptr text_input_buffer::parse_expression(bool stopAtParen)
911c64a3eafSDavid Chisnall {
912c64a3eafSDavid Chisnall 	next_token();
913c64a3eafSDavid Chisnall 	unsigned long long leftVal;
914c64a3eafSDavid Chisnall 	expression_ptr lhs;
915bbe31b70SEd Maste 	source_location l = location();
916bbe31b70SEd Maste 	switch (*(*this))
917c64a3eafSDavid Chisnall 	{
918*4dfbc03dSJose Luis Duran 		case '\'':
919*4dfbc03dSJose Luis Duran 			consume('\'');
920*4dfbc03dSJose Luis Duran 			if(!consume_char_literal(leftVal))
921*4dfbc03dSJose Luis Duran 			{
922*4dfbc03dSJose Luis Duran 				return nullptr;
923*4dfbc03dSJose Luis Duran 			}
924*4dfbc03dSJose Luis Duran 			if (!consume('\''))
925*4dfbc03dSJose Luis Duran 			{
926*4dfbc03dSJose Luis Duran 				return nullptr;
927*4dfbc03dSJose Luis Duran 			}
928*4dfbc03dSJose Luis Duran 			lhs.reset(new terminal_expr(l, leftVal));
929*4dfbc03dSJose Luis Duran 			break;
930c64a3eafSDavid Chisnall 		case '0'...'9':
931c64a3eafSDavid Chisnall 			if (!consume_integer(leftVal))
932c64a3eafSDavid Chisnall 			{
933c64a3eafSDavid Chisnall 				return nullptr;
934c64a3eafSDavid Chisnall 			}
935bbe31b70SEd Maste 			lhs.reset(new terminal_expr(l, leftVal));
936c64a3eafSDavid Chisnall 			break;
937c64a3eafSDavid Chisnall 		case '(':
938c64a3eafSDavid Chisnall 		{
939c64a3eafSDavid Chisnall 			consume('(');
940c64a3eafSDavid Chisnall 			expression_ptr &&subexpr = parse_expression();
941c64a3eafSDavid Chisnall 			if (!subexpr)
942c64a3eafSDavid Chisnall 			{
943c64a3eafSDavid Chisnall 				return nullptr;
944c64a3eafSDavid Chisnall 			}
945bbe31b70SEd Maste 			lhs.reset(new paren_expression(l, std::move(subexpr)));
946c64a3eafSDavid Chisnall 			if (!consume(')'))
947c64a3eafSDavid Chisnall 			{
948c64a3eafSDavid Chisnall 				return nullptr;
949c64a3eafSDavid Chisnall 			}
950c64a3eafSDavid Chisnall 			if (stopAtParen)
951c64a3eafSDavid Chisnall 			{
952c64a3eafSDavid Chisnall 				return lhs;
953c64a3eafSDavid Chisnall 			}
954c64a3eafSDavid Chisnall 			break;
955c64a3eafSDavid Chisnall 		}
956c64a3eafSDavid Chisnall 		case '+':
957c64a3eafSDavid Chisnall 		{
958c64a3eafSDavid Chisnall 			consume('+');
959c64a3eafSDavid Chisnall 			expression_ptr &&subexpr = parse_expression();
960c64a3eafSDavid Chisnall 			if (!subexpr)
961c64a3eafSDavid Chisnall 			{
962c64a3eafSDavid Chisnall 				return nullptr;
963c64a3eafSDavid Chisnall 			}
964bbe31b70SEd Maste 			lhs.reset(new unary_operator<'+', unary_plus<valty>>(l, std::move(subexpr)));
965c64a3eafSDavid Chisnall 			break;
966c64a3eafSDavid Chisnall 		}
967c64a3eafSDavid Chisnall 		case '-':
968c64a3eafSDavid Chisnall 		{
969c64a3eafSDavid Chisnall 			consume('-');
970c64a3eafSDavid Chisnall 			expression_ptr &&subexpr = parse_expression();
971c64a3eafSDavid Chisnall 			if (!subexpr)
972c64a3eafSDavid Chisnall 			{
973c64a3eafSDavid Chisnall 				return nullptr;
974c64a3eafSDavid Chisnall 			}
975bbe31b70SEd Maste 			lhs.reset(new unary_operator<'-', std::negate<valty>>(l, std::move(subexpr)));
976c64a3eafSDavid Chisnall 			break;
977c64a3eafSDavid Chisnall 		}
978c64a3eafSDavid Chisnall 		case '!':
979c64a3eafSDavid Chisnall 		{
980c64a3eafSDavid Chisnall 			consume('!');
981c64a3eafSDavid Chisnall 			expression_ptr &&subexpr = parse_expression();
982c64a3eafSDavid Chisnall 			if (!subexpr)
983c64a3eafSDavid Chisnall 			{
984c64a3eafSDavid Chisnall 				return nullptr;
985c64a3eafSDavid Chisnall 			}
986bbe31b70SEd Maste 			lhs.reset(new unary_operator<'!', std::logical_not<valty>>(l, std::move(subexpr)));
987c64a3eafSDavid Chisnall 			break;
988c64a3eafSDavid Chisnall 		}
989c64a3eafSDavid Chisnall 		case '~':
990c64a3eafSDavid Chisnall 		{
991c64a3eafSDavid Chisnall 			consume('~');
992c64a3eafSDavid Chisnall 			expression_ptr &&subexpr = parse_expression();
993c64a3eafSDavid Chisnall 			if (!subexpr)
994c64a3eafSDavid Chisnall 			{
995c64a3eafSDavid Chisnall 				return nullptr;
996c64a3eafSDavid Chisnall 			}
997bbe31b70SEd Maste 			lhs.reset(new unary_operator<'~', bit_not<valty>>(l, std::move(subexpr)));
998c64a3eafSDavid Chisnall 			break;
999c64a3eafSDavid Chisnall 		}
1000c64a3eafSDavid Chisnall 	}
1001c64a3eafSDavid Chisnall 	if (!lhs)
1002c64a3eafSDavid Chisnall 	{
1003c64a3eafSDavid Chisnall 		return nullptr;
1004c64a3eafSDavid Chisnall 	}
1005c64a3eafSDavid Chisnall 	return parse_binary_expression(std::move(lhs));
1006c64a3eafSDavid Chisnall }
1007c64a3eafSDavid Chisnall 
1008c64a3eafSDavid Chisnall bool
consume_integer_expression(unsigned long long & outInt)1009bbe31b70SEd Maste text_input_buffer::consume_integer_expression(unsigned long long &outInt)
1010c64a3eafSDavid Chisnall {
1011bbe31b70SEd Maste 	switch (*(*this))
1012c64a3eafSDavid Chisnall 	{
1013c64a3eafSDavid Chisnall 		case '(':
1014c64a3eafSDavid Chisnall 		{
1015c64a3eafSDavid Chisnall 			expression_ptr e(parse_expression(true));
1016c64a3eafSDavid Chisnall 			if (!e)
1017c64a3eafSDavid Chisnall 			{
1018c64a3eafSDavid Chisnall 				return false;
1019c64a3eafSDavid Chisnall 			}
1020bbe31b70SEd Maste 			auto r = (*e)();
1021bbe31b70SEd Maste 			if (r.second)
1022bbe31b70SEd Maste 			{
1023bbe31b70SEd Maste 				outInt = r.first;
1024c64a3eafSDavid Chisnall 				return true;
1025c64a3eafSDavid Chisnall 			}
1026bbe31b70SEd Maste 			return false;
1027bbe31b70SEd Maste 		}
1028c64a3eafSDavid Chisnall 		case '0'...'9':
1029c64a3eafSDavid Chisnall 			return consume_integer(outInt);
1030c64a3eafSDavid Chisnall 		default:
1031c64a3eafSDavid Chisnall 			return false;
1032c64a3eafSDavid Chisnall 	}
1033c64a3eafSDavid Chisnall }
1034c64a3eafSDavid Chisnall 
1035af0dd31fSDavid Chisnall bool
consume_hex_byte(uint8_t & outByte)1036af0dd31fSDavid Chisnall input_buffer::consume_hex_byte(uint8_t &outByte)
1037af0dd31fSDavid Chisnall {
1038af0dd31fSDavid Chisnall 	if (!ishexdigit((*this)[0]) && !ishexdigit((*this)[1]))
1039af0dd31fSDavid Chisnall 	{
1040af0dd31fSDavid Chisnall 		return false;
1041af0dd31fSDavid Chisnall 	}
1042af0dd31fSDavid Chisnall 	outByte = (digittoint((*this)[0]) << 4) | digittoint((*this)[1]);
1043af0dd31fSDavid Chisnall 	cursor += 2;
1044af0dd31fSDavid Chisnall 	return true;
1045af0dd31fSDavid Chisnall }
1046af0dd31fSDavid Chisnall 
1047bbe31b70SEd Maste text_input_buffer&
next_token()1048bbe31b70SEd Maste text_input_buffer::next_token()
1049af0dd31fSDavid Chisnall {
1050bbe31b70SEd Maste 	auto &self = *this;
1051af0dd31fSDavid Chisnall 	int start;
1052af0dd31fSDavid Chisnall 	do {
1053af0dd31fSDavid Chisnall 		start = cursor;
1054af0dd31fSDavid Chisnall 		skip_spaces();
1055bbe31b70SEd Maste 		if (finished())
1056bbe31b70SEd Maste 		{
1057bbe31b70SEd Maste 			return self;
1058bbe31b70SEd Maste 		}
1059af0dd31fSDavid Chisnall 		// Parse /* comments
1060bbe31b70SEd Maste 		if (*self == '/' && peek() == '*')
1061af0dd31fSDavid Chisnall 		{
1062af0dd31fSDavid Chisnall 			// eat the start of the comment
1063bbe31b70SEd Maste 			++self;
1064bbe31b70SEd Maste 			++self;
1065af0dd31fSDavid Chisnall 			do {
1066af0dd31fSDavid Chisnall 				// Find the ending * of */
1067bbe31b70SEd Maste 				while ((*self != '\0') && (*self != '*') && !finished())
1068af0dd31fSDavid Chisnall 				{
1069bbe31b70SEd Maste 					++self;
1070af0dd31fSDavid Chisnall 				}
1071af0dd31fSDavid Chisnall 				// Eat the *
1072bbe31b70SEd Maste 				++self;
1073bbe31b70SEd Maste 			} while ((*self != '\0') && (*self != '/') && !finished());
1074af0dd31fSDavid Chisnall 			// Eat the /
1075bbe31b70SEd Maste 			++self;
1076af0dd31fSDavid Chisnall 		}
1077a0706eb4SDavid Chisnall 		// Parse // comments
1078bbe31b70SEd Maste 		if ((*self == '/' && peek() == '/'))
1079af0dd31fSDavid Chisnall 		{
1080af0dd31fSDavid Chisnall 			// eat the start of the comment
1081bbe31b70SEd Maste 			++self;
1082bbe31b70SEd Maste 			++self;
10837f78c173SRui Paulo 			// Find the ending of the line
1084bbe31b70SEd Maste 			while (*self != '\n' && !finished())
1085af0dd31fSDavid Chisnall 			{
1086bbe31b70SEd Maste 				++self;
1087af0dd31fSDavid Chisnall 			}
1088af0dd31fSDavid Chisnall 			// Eat the \n
1089bbe31b70SEd Maste 			++self;
1090af0dd31fSDavid Chisnall 		}
1091af0dd31fSDavid Chisnall 	} while (start != cursor);
1092bbe31b70SEd Maste 	return self;
1093af0dd31fSDavid Chisnall }
1094af0dd31fSDavid Chisnall 
1095af0dd31fSDavid Chisnall void
parse_error(const char * msg)1096bbe31b70SEd Maste text_input_buffer::parse_error(const char *msg)
1097bbe31b70SEd Maste {
1098bbe31b70SEd Maste 	if (input_stack.empty())
1099bbe31b70SEd Maste 	{
1100bbe31b70SEd Maste 		fprintf(stderr, "Error: %s\n", msg);
1101bbe31b70SEd Maste 		return;
1102bbe31b70SEd Maste 	}
1103bbe31b70SEd Maste 	input_buffer &b = *input_stack.top();
1104bbe31b70SEd Maste 	parse_error(msg, b, b.cursor);
1105bbe31b70SEd Maste }
1106bbe31b70SEd Maste void
parse_error(const char * msg,input_buffer & b,int loc)1107bbe31b70SEd Maste text_input_buffer::parse_error(const char *msg,
1108bbe31b70SEd Maste                                input_buffer &b,
1109bbe31b70SEd Maste                                int loc)
1110af0dd31fSDavid Chisnall {
1111af0dd31fSDavid Chisnall 	int line_count = 1;
1112af0dd31fSDavid Chisnall 	int line_start = 0;
1113bbe31b70SEd Maste 	int line_end = loc;
1114bbe31b70SEd Maste 	if (loc < 0 || loc > b.size)
1115af0dd31fSDavid Chisnall 	{
1116bbe31b70SEd Maste 		return;
1117bbe31b70SEd Maste 	}
1118bbe31b70SEd Maste 	for (int i=loc ; i>0 ; --i)
1119bbe31b70SEd Maste 	{
1120bbe31b70SEd Maste 		if (b.buffer[i] == '\n')
1121af0dd31fSDavid Chisnall 		{
1122af0dd31fSDavid Chisnall 			line_count++;
1123af0dd31fSDavid Chisnall 			if (line_start == 0)
1124af0dd31fSDavid Chisnall 			{
1125af0dd31fSDavid Chisnall 				line_start = i+1;
1126af0dd31fSDavid Chisnall 			}
1127af0dd31fSDavid Chisnall 		}
1128af0dd31fSDavid Chisnall 	}
1129bbe31b70SEd Maste 	for (int i=loc+1 ; i<b.size ; ++i)
1130af0dd31fSDavid Chisnall 	{
1131bbe31b70SEd Maste 		if (b.buffer[i] == '\n')
1132af0dd31fSDavid Chisnall 		{
1133af0dd31fSDavid Chisnall 			line_end = i;
1134af0dd31fSDavid Chisnall 			break;
1135af0dd31fSDavid Chisnall 		}
1136af0dd31fSDavid Chisnall 	}
1137bbe31b70SEd Maste 	fprintf(stderr, "Error at %s:%d:%d: %s\n", b.filename().c_str(), line_count, loc - line_start, msg);
1138bbe31b70SEd Maste 	fwrite(&b.buffer[line_start], line_end-line_start, 1, stderr);
1139af0dd31fSDavid Chisnall 	putc('\n', stderr);
1140bbe31b70SEd Maste 	for (int i=0 ; i<(loc-line_start) ; ++i)
1141af0dd31fSDavid Chisnall 	{
1142bbe31b70SEd Maste 		char c = (b.buffer[i+line_start] == '\t') ? '\t' : ' ';
11438d9c8099SDavid Chisnall 		putc(c, stderr);
1144af0dd31fSDavid Chisnall 	}
1145af0dd31fSDavid Chisnall 	putc('^', stderr);
1146af0dd31fSDavid Chisnall 	putc('\n', stderr);
1147af0dd31fSDavid Chisnall }
1148c64a3eafSDavid Chisnall #ifndef NDEBUG
1149af0dd31fSDavid Chisnall void
dump()1150af0dd31fSDavid Chisnall input_buffer::dump()
1151af0dd31fSDavid Chisnall {
1152af0dd31fSDavid Chisnall 	fprintf(stderr, "Current cursor: %d\n", cursor);
1153af0dd31fSDavid Chisnall 	fwrite(&buffer[cursor], size-cursor, 1, stderr);
1154af0dd31fSDavid Chisnall }
1155c64a3eafSDavid Chisnall #endif
1156af0dd31fSDavid Chisnall 
1157bbe31b70SEd Maste 
1158bbe31b70SEd Maste namespace
1159af0dd31fSDavid Chisnall {
1160bbe31b70SEd Maste /**
1161bbe31b70SEd Maste  * The source files are ASCII, so we provide a non-locale-aware version of
1162bbe31b70SEd Maste  * isalpha.  This is a class so that it can be used with a template function
1163bbe31b70SEd Maste  * for parsing strings.
1164bbe31b70SEd Maste  */
1165bbe31b70SEd Maste struct is_alpha
1166af0dd31fSDavid Chisnall {
checkdtc::__anon3998a5d80311::is_alpha1167bbe31b70SEd Maste 	static inline bool check(const char c)
1168bbe31b70SEd Maste 	{
1169bbe31b70SEd Maste 		return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') &&
1170bbe31b70SEd Maste 			(c <= 'Z'));
1171af0dd31fSDavid Chisnall 	}
1172bbe31b70SEd Maste };
1173bbe31b70SEd Maste /**
1174bbe31b70SEd Maste  * Check whether a character is in the set allowed for node names.  This is a
1175bbe31b70SEd Maste  * class so that it can be used with a template function for parsing strings.
1176bbe31b70SEd Maste  */
1177bbe31b70SEd Maste struct is_node_name_character
1178af0dd31fSDavid Chisnall {
checkdtc::__anon3998a5d80311::is_node_name_character1179bbe31b70SEd Maste 	static inline bool check(const char c)
1180bbe31b70SEd Maste 	{
1181bbe31b70SEd Maste 		switch(c)
1182bbe31b70SEd Maste 		{
1183bbe31b70SEd Maste 			default:
1184bbe31b70SEd Maste 				return false;
1185bbe31b70SEd Maste 			case 'a'...'z': case 'A'...'Z': case '0'...'9':
1186bbe31b70SEd Maste 			case ',': case '.': case '+': case '-':
1187bbe31b70SEd Maste 			case '_':
1188bbe31b70SEd Maste 				return true;
1189af0dd31fSDavid Chisnall 		}
1190af0dd31fSDavid Chisnall 	}
1191bbe31b70SEd Maste };
1192bbe31b70SEd Maste /**
1193bbe31b70SEd Maste  * Check whether a character is in the set allowed for property names.  This is
1194bbe31b70SEd Maste  * a class so that it can be used with a template function for parsing strings.
1195bbe31b70SEd Maste  */
1196bbe31b70SEd Maste struct is_property_name_character
1197bbe31b70SEd Maste {
checkdtc::__anon3998a5d80311::is_property_name_character1198bbe31b70SEd Maste 	static inline bool check(const char c)
1199bbe31b70SEd Maste 	{
1200bbe31b70SEd Maste 		switch(c)
1201bbe31b70SEd Maste 		{
1202bbe31b70SEd Maste 			default:
1203bbe31b70SEd Maste 				return false;
1204bbe31b70SEd Maste 			case 'a'...'z': case 'A'...'Z': case '0'...'9':
1205bbe31b70SEd Maste 			case ',': case '.': case '+': case '-':
1206bbe31b70SEd Maste 			case '_': case '#':
1207bbe31b70SEd Maste 				return true;
1208bbe31b70SEd Maste 		}
1209bbe31b70SEd Maste 	}
1210bbe31b70SEd Maste };
1211bbe31b70SEd Maste 
1212bbe31b70SEd Maste template<class T>
parse(text_input_buffer & s)1213bbe31b70SEd Maste string parse(text_input_buffer &s)
1214bbe31b70SEd Maste {
1215bbe31b70SEd Maste 	std::vector<char> bytes;
1216bbe31b70SEd Maste 	for (char c=*s ; T::check(c) ; c=*(++s))
1217bbe31b70SEd Maste 	{
1218bbe31b70SEd Maste 		bytes.push_back(c);
1219bbe31b70SEd Maste 	}
1220bbe31b70SEd Maste 	return string(bytes.begin(), bytes.end());
1221bbe31b70SEd Maste }
1222af0dd31fSDavid Chisnall 
1223af0dd31fSDavid Chisnall }
1224af0dd31fSDavid Chisnall 
1225bbe31b70SEd Maste string
parse_node_name()1226bbe31b70SEd Maste text_input_buffer::parse_node_name()
1227af0dd31fSDavid Chisnall {
1228bbe31b70SEd Maste 	return parse<is_node_name_character>(*this);
1229af0dd31fSDavid Chisnall }
1230bbe31b70SEd Maste 
1231bbe31b70SEd Maste string
parse_property_name()1232bbe31b70SEd Maste text_input_buffer::parse_property_name()
1233bbe31b70SEd Maste {
1234bbe31b70SEd Maste 	return parse<is_property_name_character>(*this);
1235bbe31b70SEd Maste }
1236bbe31b70SEd Maste 
1237bbe31b70SEd Maste string
parse_node_or_property_name(bool & is_property)1238bbe31b70SEd Maste text_input_buffer::parse_node_or_property_name(bool &is_property)
1239bbe31b70SEd Maste {
1240bbe31b70SEd Maste 	if (is_property)
1241bbe31b70SEd Maste 	{
1242bbe31b70SEd Maste 		return parse_property_name();
1243bbe31b70SEd Maste 	}
1244bbe31b70SEd Maste 	std::vector<char> bytes;
1245bbe31b70SEd Maste 	for (char c=*(*this) ; is_node_name_character::check(c) ; c=*(++(*this)))
1246bbe31b70SEd Maste 	{
1247bbe31b70SEd Maste 		bytes.push_back(c);
1248bbe31b70SEd Maste 	}
1249bbe31b70SEd Maste 	for (char c=*(*this) ; is_property_name_character::check(c) ; c=*(++(*this)))
1250bbe31b70SEd Maste 	{
1251bbe31b70SEd Maste 		bytes.push_back(c);
1252bbe31b70SEd Maste 		is_property = true;
1253bbe31b70SEd Maste 	}
1254bbe31b70SEd Maste 	return string(bytes.begin(), bytes.end());
1255bbe31b70SEd Maste }
1256bbe31b70SEd Maste 
1257bbe31b70SEd Maste string
parse_to(char stop)1258bbe31b70SEd Maste input_buffer::parse_to(char stop)
1259bbe31b70SEd Maste {
1260bbe31b70SEd Maste 	std::vector<char> bytes;
1261bbe31b70SEd Maste 	for (char c=*(*this) ; c != stop ; c=*(++(*this)))
1262bbe31b70SEd Maste 	{
1263bbe31b70SEd Maste 		bytes.push_back(c);
1264bbe31b70SEd Maste 	}
1265bbe31b70SEd Maste 	return string(bytes.begin(), bytes.end());
1266bbe31b70SEd Maste }
1267bbe31b70SEd Maste 
1268bbe31b70SEd Maste string
parse_to(char stop)1269bbe31b70SEd Maste text_input_buffer::parse_to(char stop)
1270bbe31b70SEd Maste {
1271bbe31b70SEd Maste 	std::vector<char> bytes;
1272bbe31b70SEd Maste 	for (char c=*(*this) ; c != stop ; c=*(++(*this)))
1273bbe31b70SEd Maste 	{
1274bbe31b70SEd Maste 		if (finished())
1275bbe31b70SEd Maste 		{
1276bbe31b70SEd Maste 			break;
1277bbe31b70SEd Maste 		}
1278bbe31b70SEd Maste 		bytes.push_back(c);
1279bbe31b70SEd Maste 	}
1280bbe31b70SEd Maste 	return string(bytes.begin(), bytes.end());
1281bbe31b70SEd Maste }
1282bbe31b70SEd Maste 
1283bbe31b70SEd Maste char
peek()1284bbe31b70SEd Maste text_input_buffer::peek()
1285bbe31b70SEd Maste {
1286bbe31b70SEd Maste 	return (*input_stack.top())[1];
1287bbe31b70SEd Maste }
1288bbe31b70SEd Maste 
1289bbe31b70SEd Maste std::unique_ptr<input_buffer>
buffer_for_file(const string & path,bool warn)1290bbe31b70SEd Maste input_buffer::buffer_for_file(const string &path, bool warn)
1291bbe31b70SEd Maste {
1292bbe31b70SEd Maste 	if (path == "-")
1293bbe31b70SEd Maste 	{
1294bbe31b70SEd Maste 		std::unique_ptr<input_buffer> b(new stream_input_buffer());
1295bbe31b70SEd Maste 		return b;
1296bbe31b70SEd Maste 	}
1297bbe31b70SEd Maste 	int source = open(path.c_str(), O_RDONLY);
1298bbe31b70SEd Maste 	if (source == -1)
1299bbe31b70SEd Maste 	{
1300bbe31b70SEd Maste 		if (warn)
1301bbe31b70SEd Maste 		{
1302bbe31b70SEd Maste 			fprintf(stderr, "Unable to open file '%s'.  %s\n", path.c_str(), strerror(errno));
1303bbe31b70SEd Maste 		}
1304bbe31b70SEd Maste 		return 0;
1305bbe31b70SEd Maste 	}
1306bbe31b70SEd Maste 	struct stat st;
1307bbe31b70SEd Maste 	if (fstat(source, &st) == 0 && S_ISDIR(st.st_mode))
1308bbe31b70SEd Maste 	{
1309bbe31b70SEd Maste 		if (warn)
1310bbe31b70SEd Maste 		{
1311bbe31b70SEd Maste 			fprintf(stderr, "File %s is a directory\n", path.c_str());
1312bbe31b70SEd Maste 		}
1313bbe31b70SEd Maste 		close(source);
1314bbe31b70SEd Maste 		return 0;
1315bbe31b70SEd Maste 	}
131621d5d37bSEd Maste 	std::unique_ptr<input_buffer> b(new mmap_input_buffer(source, string(path)));
1317bbe31b70SEd Maste 	close(source);
1318bbe31b70SEd Maste 	return b;
1319af0dd31fSDavid Chisnall }
1320af0dd31fSDavid Chisnall 
1321af0dd31fSDavid Chisnall } // namespace dtc
1322af0dd31fSDavid Chisnall 
1323