xref: /freebsd-src/usr.bin/dtc/input_buffer.cc (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1af0dd31fSDavid Chisnall /*-
2*4d846d26SWarner 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__anon60f60bea0111::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__anon60f60bea0111::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_integer(unsigned long long & outInt)341a0706eb4SDavid Chisnall input_buffer::consume_integer(unsigned long long &outInt)
342af0dd31fSDavid Chisnall {
343af0dd31fSDavid Chisnall 	// The first character must be a digit.  Hex and octal strings
344af0dd31fSDavid Chisnall 	// are prefixed by 0 and 0x, respectively.
345af0dd31fSDavid Chisnall 	if (!isdigit((*this)[0]))
346af0dd31fSDavid Chisnall 	{
347af0dd31fSDavid Chisnall 		return false;
348af0dd31fSDavid Chisnall 	}
349bbe31b70SEd Maste 	char *end= const_cast<char*>(&buffer[size]);
35089f5bc46SJessica Clarke 	errno = 0;
351a0706eb4SDavid Chisnall 	outInt = strtoull(&buffer[cursor], &end, 0);
35289f5bc46SJessica Clarke 	if (end == &buffer[cursor] ||
35389f5bc46SJessica Clarke 	    (outInt == std::numeric_limits<unsigned long long>::max() &&
35489f5bc46SJessica Clarke 	     errno == ERANGE))
355af0dd31fSDavid Chisnall 	{
356af0dd31fSDavid Chisnall 		return false;
357af0dd31fSDavid Chisnall 	}
358af0dd31fSDavid Chisnall 	cursor = end - buffer;
359af0dd31fSDavid Chisnall 	return true;
360af0dd31fSDavid Chisnall }
361af0dd31fSDavid Chisnall 
362c64a3eafSDavid Chisnall namespace {
363c64a3eafSDavid Chisnall 
364c64a3eafSDavid Chisnall /**
365c64a3eafSDavid Chisnall  * Convenience typedef for the type that we use for all values.
366c64a3eafSDavid Chisnall  */
367c64a3eafSDavid Chisnall typedef unsigned long long valty;
368c64a3eafSDavid Chisnall 
369c64a3eafSDavid Chisnall /**
370c64a3eafSDavid Chisnall  * Expression tree currently being parsed.
371c64a3eafSDavid Chisnall  */
372c64a3eafSDavid Chisnall struct expression
373c64a3eafSDavid Chisnall {
374bbe31b70SEd Maste 	typedef text_input_buffer::source_location source_location;
375bbe31b70SEd Maste 	/**
376bbe31b70SEd Maste 	 * The type that is returned when computing the result.  The boolean value
377bbe31b70SEd Maste 	 * indicates whether this is a valid expression.
378bbe31b70SEd Maste 	 *
379bbe31b70SEd Maste 	 * FIXME: Once we can use C++17, this should be `std::optional`.
380bbe31b70SEd Maste 	 */
381bbe31b70SEd Maste 	typedef std::pair<valty, bool> result;
382c64a3eafSDavid Chisnall 	/**
383c64a3eafSDavid Chisnall 	 * Evaluate this node, taking into account operator precedence.
384c64a3eafSDavid Chisnall 	 */
385bbe31b70SEd Maste 	virtual result operator()() = 0;
386c64a3eafSDavid Chisnall 	/**
387c64a3eafSDavid Chisnall 	 * Returns the precedence of this node.  Lower values indicate higher
388c64a3eafSDavid Chisnall 	 * precedence.
389c64a3eafSDavid Chisnall 	 */
390c64a3eafSDavid Chisnall 	virtual int precedence() = 0;
391bbe31b70SEd Maste 	/**
392bbe31b70SEd Maste 	 * Constructs an expression, storing the location where it was created.
393bbe31b70SEd Maste 	 */
expressiondtc::__anon60f60bea0211::expression394bbe31b70SEd Maste 	expression(source_location l) : loc(l) {}
~expressiondtc::__anon60f60bea0211::expression395c64a3eafSDavid Chisnall 	virtual ~expression() {}
396c64a3eafSDavid Chisnall #ifndef NDEBUG
397c64a3eafSDavid Chisnall 	/**
398c64a3eafSDavid Chisnall 	 * Dumps this expression to `std::cerr`, appending a newline if `nl` is
399c64a3eafSDavid Chisnall 	 * `true`.
400c64a3eafSDavid Chisnall 	 */
dumpdtc::__anon60f60bea0211::expression401c64a3eafSDavid Chisnall 	void dump(bool nl=false)
402c64a3eafSDavid Chisnall 	{
403bbe31b70SEd Maste 		void *ptr = this;
404bbe31b70SEd Maste 		if (ptr == nullptr)
405c64a3eafSDavid Chisnall 		{
406c64a3eafSDavid Chisnall 			std::cerr << "{nullptr}\n";
407c64a3eafSDavid Chisnall 			return;
408c64a3eafSDavid Chisnall 		}
409c64a3eafSDavid Chisnall 		dump_impl();
410c64a3eafSDavid Chisnall 		if (nl)
411c64a3eafSDavid Chisnall 		{
412c64a3eafSDavid Chisnall 			std::cerr << '\n';
413c64a3eafSDavid Chisnall 		}
414c64a3eafSDavid Chisnall 	}
415c64a3eafSDavid Chisnall 	private:
416c64a3eafSDavid Chisnall 	/**
417c64a3eafSDavid Chisnall 	 * Method that sublcasses override to implement the behaviour of `dump()`.
418c64a3eafSDavid Chisnall 	 */
419c64a3eafSDavid Chisnall 	virtual void dump_impl() = 0;
420c64a3eafSDavid Chisnall #endif
421bbe31b70SEd Maste 	protected:
422bbe31b70SEd Maste 	source_location loc;
423c64a3eafSDavid Chisnall };
424c64a3eafSDavid Chisnall 
425c64a3eafSDavid Chisnall /**
426c64a3eafSDavid Chisnall  * Expression wrapping a single integer.  Leaf nodes in the expression tree.
427c64a3eafSDavid Chisnall  */
428c64a3eafSDavid Chisnall class terminal_expr : public expression
429c64a3eafSDavid Chisnall {
430c64a3eafSDavid Chisnall 	/**
431c64a3eafSDavid Chisnall 	 * The value that this wraps.
432c64a3eafSDavid Chisnall 	 */
433c64a3eafSDavid Chisnall 	valty val;
434c64a3eafSDavid Chisnall 	/**
435c64a3eafSDavid Chisnall 	 * Evaluate.  Trivially returns the value that this class wraps.
436c64a3eafSDavid Chisnall 	 */
operator ()()437bbe31b70SEd Maste 	result operator()() override
438c64a3eafSDavid Chisnall 	{
439bbe31b70SEd Maste 		return {val, true};
440c64a3eafSDavid Chisnall 	}
precedence()441c64a3eafSDavid Chisnall 	int precedence() override
442c64a3eafSDavid Chisnall 	{
443c64a3eafSDavid Chisnall 		return 0;
444c64a3eafSDavid Chisnall 	}
445c64a3eafSDavid Chisnall 	public:
446c64a3eafSDavid Chisnall 	/**
447c64a3eafSDavid Chisnall 	 * Constructor.
448c64a3eafSDavid Chisnall 	 */
terminal_expr(source_location l,valty v)449bbe31b70SEd Maste 	terminal_expr(source_location l, valty v) : expression(l), val(v) {}
450c64a3eafSDavid Chisnall #ifndef NDEBUG
dump_impl()451c64a3eafSDavid Chisnall 	void dump_impl() override { std::cerr << val; }
452c64a3eafSDavid Chisnall #endif
453c64a3eafSDavid Chisnall };
454c64a3eafSDavid Chisnall 
455c64a3eafSDavid Chisnall /**
456c64a3eafSDavid Chisnall  * Parenthetical expression.  Exists to make the contents opaque.
457c64a3eafSDavid Chisnall  */
458c64a3eafSDavid Chisnall struct paren_expression : public expression
459c64a3eafSDavid Chisnall {
460c64a3eafSDavid Chisnall 	/**
461c64a3eafSDavid Chisnall 	 * The expression within the parentheses.
462c64a3eafSDavid Chisnall 	 */
463c64a3eafSDavid Chisnall 	expression_ptr subexpr;
464c64a3eafSDavid Chisnall 	/**
465c64a3eafSDavid Chisnall 	 * Constructor.  Takes the child expression as the only argument.
466c64a3eafSDavid Chisnall 	 */
paren_expressiondtc::__anon60f60bea0211::paren_expression467bbe31b70SEd Maste 	paren_expression(source_location l, expression_ptr p) : expression(l),
468bbe31b70SEd Maste 	subexpr(std::move(p)) {}
precedencedtc::__anon60f60bea0211::paren_expression469c64a3eafSDavid Chisnall 	int precedence() override
470c64a3eafSDavid Chisnall 	{
471c64a3eafSDavid Chisnall 		return 0;
472c64a3eafSDavid Chisnall 	}
473c64a3eafSDavid Chisnall 	/**
474c64a3eafSDavid Chisnall 	 * Evaluate - just forwards to the underlying expression.
475c64a3eafSDavid Chisnall 	 */
operator ()dtc::__anon60f60bea0211::paren_expression476bbe31b70SEd Maste 	result operator()() override
477c64a3eafSDavid Chisnall 	{
478c64a3eafSDavid Chisnall 		return (*subexpr)();
479c64a3eafSDavid Chisnall 	}
480c64a3eafSDavid Chisnall #ifndef NDEBUG
dump_impldtc::__anon60f60bea0211::paren_expression481c64a3eafSDavid Chisnall 	void dump_impl() override
482c64a3eafSDavid Chisnall 	{
483c64a3eafSDavid Chisnall 		std::cerr << " (";
484c64a3eafSDavid Chisnall 		subexpr->dump();
485c64a3eafSDavid Chisnall 		std::cerr << ") ";
486c64a3eafSDavid Chisnall 	}
487c64a3eafSDavid Chisnall #endif
488c64a3eafSDavid Chisnall };
489c64a3eafSDavid Chisnall 
490c64a3eafSDavid Chisnall /**
491c64a3eafSDavid Chisnall  * Template class for unary operators.  The `OpChar` template parameter is
492c64a3eafSDavid Chisnall  * solely for debugging and makes it easy to print the expression.  The `Op`
493c64a3eafSDavid Chisnall  * template parameter is a function object that implements the operator that
494c64a3eafSDavid Chisnall  * this class provides.  Most of these are provided by the `<functional>`
495c64a3eafSDavid Chisnall  * header.
496c64a3eafSDavid Chisnall  */
497c64a3eafSDavid Chisnall template<char OpChar, class Op>
498c64a3eafSDavid Chisnall class unary_operator : public expression
499c64a3eafSDavid Chisnall {
500c64a3eafSDavid Chisnall 	/**
501c64a3eafSDavid Chisnall 	 * The subexpression for this unary operator.
502c64a3eafSDavid Chisnall 	 */
503c64a3eafSDavid Chisnall 	expression_ptr subexpr;
operator ()()504bbe31b70SEd Maste 	result operator()() override
505c64a3eafSDavid Chisnall 	{
506c64a3eafSDavid Chisnall 		Op op;
507bbe31b70SEd Maste 		result s = (*subexpr)();
508bbe31b70SEd Maste 		if (!s.second)
509bbe31b70SEd Maste 		{
510bbe31b70SEd Maste 			return s;
511bbe31b70SEd Maste 		}
512bbe31b70SEd Maste 		return {op(s.first), true};
513c64a3eafSDavid Chisnall 	}
514c64a3eafSDavid Chisnall 	/**
515c64a3eafSDavid Chisnall 	 * All unary operators have the same precedence.  They are all evaluated
516c64a3eafSDavid Chisnall 	 * before binary expressions, but after parentheses.
517c64a3eafSDavid Chisnall 	 */
precedence()518c64a3eafSDavid Chisnall 	int precedence() override
519c64a3eafSDavid Chisnall 	{
520c64a3eafSDavid Chisnall 		return 3;
521c64a3eafSDavid Chisnall 	}
522c64a3eafSDavid Chisnall 	public:
unary_operator(source_location l,expression_ptr p)523bbe31b70SEd Maste 	unary_operator(source_location l, expression_ptr p) :
524bbe31b70SEd Maste 		expression(l), subexpr(std::move(p)) {}
525c64a3eafSDavid Chisnall #ifndef NDEBUG
dump_impl()526c64a3eafSDavid Chisnall 	void dump_impl() override
527c64a3eafSDavid Chisnall 	{
528c64a3eafSDavid Chisnall 		std::cerr << OpChar;
529c64a3eafSDavid Chisnall 		subexpr->dump();
530c64a3eafSDavid Chisnall 	}
531c64a3eafSDavid Chisnall #endif
532c64a3eafSDavid Chisnall };
533c64a3eafSDavid Chisnall 
534c64a3eafSDavid Chisnall /**
535c64a3eafSDavid Chisnall  * Abstract base class for binary operators.  Allows the tree to be modified
536c64a3eafSDavid Chisnall  * without knowing what the operations actually are.
537c64a3eafSDavid Chisnall  */
538c64a3eafSDavid Chisnall struct binary_operator_base : public expression
539c64a3eafSDavid Chisnall {
540bbe31b70SEd Maste 	using expression::expression;
541c64a3eafSDavid Chisnall 	/**
542c64a3eafSDavid Chisnall 	 * The left side of the expression.
543c64a3eafSDavid Chisnall 	 */
544c64a3eafSDavid Chisnall 	expression_ptr lhs;
545c64a3eafSDavid Chisnall 	/**
546c64a3eafSDavid Chisnall 	 * The right side of the expression.
547c64a3eafSDavid Chisnall 	 */
548c64a3eafSDavid Chisnall 	expression_ptr rhs;
549c64a3eafSDavid Chisnall 	/**
550c64a3eafSDavid Chisnall 	 * Insert a node somewhere down the path of left children, until it would
551c64a3eafSDavid Chisnall 	 * be preempting something that should execute first.
552c64a3eafSDavid Chisnall 	 */
insert_leftdtc::__anon60f60bea0211::binary_operator_base553c64a3eafSDavid Chisnall 	void insert_left(binary_operator_base *new_left)
554c64a3eafSDavid Chisnall 	{
555c64a3eafSDavid Chisnall 		if (lhs->precedence() < new_left->precedence())
556c64a3eafSDavid Chisnall 		{
557c64a3eafSDavid Chisnall 			new_left->rhs = std::move(lhs);
558c64a3eafSDavid Chisnall 			lhs.reset(new_left);
559c64a3eafSDavid Chisnall 		}
560c64a3eafSDavid Chisnall 		else
561c64a3eafSDavid Chisnall 		{
562c64a3eafSDavid Chisnall 			static_cast<binary_operator_base*>(lhs.get())->insert_left(new_left);
563c64a3eafSDavid Chisnall 		}
564c64a3eafSDavid Chisnall 	}
565c64a3eafSDavid Chisnall };
566c64a3eafSDavid Chisnall 
567c64a3eafSDavid Chisnall /**
568c64a3eafSDavid Chisnall  * Template class for binary operators.  The precedence and the operation are
569c64a3eafSDavid Chisnall  * provided as template parameters.
570c64a3eafSDavid Chisnall  */
571c64a3eafSDavid Chisnall template<int Precedence, class Op>
572c64a3eafSDavid Chisnall struct binary_operator : public binary_operator_base
573c64a3eafSDavid Chisnall {
operator ()dtc::__anon60f60bea0211::binary_operator574bbe31b70SEd Maste 	result operator()() override
575c64a3eafSDavid Chisnall 	{
576c64a3eafSDavid Chisnall 		Op op;
577bbe31b70SEd Maste 		result l = (*lhs)();
578bbe31b70SEd Maste 		result r = (*rhs)();
579bbe31b70SEd Maste 		if (!(l.second && r.second))
580bbe31b70SEd Maste 		{
581bbe31b70SEd Maste 			return {0, false};
582bbe31b70SEd Maste 		}
583bbe31b70SEd Maste 		return {op(l.first, r.first), true};
584c64a3eafSDavid Chisnall 	}
precedencedtc::__anon60f60bea0211::binary_operator585c64a3eafSDavid Chisnall 	int precedence() override
586c64a3eafSDavid Chisnall 	{
587c64a3eafSDavid Chisnall 		return Precedence;
588c64a3eafSDavid Chisnall 	}
589c64a3eafSDavid Chisnall #ifdef NDEBUG
590c64a3eafSDavid Chisnall 	/**
591c64a3eafSDavid Chisnall 	 * Constructor.  Takes the name of the operator as an argument, for
592c64a3eafSDavid Chisnall 	 * debugging.  Only stores it in debug mode.
593c64a3eafSDavid Chisnall 	 */
binary_operatordtc::__anon60f60bea0211::binary_operator59423cba92bSDimitry Andric 	binary_operator(source_location l, const char *) :
59523cba92bSDimitry Andric 		binary_operator_base(l) {}
596c64a3eafSDavid Chisnall #else
597c64a3eafSDavid Chisnall 	const char *opName;
binary_operatordtc::__anon60f60bea0211::binary_operator598bbe31b70SEd Maste 	binary_operator(source_location l, const char *o) :
599bbe31b70SEd Maste 		binary_operator_base(l), opName(o) {}
dump_impldtc::__anon60f60bea0211::binary_operator600c64a3eafSDavid Chisnall 	void dump_impl() override
601c64a3eafSDavid Chisnall 	{
602c64a3eafSDavid Chisnall 		lhs->dump();
603c64a3eafSDavid Chisnall 		std::cerr << opName;
604c64a3eafSDavid Chisnall 		rhs->dump();
605c64a3eafSDavid Chisnall 	}
606c64a3eafSDavid Chisnall #endif
607c64a3eafSDavid Chisnall };
608c64a3eafSDavid Chisnall 
609c64a3eafSDavid Chisnall /**
610c64a3eafSDavid Chisnall  * Ternary conditional operators (`cond ? true : false`) are a special case -
611c64a3eafSDavid Chisnall  * there are no other ternary operators.
612c64a3eafSDavid Chisnall  */
613c64a3eafSDavid Chisnall class ternary_conditional_operator : public expression
614c64a3eafSDavid Chisnall {
615c64a3eafSDavid Chisnall 	/**
616c64a3eafSDavid Chisnall 	 * The condition for the clause.
617c64a3eafSDavid Chisnall 	 */
618c64a3eafSDavid Chisnall 	expression_ptr cond;
619c64a3eafSDavid Chisnall 	/**
620c64a3eafSDavid Chisnall 	 * The expression that this evaluates to if the condition is true.
621c64a3eafSDavid Chisnall 	 */
622c64a3eafSDavid Chisnall 	expression_ptr lhs;
623c64a3eafSDavid Chisnall 	/**
624c64a3eafSDavid Chisnall 	 * The expression that this evaluates to if the condition is false.
625c64a3eafSDavid Chisnall 	 */
626c64a3eafSDavid Chisnall 	expression_ptr rhs;
operator ()()627bbe31b70SEd Maste 	result operator()() override
628c64a3eafSDavid Chisnall 	{
629bbe31b70SEd Maste 		result c = (*cond)();
630bbe31b70SEd Maste 		result l = (*lhs)();
631bbe31b70SEd Maste 		result r = (*rhs)();
632bbe31b70SEd Maste 		if (!(l.second && r.second && c.second))
633bbe31b70SEd Maste 		{
634bbe31b70SEd Maste 			return {0, false};
635bbe31b70SEd Maste 		}
636bbe31b70SEd Maste 		return c.first ? l : r;
637c64a3eafSDavid Chisnall 	}
precedence()638c64a3eafSDavid Chisnall 	int precedence() override
639c64a3eafSDavid Chisnall 	{
640c64a3eafSDavid Chisnall 		// The actual precedence of a ternary conditional operator is 15, but
641c64a3eafSDavid Chisnall 		// its associativity is the opposite way around to the other operators,
642c64a3eafSDavid Chisnall 		// so we fudge it slightly.
643c64a3eafSDavid Chisnall 		return 3;
644c64a3eafSDavid Chisnall 	}
645c64a3eafSDavid Chisnall #ifndef NDEBUG
dump_impl()646c64a3eafSDavid Chisnall 	void dump_impl() override
647c64a3eafSDavid Chisnall 	{
648c64a3eafSDavid Chisnall 		cond->dump();
649c64a3eafSDavid Chisnall 		std::cerr << " ? ";
650c64a3eafSDavid Chisnall 		lhs->dump();
651c64a3eafSDavid Chisnall 		std::cerr << " : ";
652c64a3eafSDavid Chisnall 		rhs->dump();
653c64a3eafSDavid Chisnall 	}
654c64a3eafSDavid Chisnall #endif
655c64a3eafSDavid Chisnall 	public:
ternary_conditional_operator(source_location sl,expression_ptr c,expression_ptr l,expression_ptr r)656bbe31b70SEd Maste 	ternary_conditional_operator(source_location sl,
657bbe31b70SEd Maste 	                             expression_ptr c,
658c64a3eafSDavid Chisnall 	                             expression_ptr l,
659c64a3eafSDavid Chisnall 	                             expression_ptr r) :
660bbe31b70SEd Maste 		expression(sl), cond(std::move(c)), lhs(std::move(l)),
661bbe31b70SEd Maste 		rhs(std::move(r)) {}
662c64a3eafSDavid Chisnall };
663c64a3eafSDavid Chisnall 
664c64a3eafSDavid Chisnall template<typename T>
665c64a3eafSDavid Chisnall struct lshift
666c64a3eafSDavid Chisnall {
operator ()dtc::__anon60f60bea0211::lshift667c64a3eafSDavid Chisnall 	constexpr T operator()(const T &lhs, const T &rhs) const
668c64a3eafSDavid Chisnall 	{
669c64a3eafSDavid Chisnall 		return lhs << rhs;
670c64a3eafSDavid Chisnall 	}
671c64a3eafSDavid Chisnall };
672c64a3eafSDavid Chisnall template<typename T>
673c64a3eafSDavid Chisnall struct rshift
674c64a3eafSDavid Chisnall {
operator ()dtc::__anon60f60bea0211::rshift675c64a3eafSDavid Chisnall 	constexpr T operator()(const T &lhs, const T &rhs) const
676c64a3eafSDavid Chisnall 	{
677c64a3eafSDavid Chisnall 		return lhs >> rhs;
678c64a3eafSDavid Chisnall 	}
679c64a3eafSDavid Chisnall };
680c64a3eafSDavid Chisnall template<typename T>
681c64a3eafSDavid Chisnall struct unary_plus
682c64a3eafSDavid Chisnall {
operator ()dtc::__anon60f60bea0211::unary_plus683c64a3eafSDavid Chisnall 	constexpr T operator()(const T &val) const
684c64a3eafSDavid Chisnall 	{
685c64a3eafSDavid Chisnall 		return +val;
686c64a3eafSDavid Chisnall 	}
687c64a3eafSDavid Chisnall };
688c64a3eafSDavid Chisnall // TODO: Replace with std::bit_not once we can guarantee C++14 as a baseline.
689c64a3eafSDavid Chisnall template<typename T>
690c64a3eafSDavid Chisnall struct bit_not
691c64a3eafSDavid Chisnall {
operator ()dtc::__anon60f60bea0211::bit_not692c64a3eafSDavid Chisnall 	constexpr T operator()(const T &val) const
693c64a3eafSDavid Chisnall 	{
694c64a3eafSDavid Chisnall 		return ~val;
695c64a3eafSDavid Chisnall 	}
696c64a3eafSDavid Chisnall };
697c64a3eafSDavid Chisnall 
698bbe31b70SEd Maste template<typename T>
699bbe31b70SEd Maste struct divmod : public binary_operator<5, T>
700bbe31b70SEd Maste {
701bbe31b70SEd Maste 	using binary_operator<5, T>::binary_operator;
7028b4debd2SEmmanuel Vadot 	using typename binary_operator_base::result;
operator ()dtc::__anon60f60bea0211::divmod703bbe31b70SEd Maste 	result operator()() override
704bbe31b70SEd Maste 	{
705bbe31b70SEd Maste 		result r = (*binary_operator_base::rhs)();
706bbe31b70SEd Maste 		if (r.second && (r.first == 0))
707bbe31b70SEd Maste 		{
708bbe31b70SEd Maste 			expression::loc.report_error("Division by zero");
709bbe31b70SEd Maste 			return {0, false};
710bbe31b70SEd Maste 		}
711bbe31b70SEd Maste 		return binary_operator<5, T>::operator()();
712bbe31b70SEd Maste 	}
713bbe31b70SEd Maste };
714bbe31b70SEd Maste 
715c64a3eafSDavid Chisnall } // anonymous namespace
716c64a3eafSDavid Chisnall 
717c64a3eafSDavid Chisnall 
parse_binary_expression(expression_ptr lhs)718bbe31b70SEd Maste expression_ptr text_input_buffer::parse_binary_expression(expression_ptr lhs)
719c64a3eafSDavid Chisnall {
720c64a3eafSDavid Chisnall 	next_token();
721c64a3eafSDavid Chisnall 	binary_operator_base *expr = nullptr;
722bbe31b70SEd Maste 	char op = *(*this);
723bbe31b70SEd Maste 	source_location l = location();
724c64a3eafSDavid Chisnall 	switch (op)
725c64a3eafSDavid Chisnall 	{
726c64a3eafSDavid Chisnall 		default:
727c64a3eafSDavid Chisnall 			return lhs;
728c64a3eafSDavid Chisnall 		case '+':
729bbe31b70SEd Maste 			expr = new binary_operator<6, std::plus<valty>>(l, "+");
730c64a3eafSDavid Chisnall 			break;
731c64a3eafSDavid Chisnall 		case '-':
732bbe31b70SEd Maste 			expr = new binary_operator<6, std::minus<valty>>(l, "-");
733c64a3eafSDavid Chisnall 			break;
734c64a3eafSDavid Chisnall 		case '%':
735bbe31b70SEd Maste 			expr = new divmod<std::modulus<valty>>(l, "/");
736c64a3eafSDavid Chisnall 			break;
737c64a3eafSDavid Chisnall 		case '*':
738bbe31b70SEd Maste 			expr = new binary_operator<5, std::multiplies<valty>>(l, "*");
739c64a3eafSDavid Chisnall 			break;
740c64a3eafSDavid Chisnall 		case '/':
741bbe31b70SEd Maste 			expr = new divmod<std::divides<valty>>(l, "/");
742c64a3eafSDavid Chisnall 			break;
743c64a3eafSDavid Chisnall 		case '<':
744bbe31b70SEd Maste 			switch (peek())
745c64a3eafSDavid Chisnall 			{
746c64a3eafSDavid Chisnall 				default:
747c64a3eafSDavid Chisnall 					parse_error("Invalid operator");
748c64a3eafSDavid Chisnall 					return nullptr;
749c64a3eafSDavid Chisnall 				case ' ':
750c64a3eafSDavid Chisnall 				case '(':
751c64a3eafSDavid Chisnall 				case '0'...'9':
752bbe31b70SEd Maste 					expr = new binary_operator<8, std::less<valty>>(l, "<");
753c64a3eafSDavid Chisnall 					break;
754c64a3eafSDavid Chisnall 				case '=':
755bbe31b70SEd Maste 					++(*this);
756bbe31b70SEd Maste 					expr = new binary_operator<8, std::less_equal<valty>>(l, "<=");
757c64a3eafSDavid Chisnall 					break;
758c64a3eafSDavid Chisnall 				case '<':
759bbe31b70SEd Maste 					++(*this);
760bbe31b70SEd Maste 					expr = new binary_operator<7, lshift<valty>>(l, "<<");
761c64a3eafSDavid Chisnall 					break;
762c64a3eafSDavid Chisnall 			}
763c64a3eafSDavid Chisnall 			break;
764c64a3eafSDavid Chisnall 		case '>':
765bbe31b70SEd Maste 			switch (peek())
766c64a3eafSDavid Chisnall 			{
767c64a3eafSDavid Chisnall 				default:
768c64a3eafSDavid Chisnall 					parse_error("Invalid operator");
769c64a3eafSDavid Chisnall 					return nullptr;
770c64a3eafSDavid Chisnall 				case '(':
771c64a3eafSDavid Chisnall 				case ' ':
772c64a3eafSDavid Chisnall 				case '0'...'9':
773bbe31b70SEd Maste 					expr = new binary_operator<8, std::greater<valty>>(l, ">");
774c64a3eafSDavid Chisnall 					break;
775c64a3eafSDavid Chisnall 				case '=':
776bbe31b70SEd Maste 					++(*this);
777bbe31b70SEd Maste 					expr = new binary_operator<8, std::greater_equal<valty>>(l, ">=");
778c64a3eafSDavid Chisnall 					break;
779c64a3eafSDavid Chisnall 				case '>':
780bbe31b70SEd Maste 					++(*this);
781bbe31b70SEd Maste 					expr = new binary_operator<7, rshift<valty>>(l, ">>");
782c64a3eafSDavid Chisnall 					break;
783c64a3eafSDavid Chisnall 					return lhs;
784c64a3eafSDavid Chisnall 			}
785c64a3eafSDavid Chisnall 			break;
786c64a3eafSDavid Chisnall 		case '=':
787bbe31b70SEd Maste 			if (peek() != '=')
788c64a3eafSDavid Chisnall 			{
789c64a3eafSDavid Chisnall 				parse_error("Invalid operator");
790c64a3eafSDavid Chisnall 				return nullptr;
791c64a3eafSDavid Chisnall 			}
792bbe31b70SEd Maste 			expr = new binary_operator<9, std::equal_to<valty>>(l, "==");
793c64a3eafSDavid Chisnall 			break;
794c64a3eafSDavid Chisnall 		case '!':
795bbe31b70SEd Maste 			if (peek() != '=')
796c64a3eafSDavid Chisnall 			{
797c64a3eafSDavid Chisnall 				parse_error("Invalid operator");
798c64a3eafSDavid Chisnall 				return nullptr;
799c64a3eafSDavid Chisnall 			}
800c64a3eafSDavid Chisnall 			cursor++;
801bbe31b70SEd Maste 			expr = new binary_operator<9, std::not_equal_to<valty>>(l, "!=");
802c64a3eafSDavid Chisnall 			break;
803c64a3eafSDavid Chisnall 		case '&':
804bbe31b70SEd Maste 			if (peek() == '&')
805c64a3eafSDavid Chisnall 			{
806bbe31b70SEd Maste 				expr = new binary_operator<13, std::logical_and<valty>>(l, "&&");
807c64a3eafSDavid Chisnall 			}
808c64a3eafSDavid Chisnall 			else
809c64a3eafSDavid Chisnall 			{
810bbe31b70SEd Maste 				expr = new binary_operator<10, std::bit_and<valty>>(l, "&");
811c64a3eafSDavid Chisnall 			}
812c64a3eafSDavid Chisnall 			break;
813c64a3eafSDavid Chisnall 		case '|':
814bbe31b70SEd Maste 			if (peek() == '|')
815c64a3eafSDavid Chisnall 			{
816bbe31b70SEd Maste 				expr = new binary_operator<12, std::logical_or<valty>>(l, "||");
817c64a3eafSDavid Chisnall 			}
818c64a3eafSDavid Chisnall 			else
819c64a3eafSDavid Chisnall 			{
820bbe31b70SEd Maste 				expr = new binary_operator<14, std::bit_or<valty>>(l, "|");
821c64a3eafSDavid Chisnall 			}
822c64a3eafSDavid Chisnall 			break;
823c64a3eafSDavid Chisnall 		case '?':
824c64a3eafSDavid Chisnall 		{
825c64a3eafSDavid Chisnall 			consume('?');
826c64a3eafSDavid Chisnall 			expression_ptr true_case = parse_expression();
827c64a3eafSDavid Chisnall 			next_token();
828c64a3eafSDavid Chisnall 			if (!true_case || !consume(':'))
829c64a3eafSDavid Chisnall 			{
830c64a3eafSDavid Chisnall 				parse_error("Expected : in ternary conditional operator");
831c64a3eafSDavid Chisnall 				return nullptr;
832c64a3eafSDavid Chisnall 			}
833c64a3eafSDavid Chisnall 			expression_ptr false_case = parse_expression();
834c64a3eafSDavid Chisnall 			if (!false_case)
835c64a3eafSDavid Chisnall 			{
836c64a3eafSDavid Chisnall 				parse_error("Expected false condition for ternary operator");
837c64a3eafSDavid Chisnall 				return nullptr;
838c64a3eafSDavid Chisnall 			}
839bbe31b70SEd Maste 			return expression_ptr(new ternary_conditional_operator(l, std::move(lhs),
840c64a3eafSDavid Chisnall 						std::move(true_case), std::move(false_case)));
841c64a3eafSDavid Chisnall 		}
842c64a3eafSDavid Chisnall 	}
843bbe31b70SEd Maste 	++(*this);
844c64a3eafSDavid Chisnall 	next_token();
845c64a3eafSDavid Chisnall 	expression_ptr e(expr);
846c64a3eafSDavid Chisnall 	expression_ptr rhs(parse_expression());
847c64a3eafSDavid Chisnall 	if (!rhs)
848c64a3eafSDavid Chisnall 	{
849c64a3eafSDavid Chisnall 		return nullptr;
850c64a3eafSDavid Chisnall 	}
851c64a3eafSDavid Chisnall 	expr->lhs = std::move(lhs);
852c64a3eafSDavid Chisnall 	if (rhs->precedence() < expr->precedence())
853c64a3eafSDavid Chisnall 	{
854c64a3eafSDavid Chisnall 		expr->rhs = std::move(rhs);
855c64a3eafSDavid Chisnall 	}
856c64a3eafSDavid Chisnall 	else
857c64a3eafSDavid Chisnall 	{
858c64a3eafSDavid Chisnall 		// If we're a normal left-to-right expression, then we need to insert
859c64a3eafSDavid Chisnall 		// this as the far-left child node of the rhs expression
860c64a3eafSDavid Chisnall 		binary_operator_base *rhs_op =
861c64a3eafSDavid Chisnall 			static_cast<binary_operator_base*>(rhs.get());
862c64a3eafSDavid Chisnall 		rhs_op->insert_left(expr);
863c64a3eafSDavid Chisnall 		e.release();
864c64a3eafSDavid Chisnall 		return rhs;
865c64a3eafSDavid Chisnall 	}
866c64a3eafSDavid Chisnall 	return e;
867c64a3eafSDavid Chisnall }
868c64a3eafSDavid Chisnall 
parse_expression(bool stopAtParen)869bbe31b70SEd Maste expression_ptr text_input_buffer::parse_expression(bool stopAtParen)
870c64a3eafSDavid Chisnall {
871c64a3eafSDavid Chisnall 	next_token();
872c64a3eafSDavid Chisnall 	unsigned long long leftVal;
873c64a3eafSDavid Chisnall 	expression_ptr lhs;
874bbe31b70SEd Maste 	source_location l = location();
875bbe31b70SEd Maste 	switch (*(*this))
876c64a3eafSDavid Chisnall 	{
877c64a3eafSDavid Chisnall 		case '0'...'9':
878c64a3eafSDavid Chisnall 			if (!consume_integer(leftVal))
879c64a3eafSDavid Chisnall 			{
880c64a3eafSDavid Chisnall 				return nullptr;
881c64a3eafSDavid Chisnall 			}
882bbe31b70SEd Maste 			lhs.reset(new terminal_expr(l, leftVal));
883c64a3eafSDavid Chisnall 			break;
884c64a3eafSDavid Chisnall 		case '(':
885c64a3eafSDavid Chisnall 		{
886c64a3eafSDavid Chisnall 			consume('(');
887c64a3eafSDavid Chisnall 			expression_ptr &&subexpr = parse_expression();
888c64a3eafSDavid Chisnall 			if (!subexpr)
889c64a3eafSDavid Chisnall 			{
890c64a3eafSDavid Chisnall 				return nullptr;
891c64a3eafSDavid Chisnall 			}
892bbe31b70SEd Maste 			lhs.reset(new paren_expression(l, std::move(subexpr)));
893c64a3eafSDavid Chisnall 			if (!consume(')'))
894c64a3eafSDavid Chisnall 			{
895c64a3eafSDavid Chisnall 				return nullptr;
896c64a3eafSDavid Chisnall 			}
897c64a3eafSDavid Chisnall 			if (stopAtParen)
898c64a3eafSDavid Chisnall 			{
899c64a3eafSDavid Chisnall 				return lhs;
900c64a3eafSDavid Chisnall 			}
901c64a3eafSDavid Chisnall 			break;
902c64a3eafSDavid Chisnall 		}
903c64a3eafSDavid Chisnall 		case '+':
904c64a3eafSDavid Chisnall 		{
905c64a3eafSDavid Chisnall 			consume('+');
906c64a3eafSDavid Chisnall 			expression_ptr &&subexpr = parse_expression();
907c64a3eafSDavid Chisnall 			if (!subexpr)
908c64a3eafSDavid Chisnall 			{
909c64a3eafSDavid Chisnall 				return nullptr;
910c64a3eafSDavid Chisnall 			}
911bbe31b70SEd Maste 			lhs.reset(new unary_operator<'+', unary_plus<valty>>(l, std::move(subexpr)));
912c64a3eafSDavid Chisnall 			break;
913c64a3eafSDavid Chisnall 		}
914c64a3eafSDavid Chisnall 		case '-':
915c64a3eafSDavid Chisnall 		{
916c64a3eafSDavid Chisnall 			consume('-');
917c64a3eafSDavid Chisnall 			expression_ptr &&subexpr = parse_expression();
918c64a3eafSDavid Chisnall 			if (!subexpr)
919c64a3eafSDavid Chisnall 			{
920c64a3eafSDavid Chisnall 				return nullptr;
921c64a3eafSDavid Chisnall 			}
922bbe31b70SEd Maste 			lhs.reset(new unary_operator<'-', std::negate<valty>>(l, std::move(subexpr)));
923c64a3eafSDavid Chisnall 			break;
924c64a3eafSDavid Chisnall 		}
925c64a3eafSDavid Chisnall 		case '!':
926c64a3eafSDavid Chisnall 		{
927c64a3eafSDavid Chisnall 			consume('!');
928c64a3eafSDavid Chisnall 			expression_ptr &&subexpr = parse_expression();
929c64a3eafSDavid Chisnall 			if (!subexpr)
930c64a3eafSDavid Chisnall 			{
931c64a3eafSDavid Chisnall 				return nullptr;
932c64a3eafSDavid Chisnall 			}
933bbe31b70SEd Maste 			lhs.reset(new unary_operator<'!', std::logical_not<valty>>(l, std::move(subexpr)));
934c64a3eafSDavid Chisnall 			break;
935c64a3eafSDavid Chisnall 		}
936c64a3eafSDavid Chisnall 		case '~':
937c64a3eafSDavid Chisnall 		{
938c64a3eafSDavid Chisnall 			consume('~');
939c64a3eafSDavid Chisnall 			expression_ptr &&subexpr = parse_expression();
940c64a3eafSDavid Chisnall 			if (!subexpr)
941c64a3eafSDavid Chisnall 			{
942c64a3eafSDavid Chisnall 				return nullptr;
943c64a3eafSDavid Chisnall 			}
944bbe31b70SEd Maste 			lhs.reset(new unary_operator<'~', bit_not<valty>>(l, std::move(subexpr)));
945c64a3eafSDavid Chisnall 			break;
946c64a3eafSDavid Chisnall 		}
947c64a3eafSDavid Chisnall 	}
948c64a3eafSDavid Chisnall 	if (!lhs)
949c64a3eafSDavid Chisnall 	{
950c64a3eafSDavid Chisnall 		return nullptr;
951c64a3eafSDavid Chisnall 	}
952c64a3eafSDavid Chisnall 	return parse_binary_expression(std::move(lhs));
953c64a3eafSDavid Chisnall }
954c64a3eafSDavid Chisnall 
955c64a3eafSDavid Chisnall bool
consume_integer_expression(unsigned long long & outInt)956bbe31b70SEd Maste text_input_buffer::consume_integer_expression(unsigned long long &outInt)
957c64a3eafSDavid Chisnall {
958bbe31b70SEd Maste 	switch (*(*this))
959c64a3eafSDavid Chisnall 	{
960c64a3eafSDavid Chisnall 		case '(':
961c64a3eafSDavid Chisnall 		{
962c64a3eafSDavid Chisnall 			expression_ptr e(parse_expression(true));
963c64a3eafSDavid Chisnall 			if (!e)
964c64a3eafSDavid Chisnall 			{
965c64a3eafSDavid Chisnall 				return false;
966c64a3eafSDavid Chisnall 			}
967bbe31b70SEd Maste 			auto r = (*e)();
968bbe31b70SEd Maste 			if (r.second)
969bbe31b70SEd Maste 			{
970bbe31b70SEd Maste 				outInt = r.first;
971c64a3eafSDavid Chisnall 				return true;
972c64a3eafSDavid Chisnall 			}
973bbe31b70SEd Maste 			return false;
974bbe31b70SEd Maste 		}
975c64a3eafSDavid Chisnall 		case '0'...'9':
976c64a3eafSDavid Chisnall 			return consume_integer(outInt);
977c64a3eafSDavid Chisnall 		default:
978c64a3eafSDavid Chisnall 			return false;
979c64a3eafSDavid Chisnall 	}
980c64a3eafSDavid Chisnall }
981c64a3eafSDavid Chisnall 
982af0dd31fSDavid Chisnall bool
consume_hex_byte(uint8_t & outByte)983af0dd31fSDavid Chisnall input_buffer::consume_hex_byte(uint8_t &outByte)
984af0dd31fSDavid Chisnall {
985af0dd31fSDavid Chisnall 	if (!ishexdigit((*this)[0]) && !ishexdigit((*this)[1]))
986af0dd31fSDavid Chisnall 	{
987af0dd31fSDavid Chisnall 		return false;
988af0dd31fSDavid Chisnall 	}
989af0dd31fSDavid Chisnall 	outByte = (digittoint((*this)[0]) << 4) | digittoint((*this)[1]);
990af0dd31fSDavid Chisnall 	cursor += 2;
991af0dd31fSDavid Chisnall 	return true;
992af0dd31fSDavid Chisnall }
993af0dd31fSDavid Chisnall 
994bbe31b70SEd Maste text_input_buffer&
next_token()995bbe31b70SEd Maste text_input_buffer::next_token()
996af0dd31fSDavid Chisnall {
997bbe31b70SEd Maste 	auto &self = *this;
998af0dd31fSDavid Chisnall 	int start;
999af0dd31fSDavid Chisnall 	do {
1000af0dd31fSDavid Chisnall 		start = cursor;
1001af0dd31fSDavid Chisnall 		skip_spaces();
1002bbe31b70SEd Maste 		if (finished())
1003bbe31b70SEd Maste 		{
1004bbe31b70SEd Maste 			return self;
1005bbe31b70SEd Maste 		}
1006af0dd31fSDavid Chisnall 		// Parse /* comments
1007bbe31b70SEd Maste 		if (*self == '/' && peek() == '*')
1008af0dd31fSDavid Chisnall 		{
1009af0dd31fSDavid Chisnall 			// eat the start of the comment
1010bbe31b70SEd Maste 			++self;
1011bbe31b70SEd Maste 			++self;
1012af0dd31fSDavid Chisnall 			do {
1013af0dd31fSDavid Chisnall 				// Find the ending * of */
1014bbe31b70SEd Maste 				while ((*self != '\0') && (*self != '*') && !finished())
1015af0dd31fSDavid Chisnall 				{
1016bbe31b70SEd Maste 					++self;
1017af0dd31fSDavid Chisnall 				}
1018af0dd31fSDavid Chisnall 				// Eat the *
1019bbe31b70SEd Maste 				++self;
1020bbe31b70SEd Maste 			} while ((*self != '\0') && (*self != '/') && !finished());
1021af0dd31fSDavid Chisnall 			// Eat the /
1022bbe31b70SEd Maste 			++self;
1023af0dd31fSDavid Chisnall 		}
1024a0706eb4SDavid Chisnall 		// Parse // comments
1025bbe31b70SEd Maste 		if ((*self == '/' && peek() == '/'))
1026af0dd31fSDavid Chisnall 		{
1027af0dd31fSDavid Chisnall 			// eat the start of the comment
1028bbe31b70SEd Maste 			++self;
1029bbe31b70SEd Maste 			++self;
10307f78c173SRui Paulo 			// Find the ending of the line
1031bbe31b70SEd Maste 			while (*self != '\n' && !finished())
1032af0dd31fSDavid Chisnall 			{
1033bbe31b70SEd Maste 				++self;
1034af0dd31fSDavid Chisnall 			}
1035af0dd31fSDavid Chisnall 			// Eat the \n
1036bbe31b70SEd Maste 			++self;
1037af0dd31fSDavid Chisnall 		}
1038af0dd31fSDavid Chisnall 	} while (start != cursor);
1039bbe31b70SEd Maste 	return self;
1040af0dd31fSDavid Chisnall }
1041af0dd31fSDavid Chisnall 
1042af0dd31fSDavid Chisnall void
parse_error(const char * msg)1043bbe31b70SEd Maste text_input_buffer::parse_error(const char *msg)
1044bbe31b70SEd Maste {
1045bbe31b70SEd Maste 	if (input_stack.empty())
1046bbe31b70SEd Maste 	{
1047bbe31b70SEd Maste 		fprintf(stderr, "Error: %s\n", msg);
1048bbe31b70SEd Maste 		return;
1049bbe31b70SEd Maste 	}
1050bbe31b70SEd Maste 	input_buffer &b = *input_stack.top();
1051bbe31b70SEd Maste 	parse_error(msg, b, b.cursor);
1052bbe31b70SEd Maste }
1053bbe31b70SEd Maste void
parse_error(const char * msg,input_buffer & b,int loc)1054bbe31b70SEd Maste text_input_buffer::parse_error(const char *msg,
1055bbe31b70SEd Maste                                input_buffer &b,
1056bbe31b70SEd Maste                                int loc)
1057af0dd31fSDavid Chisnall {
1058af0dd31fSDavid Chisnall 	int line_count = 1;
1059af0dd31fSDavid Chisnall 	int line_start = 0;
1060bbe31b70SEd Maste 	int line_end = loc;
1061bbe31b70SEd Maste 	if (loc < 0 || loc > b.size)
1062af0dd31fSDavid Chisnall 	{
1063bbe31b70SEd Maste 		return;
1064bbe31b70SEd Maste 	}
1065bbe31b70SEd Maste 	for (int i=loc ; i>0 ; --i)
1066bbe31b70SEd Maste 	{
1067bbe31b70SEd Maste 		if (b.buffer[i] == '\n')
1068af0dd31fSDavid Chisnall 		{
1069af0dd31fSDavid Chisnall 			line_count++;
1070af0dd31fSDavid Chisnall 			if (line_start == 0)
1071af0dd31fSDavid Chisnall 			{
1072af0dd31fSDavid Chisnall 				line_start = i+1;
1073af0dd31fSDavid Chisnall 			}
1074af0dd31fSDavid Chisnall 		}
1075af0dd31fSDavid Chisnall 	}
1076bbe31b70SEd Maste 	for (int i=loc+1 ; i<b.size ; ++i)
1077af0dd31fSDavid Chisnall 	{
1078bbe31b70SEd Maste 		if (b.buffer[i] == '\n')
1079af0dd31fSDavid Chisnall 		{
1080af0dd31fSDavid Chisnall 			line_end = i;
1081af0dd31fSDavid Chisnall 			break;
1082af0dd31fSDavid Chisnall 		}
1083af0dd31fSDavid Chisnall 	}
1084bbe31b70SEd Maste 	fprintf(stderr, "Error at %s:%d:%d: %s\n", b.filename().c_str(), line_count, loc - line_start, msg);
1085bbe31b70SEd Maste 	fwrite(&b.buffer[line_start], line_end-line_start, 1, stderr);
1086af0dd31fSDavid Chisnall 	putc('\n', stderr);
1087bbe31b70SEd Maste 	for (int i=0 ; i<(loc-line_start) ; ++i)
1088af0dd31fSDavid Chisnall 	{
1089bbe31b70SEd Maste 		char c = (b.buffer[i+line_start] == '\t') ? '\t' : ' ';
10908d9c8099SDavid Chisnall 		putc(c, stderr);
1091af0dd31fSDavid Chisnall 	}
1092af0dd31fSDavid Chisnall 	putc('^', stderr);
1093af0dd31fSDavid Chisnall 	putc('\n', stderr);
1094af0dd31fSDavid Chisnall }
1095c64a3eafSDavid Chisnall #ifndef NDEBUG
1096af0dd31fSDavid Chisnall void
dump()1097af0dd31fSDavid Chisnall input_buffer::dump()
1098af0dd31fSDavid Chisnall {
1099af0dd31fSDavid Chisnall 	fprintf(stderr, "Current cursor: %d\n", cursor);
1100af0dd31fSDavid Chisnall 	fwrite(&buffer[cursor], size-cursor, 1, stderr);
1101af0dd31fSDavid Chisnall }
1102c64a3eafSDavid Chisnall #endif
1103af0dd31fSDavid Chisnall 
1104bbe31b70SEd Maste 
1105bbe31b70SEd Maste namespace
1106af0dd31fSDavid Chisnall {
1107bbe31b70SEd Maste /**
1108bbe31b70SEd Maste  * The source files are ASCII, so we provide a non-locale-aware version of
1109bbe31b70SEd Maste  * isalpha.  This is a class so that it can be used with a template function
1110bbe31b70SEd Maste  * for parsing strings.
1111bbe31b70SEd Maste  */
1112bbe31b70SEd Maste struct is_alpha
1113af0dd31fSDavid Chisnall {
checkdtc::__anon60f60bea0311::is_alpha1114bbe31b70SEd Maste 	static inline bool check(const char c)
1115bbe31b70SEd Maste 	{
1116bbe31b70SEd Maste 		return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') &&
1117bbe31b70SEd Maste 			(c <= 'Z'));
1118af0dd31fSDavid Chisnall 	}
1119bbe31b70SEd Maste };
1120bbe31b70SEd Maste /**
1121bbe31b70SEd Maste  * Check whether a character is in the set allowed for node names.  This is a
1122bbe31b70SEd Maste  * class so that it can be used with a template function for parsing strings.
1123bbe31b70SEd Maste  */
1124bbe31b70SEd Maste struct is_node_name_character
1125af0dd31fSDavid Chisnall {
checkdtc::__anon60f60bea0311::is_node_name_character1126bbe31b70SEd Maste 	static inline bool check(const char c)
1127bbe31b70SEd Maste 	{
1128bbe31b70SEd Maste 		switch(c)
1129bbe31b70SEd Maste 		{
1130bbe31b70SEd Maste 			default:
1131bbe31b70SEd Maste 				return false;
1132bbe31b70SEd Maste 			case 'a'...'z': case 'A'...'Z': case '0'...'9':
1133bbe31b70SEd Maste 			case ',': case '.': case '+': case '-':
1134bbe31b70SEd Maste 			case '_':
1135bbe31b70SEd Maste 				return true;
1136af0dd31fSDavid Chisnall 		}
1137af0dd31fSDavid Chisnall 	}
1138bbe31b70SEd Maste };
1139bbe31b70SEd Maste /**
1140bbe31b70SEd Maste  * Check whether a character is in the set allowed for property names.  This is
1141bbe31b70SEd Maste  * a class so that it can be used with a template function for parsing strings.
1142bbe31b70SEd Maste  */
1143bbe31b70SEd Maste struct is_property_name_character
1144bbe31b70SEd Maste {
checkdtc::__anon60f60bea0311::is_property_name_character1145bbe31b70SEd Maste 	static inline bool check(const char c)
1146bbe31b70SEd Maste 	{
1147bbe31b70SEd Maste 		switch(c)
1148bbe31b70SEd Maste 		{
1149bbe31b70SEd Maste 			default:
1150bbe31b70SEd Maste 				return false;
1151bbe31b70SEd Maste 			case 'a'...'z': case 'A'...'Z': case '0'...'9':
1152bbe31b70SEd Maste 			case ',': case '.': case '+': case '-':
1153bbe31b70SEd Maste 			case '_': case '#':
1154bbe31b70SEd Maste 				return true;
1155bbe31b70SEd Maste 		}
1156bbe31b70SEd Maste 	}
1157bbe31b70SEd Maste };
1158bbe31b70SEd Maste 
1159bbe31b70SEd Maste template<class T>
parse(text_input_buffer & s)1160bbe31b70SEd Maste string parse(text_input_buffer &s)
1161bbe31b70SEd Maste {
1162bbe31b70SEd Maste 	std::vector<char> bytes;
1163bbe31b70SEd Maste 	for (char c=*s ; T::check(c) ; c=*(++s))
1164bbe31b70SEd Maste 	{
1165bbe31b70SEd Maste 		bytes.push_back(c);
1166bbe31b70SEd Maste 	}
1167bbe31b70SEd Maste 	return string(bytes.begin(), bytes.end());
1168bbe31b70SEd Maste }
1169af0dd31fSDavid Chisnall 
1170af0dd31fSDavid Chisnall }
1171af0dd31fSDavid Chisnall 
1172bbe31b70SEd Maste string
parse_node_name()1173bbe31b70SEd Maste text_input_buffer::parse_node_name()
1174af0dd31fSDavid Chisnall {
1175bbe31b70SEd Maste 	return parse<is_node_name_character>(*this);
1176af0dd31fSDavid Chisnall }
1177bbe31b70SEd Maste 
1178bbe31b70SEd Maste string
parse_property_name()1179bbe31b70SEd Maste text_input_buffer::parse_property_name()
1180bbe31b70SEd Maste {
1181bbe31b70SEd Maste 	return parse<is_property_name_character>(*this);
1182bbe31b70SEd Maste }
1183bbe31b70SEd Maste 
1184bbe31b70SEd Maste string
parse_node_or_property_name(bool & is_property)1185bbe31b70SEd Maste text_input_buffer::parse_node_or_property_name(bool &is_property)
1186bbe31b70SEd Maste {
1187bbe31b70SEd Maste 	if (is_property)
1188bbe31b70SEd Maste 	{
1189bbe31b70SEd Maste 		return parse_property_name();
1190bbe31b70SEd Maste 	}
1191bbe31b70SEd Maste 	std::vector<char> bytes;
1192bbe31b70SEd Maste 	for (char c=*(*this) ; is_node_name_character::check(c) ; c=*(++(*this)))
1193bbe31b70SEd Maste 	{
1194bbe31b70SEd Maste 		bytes.push_back(c);
1195bbe31b70SEd Maste 	}
1196bbe31b70SEd Maste 	for (char c=*(*this) ; is_property_name_character::check(c) ; c=*(++(*this)))
1197bbe31b70SEd Maste 	{
1198bbe31b70SEd Maste 		bytes.push_back(c);
1199bbe31b70SEd Maste 		is_property = true;
1200bbe31b70SEd Maste 	}
1201bbe31b70SEd Maste 	return string(bytes.begin(), bytes.end());
1202bbe31b70SEd Maste }
1203bbe31b70SEd Maste 
1204bbe31b70SEd Maste string
parse_to(char stop)1205bbe31b70SEd Maste input_buffer::parse_to(char stop)
1206bbe31b70SEd Maste {
1207bbe31b70SEd Maste 	std::vector<char> bytes;
1208bbe31b70SEd Maste 	for (char c=*(*this) ; c != stop ; c=*(++(*this)))
1209bbe31b70SEd Maste 	{
1210bbe31b70SEd Maste 		bytes.push_back(c);
1211bbe31b70SEd Maste 	}
1212bbe31b70SEd Maste 	return string(bytes.begin(), bytes.end());
1213bbe31b70SEd Maste }
1214bbe31b70SEd Maste 
1215bbe31b70SEd Maste string
parse_to(char stop)1216bbe31b70SEd Maste text_input_buffer::parse_to(char stop)
1217bbe31b70SEd Maste {
1218bbe31b70SEd Maste 	std::vector<char> bytes;
1219bbe31b70SEd Maste 	for (char c=*(*this) ; c != stop ; c=*(++(*this)))
1220bbe31b70SEd Maste 	{
1221bbe31b70SEd Maste 		if (finished())
1222bbe31b70SEd Maste 		{
1223bbe31b70SEd Maste 			break;
1224bbe31b70SEd Maste 		}
1225bbe31b70SEd Maste 		bytes.push_back(c);
1226bbe31b70SEd Maste 	}
1227bbe31b70SEd Maste 	return string(bytes.begin(), bytes.end());
1228bbe31b70SEd Maste }
1229bbe31b70SEd Maste 
1230bbe31b70SEd Maste char
peek()1231bbe31b70SEd Maste text_input_buffer::peek()
1232bbe31b70SEd Maste {
1233bbe31b70SEd Maste 	return (*input_stack.top())[1];
1234bbe31b70SEd Maste }
1235bbe31b70SEd Maste 
1236bbe31b70SEd Maste std::unique_ptr<input_buffer>
buffer_for_file(const string & path,bool warn)1237bbe31b70SEd Maste input_buffer::buffer_for_file(const string &path, bool warn)
1238bbe31b70SEd Maste {
1239bbe31b70SEd Maste 	if (path == "-")
1240bbe31b70SEd Maste 	{
1241bbe31b70SEd Maste 		std::unique_ptr<input_buffer> b(new stream_input_buffer());
1242bbe31b70SEd Maste 		return b;
1243bbe31b70SEd Maste 	}
1244bbe31b70SEd Maste 	int source = open(path.c_str(), O_RDONLY);
1245bbe31b70SEd Maste 	if (source == -1)
1246bbe31b70SEd Maste 	{
1247bbe31b70SEd Maste 		if (warn)
1248bbe31b70SEd Maste 		{
1249bbe31b70SEd Maste 			fprintf(stderr, "Unable to open file '%s'.  %s\n", path.c_str(), strerror(errno));
1250bbe31b70SEd Maste 		}
1251bbe31b70SEd Maste 		return 0;
1252bbe31b70SEd Maste 	}
1253bbe31b70SEd Maste 	struct stat st;
1254bbe31b70SEd Maste 	if (fstat(source, &st) == 0 && S_ISDIR(st.st_mode))
1255bbe31b70SEd Maste 	{
1256bbe31b70SEd Maste 		if (warn)
1257bbe31b70SEd Maste 		{
1258bbe31b70SEd Maste 			fprintf(stderr, "File %s is a directory\n", path.c_str());
1259bbe31b70SEd Maste 		}
1260bbe31b70SEd Maste 		close(source);
1261bbe31b70SEd Maste 		return 0;
1262bbe31b70SEd Maste 	}
126321d5d37bSEd Maste 	std::unique_ptr<input_buffer> b(new mmap_input_buffer(source, string(path)));
1264bbe31b70SEd Maste 	close(source);
1265bbe31b70SEd Maste 	return b;
1266af0dd31fSDavid Chisnall }
1267af0dd31fSDavid Chisnall 
1268af0dd31fSDavid Chisnall } // namespace dtc
1269af0dd31fSDavid Chisnall 
1270