1245803Stheraven/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
4245803Stheraven * Copyright (c) 2013 David Chisnall
5245803Stheraven * All rights reserved.
6245803Stheraven *
7245803Stheraven * This software was developed by SRI International and the University of
8245803Stheraven * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
9245803Stheraven * ("CTSRD"), as part of the DARPA CRASH research programme.
10245803Stheraven *
11245803Stheraven * Redistribution and use in source and binary forms, with or without
12245803Stheraven * modification, are permitted provided that the following conditions
13245803Stheraven * are met:
14245803Stheraven * 1. Redistributions of source code must retain the above copyright
15245803Stheraven *    notice, this list of conditions and the following disclaimer.
16245803Stheraven * 2. Redistributions in binary form must reproduce the above copyright
17245803Stheraven *    notice, this list of conditions and the following disclaimer in the
18245803Stheraven *    documentation and/or other materials provided with the distribution.
19245803Stheraven *
20245803Stheraven * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21245803Stheraven * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22245803Stheraven * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23245803Stheraven * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24245803Stheraven * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25245803Stheraven * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26245803Stheraven * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27245803Stheraven * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28245803Stheraven * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29245803Stheraven * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30245803Stheraven * SUCH DAMAGE.
31245803Stheraven *
32245803Stheraven * $FreeBSD: stable/11/usr.bin/dtc/input_buffer.hh 330449 2018-03-05 07:26:05Z eadler $
33245803Stheraven */
34245803Stheraven
35245803Stheraven#ifndef _INPUT_BUFFER_HH_
36245803Stheraven#define _INPUT_BUFFER_HH_
37245803Stheraven#include "util.hh"
38245803Stheraven#include <assert.h>
39318093Sgonzo#include <stack>
40318093Sgonzo#include <string>
41318093Sgonzo#include <unordered_set>
42245803Stheraven
43245803Stheravennamespace dtc
44245803Stheraven{
45245803Stheraven
46292876Stheravennamespace {
47292876Stheravenstruct expression;
48292876Stheraventypedef std::unique_ptr<expression> expression_ptr;
49292876Stheraven}
50292876Stheraven
51245803Stheraven/**
52245803Stheraven * Class encapsulating the input file.  Can be used as a const char*, but has
53245803Stheraven * range checking.  Attempting to access anything out of range will return a 0
54245803Stheraven * byte.  The input buffer can be cheaply copied, without copying the
55245803Stheraven * underlying memory, however it is the user's responsibility to ensure that
56245803Stheraven * such copies do not persist beyond the lifetime of the underlying memory.
57245803Stheraven *
58245803Stheraven * This also contains methods for reporting errors and for consuming the token
59245803Stheraven * stream.
60245803Stheraven */
61245803Stheravenclass input_buffer
62245803Stheraven{
63318093Sgonzo	friend class text_input_buffer;
64245803Stheraven	protected:
65245803Stheraven	/**
66245803Stheraven	 * The buffer.  This class doesn't own the buffer, but the
67245803Stheraven	 * mmap_input_buffer subclass does.
68245803Stheraven	 */
69245803Stheraven	const char* buffer;
70245803Stheraven	/**
71245803Stheraven	 * The size of the buffer.
72245803Stheraven	 */
73245803Stheraven	int size;
74245803Stheraven	private:
75245803Stheraven	/**
76245803Stheraven	 * The current place in the buffer where we are reading.  This class
77245803Stheraven	 * keeps a separate size, pointer, and cursor so that we can move
78245803Stheraven	 * forwards and backwards and still have checks that we haven't fallen
79245803Stheraven	 * off either end.
80245803Stheraven	 */
81245803Stheraven	int cursor;
82245803Stheraven	/**
83245803Stheraven	 * Private constructor.  This is used to create input buffers that
84245803Stheraven	 * refer to the same memory, but have different cursors.
85245803Stheraven	 */
86245803Stheraven	input_buffer(const char* b, int s, int c) : buffer(b), size(s),
87245803Stheraven		cursor(c) {}
88318093Sgonzo	public:
89245803Stheraven	/**
90318093Sgonzo	 * Returns the file name associated with this buffer.
91245803Stheraven	 */
92318093Sgonzo	virtual const std::string &filename() const
93318093Sgonzo	{
94318093Sgonzo		static std::string s;
95318093Sgonzo		return s;
96318093Sgonzo	}
97318093Sgonzo	static std::unique_ptr<input_buffer> buffer_for_file(const std::string &path,
98318093Sgonzo	                                                     bool warn=true);
99245803Stheraven	/**
100318093Sgonzo	 * Skips all characters in the input until the specified character is
101318093Sgonzo	 * encountered.
102318093Sgonzo	 */
103318093Sgonzo	void skip_to(char);
104318093Sgonzo	/**
105318093Sgonzo	 * Parses up to a specified character and returns the intervening
106318093Sgonzo	 * characters as a string.
107318093Sgonzo	 */
108318093Sgonzo	std::string parse_to(char);
109318093Sgonzo	/**
110289935Stheraven	 * Return whether all input has been consumed.
111289935Stheraven	 */
112289935Stheraven	bool finished() { return cursor >= size; }
113289935Stheraven	/**
114245803Stheraven	 * Virtual destructor.  Does nothing, but exists so that subclasses
115245803Stheraven	 * that own the memory can run cleanup code for deallocating it.
116245803Stheraven	 */
117245803Stheraven	virtual ~input_buffer() {};
118245803Stheraven	/**
119245803Stheraven	 * Constructs an empty buffer.
120245803Stheraven	 */
121245803Stheraven	input_buffer() : buffer(0), size(0), cursor(0) {}
122245803Stheraven	/**
123245803Stheraven	 * Constructs a new buffer with a specified memory region and size.
124245803Stheraven	 */
125245803Stheraven	input_buffer(const char* b, int s) : buffer(b), size(s), cursor(0){}
126245803Stheraven	/**
127245803Stheraven	 * Returns a new input buffer referring into this input, clamped to the
128245803Stheraven	 * specified size.  If the requested buffer would fall outside the
129245803Stheraven	 * range of this one, then it returns an empty buffer.
130245803Stheraven	 *
131245803Stheraven	 * The returned buffer shares the same underlying storage as the
132245803Stheraven	 * original.  This is intended to be used for splitting up the various
133245803Stheraven	 * sections of a device tree blob.  Requesting a size of 0 will give a
134245803Stheraven	 * buffer that extends to the end of the available memory.
135245803Stheraven	 */
136245803Stheraven	input_buffer buffer_from_offset(int offset, int s=0);
137245803Stheraven	/**
138245803Stheraven	 * Dereferencing operator, allows the buffer to be treated as a char*
139245803Stheraven	 * and dereferenced to give a character.  This returns a null byte if
140245803Stheraven	 * the cursor is out of range.
141245803Stheraven	 */
142245803Stheraven	inline char operator*()
143245803Stheraven	{
144245803Stheraven		if (cursor >= size) { return '\0'; }
145245803Stheraven		if (cursor < 0) { return '\0'; }
146245803Stheraven		return buffer[cursor];
147245803Stheraven	}
148245803Stheraven	/**
149245803Stheraven	 * Array subscripting operator, returns a character at the specified
150245803Stheraven	 * index offset from the current cursor.  The offset may be negative,
151245803Stheraven	 * to reread characters that have already been read.  If the current
152245803Stheraven	 * cursor plus offset is outside of the range, this returns a nul
153245803Stheraven	 * byte.
154245803Stheraven	 */
155245803Stheraven	inline char operator[](int offset)
156245803Stheraven	{
157245803Stheraven		if (cursor + offset >= size) { return '\0'; }
158245803Stheraven		if (cursor + offset < 0) { return '\0'; }
159245803Stheraven		return buffer[cursor + offset];
160245803Stheraven	}
161245803Stheraven	/**
162245803Stheraven	 * Increments the cursor, iterating forward in the buffer.
163245803Stheraven	 */
164245803Stheraven	inline input_buffer &operator++()
165245803Stheraven	{
166245803Stheraven		cursor++;
167245803Stheraven		return *this;
168245803Stheraven	}
169328495Skevans	const char *begin()
170328495Skevans	{
171328495Skevans		return buffer;
172328495Skevans	}
173328495Skevans	const char *end()
174328495Skevans	{
175328495Skevans		return buffer + size;
176328495Skevans	}
177245803Stheraven	/**
178245803Stheraven	 * Consumes a character.  Moves the cursor one character forward if the
179245803Stheraven	 * next character matches the argument, returning true.  If the current
180245803Stheraven	 * character does not match the argument, returns false.
181245803Stheraven	 */
182245803Stheraven	inline bool consume(char c)
183245803Stheraven	{
184318093Sgonzo		if (*(*this) == c)
185245803Stheraven		{
186245803Stheraven			++(*this);
187245803Stheraven			return true;
188245803Stheraven		}
189245803Stheraven		return false;
190245803Stheraven	}
191245803Stheraven	/**
192245803Stheraven	 * Consumes a string.  If the (null-terminated) string passed as the
193245803Stheraven	 * argument appears in the input, advances the cursor to the end and
194245803Stheraven	 * returns true.  Returns false if the string does not appear at the
195245803Stheraven	 * current point in the input.
196245803Stheraven	 */
197245803Stheraven	bool consume(const char *str);
198245803Stheraven	/**
199245803Stheraven	 * Reads an integer in base 8, 10, or 16.  Returns true and advances
200245803Stheraven	 * the cursor to the end of the integer if the cursor points to an
201245803Stheraven	 * integer, returns false and does not move the cursor otherwise.
202245803Stheraven	 *
203245803Stheraven	 * The parsed value is returned via the argument.
204245803Stheraven	 */
205289935Stheraven	bool consume_integer(unsigned long long &outInt);
206245803Stheraven	/**
207292876Stheraven	 * Reads an arithmetic expression (containing any of the normal C
208292876Stheraven	 * operators), evaluates it, and returns the result.
209292876Stheraven	 */
210292876Stheraven	bool consume_integer_expression(unsigned long long &outInt);
211292876Stheraven	/**
212318093Sgonzo	 * Consumes two hex digits and return the resulting byte via the first
213318093Sgonzo	 * argument.  If the next two characters are hex digits, returns true
214318093Sgonzo	 * and advances the cursor.  If not, then returns false and leaves the
215318093Sgonzo	 * cursor in place.
216318093Sgonzo	 */
217318093Sgonzo	bool consume_hex_byte(uint8_t &outByte);
218318093Sgonzo	/**
219245803Stheraven	 * Template function that consumes a binary value in big-endian format
220245803Stheraven	 * from the input stream.  Returns true and advances the cursor if
221245803Stheraven	 * there is a value of the correct size.  This function assumes that
222245803Stheraven	 * all values must be natively aligned, and so advances the cursor to
223245803Stheraven	 * the correct alignment before reading.
224245803Stheraven	 */
225245803Stheraven	template<typename T>
226245803Stheraven	bool consume_binary(T &out)
227245803Stheraven	{
228245803Stheraven		int align = 0;
229245803Stheraven		int type_size = sizeof(T);
230245803Stheraven		if (cursor % type_size != 0)
231245803Stheraven		{
232245803Stheraven			align = type_size - (cursor % type_size);
233245803Stheraven		}
234245803Stheraven		if (size < cursor + align + type_size)
235245803Stheraven		{
236245803Stheraven			return false;
237245803Stheraven		}
238245803Stheraven		cursor += align;
239245803Stheraven		assert(cursor % type_size == 0);
240245803Stheraven		out = 0;
241245803Stheraven		for (int i=0 ; i<type_size ; ++i)
242245803Stheraven		{
243318093Sgonzo			if (size < cursor)
244318093Sgonzo			{
245318093Sgonzo				return false;
246318093Sgonzo			}
247245803Stheraven			out <<= 8;
248245803Stheraven			out |= (((T)buffer[cursor++]) & 0xff);
249245803Stheraven		}
250245803Stheraven		return true;
251245803Stheraven	}
252292876Stheraven#ifndef NDEBUG
253245803Stheraven	/**
254245803Stheraven	 * Dumps the current cursor value and the unconsumed values in the
255245803Stheraven	 * input buffer to the standard error.  This method is intended solely
256245803Stheraven	 * for debugging.
257245803Stheraven	 */
258245803Stheraven	void dump();
259292876Stheraven#endif
260245803Stheraven};
261245803Stheraven/**
262245803Stheraven * Explicit specialisation for reading a single byte.
263245803Stheraven */
264245803Stheraventemplate<>
265245803Stheraveninline bool input_buffer::consume_binary(uint8_t &out)
266245803Stheraven{
267245803Stheraven	if (size < cursor + 1)
268245803Stheraven	{
269245803Stheraven		return false;
270245803Stheraven	}
271245803Stheraven	out = buffer[cursor++];
272245803Stheraven	return true;
273245803Stheraven}
274245803Stheraven
275245803Stheraven/**
276318093Sgonzo * An input buffer subclass used for parsing DTS files.  This manages a stack
277318093Sgonzo * of input buffers to handle /input/ operations.
278245803Stheraven */
279318093Sgonzoclass text_input_buffer
280245803Stheraven{
281318093Sgonzo	std::unordered_set<std::string> defines;
282245803Stheraven	/**
283318093Sgonzo	 * The cursor is the input into the input stream where we are currently reading.
284245803Stheraven	 */
285318093Sgonzo	int cursor = 0;
286245803Stheraven	/**
287318093Sgonzo	 * The current stack of includes.  The current input is always from the top
288318093Sgonzo	 * of the stack.
289245803Stheraven	 */
290318093Sgonzo	std::stack<std::shared_ptr<input_buffer>> input_stack;
291245803Stheraven	/**
292318093Sgonzo	 *
293245803Stheraven	 */
294318093Sgonzo	const std::vector<std::string> include_paths;
295245803Stheraven	/**
296318093Sgonzo	 * Reads forward past any spaces.  The DTS format is not whitespace
297318093Sgonzo	 * sensitive and so we want to scan past whitespace when reading it.
298245803Stheraven	 */
299318093Sgonzo	void skip_spaces();
300318093Sgonzo	/**
301318093Sgonzo	 * Returns the character immediately after the current one.
302318093Sgonzo	 *
303318093Sgonzo	 * This method does not look between files.
304318093Sgonzo	 */
305318093Sgonzo	char peek();
306318093Sgonzo	/**
307318093Sgonzo	 * If a /include/ token is encountered, then look up the corresponding
308318093Sgonzo	 * input file, push it onto the input stack, and continue.
309318093Sgonzo	 */
310318093Sgonzo	void handle_include();
311318093Sgonzo	/**
312318093Sgonzo	 * The base directory for this file.
313318093Sgonzo	 */
314318093Sgonzo	const std::string dir;
315318093Sgonzo	/**
316318093Sgonzo	 * The file where dependencies should be output.
317318093Sgonzo	 */
318318093Sgonzo	FILE *depfile;
319318093Sgonzo	public:
320318093Sgonzo	/**
321318093Sgonzo	 * Construct a new text input buffer with the specified buffer as the start
322318093Sgonzo	 * of parsing and the specified set of input paths for handling new
323318093Sgonzo	 * inclusions.
324318093Sgonzo	 */
325318093Sgonzo	text_input_buffer(std::unique_ptr<input_buffer> &&b,
326318093Sgonzo	                  std::unordered_set<std::string> &&d,
327318093Sgonzo	                  std::vector<std::string> &&i,
328318093Sgonzo	                  const std::string directory,
329318093Sgonzo	                  FILE *deps)
330318093Sgonzo		: defines(d), include_paths(i), dir(directory), depfile(deps)
331318093Sgonzo	{
332318093Sgonzo		input_stack.push(std::move(b));
333318093Sgonzo	}
334318093Sgonzo	/**
335318093Sgonzo	 * Skips all characters in the input until the specified character is
336318093Sgonzo	 * encountered.
337318093Sgonzo	 */
338318093Sgonzo	void skip_to(char);
339318093Sgonzo	/**
340318093Sgonzo	 * Parse an expression.  If `stopAtParen` is set, then only parse a number
341318093Sgonzo	 * or a parenthetical expression, otherwise assume that either is the
342318093Sgonzo	 * left-hand side of a binary expression and try to parse the right-hand
343318093Sgonzo	 * side.
344318093Sgonzo	 */
345318093Sgonzo	expression_ptr parse_expression(bool stopAtParen=false);
346318093Sgonzo	/**
347318093Sgonzo	 * Parse a binary expression, having already parsed the right-hand side.
348318093Sgonzo	 */
349318093Sgonzo	expression_ptr parse_binary_expression(expression_ptr lhs);
350318093Sgonzo	/**
351318093Sgonzo	 * Return whether all input has been consumed.
352318093Sgonzo	 */
353318093Sgonzo	bool finished()
354318093Sgonzo	{
355318093Sgonzo		return input_stack.empty() ||
356318093Sgonzo			((input_stack.size() == 1) && input_stack.top()->finished());
357318093Sgonzo	}
358318093Sgonzo	/**
359318093Sgonzo	 * Dereferencing operator.  Returns the current character in the top input buffer.
360318093Sgonzo	 */
361318093Sgonzo	inline char operator*()
362318093Sgonzo	{
363318093Sgonzo		if (input_stack.empty())
364318093Sgonzo		{
365318093Sgonzo			return 0;
366318093Sgonzo		}
367318093Sgonzo		return *(*input_stack.top());
368318093Sgonzo	}
369318093Sgonzo	/**
370318093Sgonzo	 * Increments the cursor, iterating forward in the buffer.
371318093Sgonzo	 */
372318093Sgonzo	inline text_input_buffer &operator++()
373318093Sgonzo	{
374318093Sgonzo		if (input_stack.empty())
375318093Sgonzo		{
376318093Sgonzo			return *this;
377318093Sgonzo		}
378318093Sgonzo		cursor++;
379318093Sgonzo		auto &top = *input_stack.top();
380318093Sgonzo		++top;
381318093Sgonzo		if (top.finished())
382318093Sgonzo		{
383318093Sgonzo			input_stack.pop();
384318093Sgonzo		}
385318093Sgonzo		return *this;
386318093Sgonzo	}
387318093Sgonzo	/**
388318093Sgonzo	 * Consumes a character.  Moves the cursor one character forward if the
389318093Sgonzo	 * next character matches the argument, returning true.  If the current
390318093Sgonzo	 * character does not match the argument, returns false.
391318093Sgonzo	 */
392318093Sgonzo	inline bool consume(char c)
393318093Sgonzo	{
394318093Sgonzo		if (*(*this) == c)
395318093Sgonzo		{
396318093Sgonzo			++(*this);
397318093Sgonzo			return true;
398318093Sgonzo		}
399318093Sgonzo		return false;
400318093Sgonzo	}
401318093Sgonzo	/**
402318093Sgonzo	 * Consumes a string.  If the (null-terminated) string passed as the
403318093Sgonzo	 * argument appears in the input, advances the cursor to the end and
404318093Sgonzo	 * returns true.  Returns false if the string does not appear at the
405318093Sgonzo	 * current point in the input.
406318093Sgonzo	 *
407318093Sgonzo	 * This method does not scan between files.
408318093Sgonzo	 */
409318093Sgonzo	bool consume(const char *str)
410318093Sgonzo	{
411318093Sgonzo		if (input_stack.empty())
412318093Sgonzo		{
413318093Sgonzo			return false;
414318093Sgonzo		}
415318093Sgonzo		return input_stack.top()->consume(str);
416318093Sgonzo	}
417318093Sgonzo	/**
418318093Sgonzo	 * Reads an integer in base 8, 10, or 16.  Returns true and advances
419318093Sgonzo	 * the cursor to the end of the integer if the cursor points to an
420318093Sgonzo	 * integer, returns false and does not move the cursor otherwise.
421318093Sgonzo	 *
422318093Sgonzo	 * The parsed value is returned via the argument.
423318093Sgonzo	 *
424318093Sgonzo	 * This method does not scan between files.
425318093Sgonzo	 */
426318093Sgonzo	bool consume_integer(unsigned long long &outInt)
427318093Sgonzo	{
428318093Sgonzo		if (input_stack.empty())
429318093Sgonzo		{
430318093Sgonzo			return false;
431318093Sgonzo		}
432318093Sgonzo		return input_stack.top()->consume_integer(outInt);
433318093Sgonzo	}
434318093Sgonzo	/**
435318093Sgonzo	 * Reads an arithmetic expression (containing any of the normal C
436318093Sgonzo	 * operators), evaluates it, and returns the result.
437318093Sgonzo	 */
438318093Sgonzo	bool consume_integer_expression(unsigned long long &outInt);
439318093Sgonzo	/**
440318093Sgonzo	 * Consumes two hex digits and return the resulting byte via the first
441318093Sgonzo	 * argument.  If the next two characters are hex digits, returns true
442318093Sgonzo	 * and advances the cursor.  If not, then returns false and leaves the
443318093Sgonzo	 * cursor in place.
444318093Sgonzo	 *
445318093Sgonzo	 * This method does not scan between files.
446318093Sgonzo	 */
447318093Sgonzo	bool consume_hex_byte(uint8_t &outByte)
448318093Sgonzo	{
449318093Sgonzo		if (input_stack.empty())
450318093Sgonzo		{
451318093Sgonzo			return false;
452318093Sgonzo		}
453318093Sgonzo		return input_stack.top()->consume_hex_byte(outByte);
454318093Sgonzo	}
455318093Sgonzo	/**
456318093Sgonzo	 * Returns the longest string in the input buffer starting at the
457318093Sgonzo	 * current cursor and composed entirely of characters that are valid in
458318093Sgonzo	 * node names.
459318093Sgonzo	*/
460318093Sgonzo	std::string parse_node_name();
461318093Sgonzo	/**
462318093Sgonzo	 * Returns the longest string in the input buffer starting at the
463318093Sgonzo	 * current cursor and composed entirely of characters that are valid in
464318093Sgonzo	 * property names.
465318093Sgonzo	 */
466318093Sgonzo	std::string parse_property_name();
467318093Sgonzo	/**
468318093Sgonzo	 * Parses either a node or a property name.  If is_property is true on
469318093Sgonzo	 * entry, then only property names are parsed.  If it is false, then it
470318093Sgonzo	 * will be set, on return, to indicate whether the parsed name is only
471318093Sgonzo	 * valid as a property.
472318093Sgonzo	 */
473318093Sgonzo	std::string parse_node_or_property_name(bool &is_property);
474318093Sgonzo	/**
475318093Sgonzo	 * Parses up to a specified character and returns the intervening
476318093Sgonzo	 * characters as a string.
477318093Sgonzo	 */
478318093Sgonzo	std::string parse_to(char);
479318093Sgonzo	/**
480318093Sgonzo	 * Advances the cursor to the start of the next token, skipping
481318093Sgonzo	 * comments and whitespace.  If the cursor already points to the start
482318093Sgonzo	 * of a token, then this function does nothing.
483318093Sgonzo	 */
484318093Sgonzo	text_input_buffer &next_token();
485318093Sgonzo	/**
486318093Sgonzo	 * Location in the source file.  This should never be interpreted by
487318093Sgonzo	 * anything other than error reporting functions of this class.  It will
488318093Sgonzo	 * eventually become something more complex than an `int`.
489318093Sgonzo	 */
490318093Sgonzo	class source_location
491318093Sgonzo	{
492318093Sgonzo		friend class text_input_buffer;
493318093Sgonzo		/**
494318093Sgonzo		 * The text buffer object that included `b`.
495318093Sgonzo		 */
496318093Sgonzo		text_input_buffer &buffer;
497318093Sgonzo		/**
498318093Sgonzo		 * The underlying buffer that contains this location.
499318093Sgonzo		 */
500318093Sgonzo		std::shared_ptr<input_buffer> b;
501318093Sgonzo		/**
502318093Sgonzo		 * The offset within the current buffer of the source location.
503318093Sgonzo		 */
504318093Sgonzo		int cursor;
505318093Sgonzo		source_location(text_input_buffer &buf)
506318093Sgonzo			: buffer(buf),
507318093Sgonzo			  b(buf.input_stack.empty() ? nullptr : buf.input_stack.top()),
508318093Sgonzo			  cursor(b ? b->cursor : 0) {}
509318093Sgonzo		public:
510318093Sgonzo		/**
511318093Sgonzo		 * Report an error at this location.
512318093Sgonzo		 */
513318093Sgonzo		void report_error(const char *msg)
514318093Sgonzo		{
515318093Sgonzo			if (b)
516318093Sgonzo			{
517318093Sgonzo				buffer.parse_error(msg, *b, cursor);
518318093Sgonzo			}
519318093Sgonzo			else
520318093Sgonzo			{
521318093Sgonzo				buffer.parse_error(msg);
522318093Sgonzo			}
523318093Sgonzo		}
524318093Sgonzo	};
525318093Sgonzo	/**
526318093Sgonzo	 * Returns the current source location.
527318093Sgonzo	 */
528318093Sgonzo	source_location location()
529318093Sgonzo	{
530318093Sgonzo		return { *this };
531318093Sgonzo	}
532318093Sgonzo	/**
533318093Sgonzo	 * Prints a message indicating the location of a parse error.
534318093Sgonzo	 */
535318093Sgonzo	void parse_error(const char *msg);
536328495Skevans	/**
537328495Skevans	 * Reads the contents of a binary file into `b`.  The file name is assumed
538328495Skevans	 * to be relative to one of the include paths.
539328495Skevans	 *
540328495Skevans	 * Returns true if the file exists and can be read, false otherwise.
541328495Skevans	 */
542328495Skevans	bool read_binary_file(const std::string &filename, byte_buffer &b);
543318093Sgonzo	private:
544318093Sgonzo	/**
545318093Sgonzo	 * Prints a message indicating the location of a parse error, given a
546318093Sgonzo	 * specified location.  This is used when input has already moved beyond
547318093Sgonzo	 * the location that caused the failure.
548318093Sgonzo	 */
549318093Sgonzo	void parse_error(const char *msg, input_buffer &b, int loc);
550245803Stheraven};
551245803Stheraven
552245803Stheraven} // namespace dtc
553245803Stheraven
554245803Stheraven#endif // !_INPUT_BUFFER_HH_
555