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 #ifndef _INPUT_BUFFER_HH_
34af0dd31fSDavid Chisnall #define _INPUT_BUFFER_HH_
35af0dd31fSDavid Chisnall #include "util.hh"
36af0dd31fSDavid Chisnall #include <assert.h>
37bbe31b70SEd Maste #include <stack>
38bbe31b70SEd Maste #include <string>
39bbe31b70SEd Maste #include <unordered_set>
40af0dd31fSDavid Chisnall
41af0dd31fSDavid Chisnall namespace dtc
42af0dd31fSDavid Chisnall {
43af0dd31fSDavid Chisnall
44c64a3eafSDavid Chisnall namespace {
45c64a3eafSDavid Chisnall struct expression;
46c64a3eafSDavid Chisnall typedef std::unique_ptr<expression> expression_ptr;
47c64a3eafSDavid Chisnall }
48c64a3eafSDavid Chisnall
49af0dd31fSDavid Chisnall /**
50af0dd31fSDavid Chisnall * Class encapsulating the input file. Can be used as a const char*, but has
51af0dd31fSDavid Chisnall * range checking. Attempting to access anything out of range will return a 0
52af0dd31fSDavid Chisnall * byte. The input buffer can be cheaply copied, without copying the
53af0dd31fSDavid Chisnall * underlying memory, however it is the user's responsibility to ensure that
54af0dd31fSDavid Chisnall * such copies do not persist beyond the lifetime of the underlying memory.
55af0dd31fSDavid Chisnall *
56af0dd31fSDavid Chisnall * This also contains methods for reporting errors and for consuming the token
57af0dd31fSDavid Chisnall * stream.
58af0dd31fSDavid Chisnall */
59af0dd31fSDavid Chisnall class input_buffer
60af0dd31fSDavid Chisnall {
61bbe31b70SEd Maste friend class text_input_buffer;
62af0dd31fSDavid Chisnall protected:
63af0dd31fSDavid Chisnall /**
64af0dd31fSDavid Chisnall * The buffer. This class doesn't own the buffer, but the
65af0dd31fSDavid Chisnall * mmap_input_buffer subclass does.
66af0dd31fSDavid Chisnall */
67af0dd31fSDavid Chisnall const char* buffer;
68af0dd31fSDavid Chisnall /**
69af0dd31fSDavid Chisnall * The size of the buffer.
70af0dd31fSDavid Chisnall */
71af0dd31fSDavid Chisnall int size;
72af0dd31fSDavid Chisnall private:
73af0dd31fSDavid Chisnall /**
74af0dd31fSDavid Chisnall * The current place in the buffer where we are reading. This class
75af0dd31fSDavid Chisnall * keeps a separate size, pointer, and cursor so that we can move
76af0dd31fSDavid Chisnall * forwards and backwards and still have checks that we haven't fallen
77af0dd31fSDavid Chisnall * off either end.
78af0dd31fSDavid Chisnall */
79af0dd31fSDavid Chisnall int cursor;
80af0dd31fSDavid Chisnall /**
81af0dd31fSDavid Chisnall * Private constructor. This is used to create input buffers that
82af0dd31fSDavid Chisnall * refer to the same memory, but have different cursors.
83af0dd31fSDavid Chisnall */
input_buffer(const char * b,int s,int c)84af0dd31fSDavid Chisnall input_buffer(const char* b, int s, int c) : buffer(b), size(s),
85af0dd31fSDavid Chisnall cursor(c) {}
86af0dd31fSDavid Chisnall public:
87af0dd31fSDavid Chisnall /**
88bbe31b70SEd Maste * Returns the file name associated with this buffer.
89bbe31b70SEd Maste */
filename() const90bbe31b70SEd Maste virtual const std::string &filename() const
91bbe31b70SEd Maste {
92bbe31b70SEd Maste static std::string s;
93bbe31b70SEd Maste return s;
94bbe31b70SEd Maste }
95bbe31b70SEd Maste static std::unique_ptr<input_buffer> buffer_for_file(const std::string &path,
96bbe31b70SEd Maste bool warn=true);
97bbe31b70SEd Maste /**
98bbe31b70SEd Maste * Skips all characters in the input until the specified character is
99bbe31b70SEd Maste * encountered.
100bbe31b70SEd Maste */
101bbe31b70SEd Maste void skip_to(char);
102bbe31b70SEd Maste /**
103bbe31b70SEd Maste * Parses up to a specified character and returns the intervening
104bbe31b70SEd Maste * characters as a string.
105bbe31b70SEd Maste */
106bbe31b70SEd Maste std::string parse_to(char);
107bbe31b70SEd Maste /**
108a0706eb4SDavid Chisnall * Return whether all input has been consumed.
109a0706eb4SDavid Chisnall */
finished()110a0706eb4SDavid Chisnall bool finished() { return cursor >= size; }
111a0706eb4SDavid Chisnall /**
112af0dd31fSDavid Chisnall * Virtual destructor. Does nothing, but exists so that subclasses
113af0dd31fSDavid Chisnall * that own the memory can run cleanup code for deallocating it.
114af0dd31fSDavid Chisnall */
~input_buffer()115af0dd31fSDavid Chisnall virtual ~input_buffer() {};
116af0dd31fSDavid Chisnall /**
117af0dd31fSDavid Chisnall * Constructs an empty buffer.
118af0dd31fSDavid Chisnall */
input_buffer()119af0dd31fSDavid Chisnall input_buffer() : buffer(0), size(0), cursor(0) {}
120af0dd31fSDavid Chisnall /**
121af0dd31fSDavid Chisnall * Constructs a new buffer with a specified memory region and size.
122af0dd31fSDavid Chisnall */
input_buffer(const char * b,int s)123af0dd31fSDavid Chisnall input_buffer(const char* b, int s) : buffer(b), size(s), cursor(0){}
124af0dd31fSDavid Chisnall /**
125af0dd31fSDavid Chisnall * Returns a new input buffer referring into this input, clamped to the
126af0dd31fSDavid Chisnall * specified size. If the requested buffer would fall outside the
127af0dd31fSDavid Chisnall * range of this one, then it returns an empty buffer.
128af0dd31fSDavid Chisnall *
129af0dd31fSDavid Chisnall * The returned buffer shares the same underlying storage as the
130af0dd31fSDavid Chisnall * original. This is intended to be used for splitting up the various
131af0dd31fSDavid Chisnall * sections of a device tree blob. Requesting a size of 0 will give a
132af0dd31fSDavid Chisnall * buffer that extends to the end of the available memory.
133af0dd31fSDavid Chisnall */
134af0dd31fSDavid Chisnall input_buffer buffer_from_offset(int offset, int s=0);
135af0dd31fSDavid Chisnall /**
136af0dd31fSDavid Chisnall * Dereferencing operator, allows the buffer to be treated as a char*
137af0dd31fSDavid Chisnall * and dereferenced to give a character. This returns a null byte if
138af0dd31fSDavid Chisnall * the cursor is out of range.
139af0dd31fSDavid Chisnall */
operator *()140af0dd31fSDavid Chisnall inline char operator*()
141af0dd31fSDavid Chisnall {
142af0dd31fSDavid Chisnall if (cursor >= size) { return '\0'; }
143af0dd31fSDavid Chisnall if (cursor < 0) { return '\0'; }
144af0dd31fSDavid Chisnall return buffer[cursor];
145af0dd31fSDavid Chisnall }
146af0dd31fSDavid Chisnall /**
147af0dd31fSDavid Chisnall * Array subscripting operator, returns a character at the specified
148af0dd31fSDavid Chisnall * index offset from the current cursor. The offset may be negative,
149af0dd31fSDavid Chisnall * to reread characters that have already been read. If the current
150af0dd31fSDavid Chisnall * cursor plus offset is outside of the range, this returns a nul
151af0dd31fSDavid Chisnall * byte.
152af0dd31fSDavid Chisnall */
operator [](int offset)153af0dd31fSDavid Chisnall inline char operator[](int offset)
154af0dd31fSDavid Chisnall {
155af0dd31fSDavid Chisnall if (cursor + offset >= size) { return '\0'; }
156af0dd31fSDavid Chisnall if (cursor + offset < 0) { return '\0'; }
157af0dd31fSDavid Chisnall return buffer[cursor + offset];
158af0dd31fSDavid Chisnall }
159af0dd31fSDavid Chisnall /**
160af0dd31fSDavid Chisnall * Increments the cursor, iterating forward in the buffer.
161af0dd31fSDavid Chisnall */
operator ++()162af0dd31fSDavid Chisnall inline input_buffer &operator++()
163af0dd31fSDavid Chisnall {
164af0dd31fSDavid Chisnall cursor++;
165af0dd31fSDavid Chisnall return *this;
166af0dd31fSDavid Chisnall }
begin()167ca84c67cSKyle Evans const char *begin()
168ca84c67cSKyle Evans {
169ca84c67cSKyle Evans return buffer;
170ca84c67cSKyle Evans }
end()171ca84c67cSKyle Evans const char *end()
172ca84c67cSKyle Evans {
173ca84c67cSKyle Evans return buffer + size;
174ca84c67cSKyle Evans }
175af0dd31fSDavid Chisnall /**
176af0dd31fSDavid Chisnall * Consumes a character. Moves the cursor one character forward if the
177af0dd31fSDavid Chisnall * next character matches the argument, returning true. If the current
178af0dd31fSDavid Chisnall * character does not match the argument, returns false.
179af0dd31fSDavid Chisnall */
consume(char c)180af0dd31fSDavid Chisnall inline bool consume(char c)
181af0dd31fSDavid Chisnall {
182bbe31b70SEd Maste if (*(*this) == c)
183af0dd31fSDavid Chisnall {
184af0dd31fSDavid Chisnall ++(*this);
185af0dd31fSDavid Chisnall return true;
186af0dd31fSDavid Chisnall }
187af0dd31fSDavid Chisnall return false;
188af0dd31fSDavid Chisnall }
189af0dd31fSDavid Chisnall /**
190af0dd31fSDavid Chisnall * Consumes a string. If the (null-terminated) string passed as the
191af0dd31fSDavid Chisnall * argument appears in the input, advances the cursor to the end and
192af0dd31fSDavid Chisnall * returns true. Returns false if the string does not appear at the
193af0dd31fSDavid Chisnall * current point in the input.
194af0dd31fSDavid Chisnall */
195af0dd31fSDavid Chisnall bool consume(const char *str);
196af0dd31fSDavid Chisnall /**
197af0dd31fSDavid Chisnall * Reads an integer in base 8, 10, or 16. Returns true and advances
198af0dd31fSDavid Chisnall * the cursor to the end of the integer if the cursor points to an
199af0dd31fSDavid Chisnall * integer, returns false and does not move the cursor otherwise.
200af0dd31fSDavid Chisnall *
201af0dd31fSDavid Chisnall * The parsed value is returned via the argument.
202af0dd31fSDavid Chisnall */
203a0706eb4SDavid Chisnall bool consume_integer(unsigned long long &outInt);
204af0dd31fSDavid Chisnall /**
205c64a3eafSDavid Chisnall * Reads an arithmetic expression (containing any of the normal C
206c64a3eafSDavid Chisnall * operators), evaluates it, and returns the result.
207c64a3eafSDavid Chisnall */
208c64a3eafSDavid Chisnall bool consume_integer_expression(unsigned long long &outInt);
209c64a3eafSDavid Chisnall /**
210bbe31b70SEd Maste * Consumes two hex digits and return the resulting byte via the first
211bbe31b70SEd Maste * argument. If the next two characters are hex digits, returns true
212bbe31b70SEd Maste * and advances the cursor. If not, then returns false and leaves the
213bbe31b70SEd Maste * cursor in place.
214bbe31b70SEd Maste */
215bbe31b70SEd Maste bool consume_hex_byte(uint8_t &outByte);
216bbe31b70SEd Maste /**
217af0dd31fSDavid Chisnall * Template function that consumes a binary value in big-endian format
218af0dd31fSDavid Chisnall * from the input stream. Returns true and advances the cursor if
219af0dd31fSDavid Chisnall * there is a value of the correct size. This function assumes that
220af0dd31fSDavid Chisnall * all values must be natively aligned, and so advances the cursor to
221af0dd31fSDavid Chisnall * the correct alignment before reading.
222af0dd31fSDavid Chisnall */
223af0dd31fSDavid Chisnall template<typename T>
consume_binary(T & out)224af0dd31fSDavid Chisnall bool consume_binary(T &out)
225af0dd31fSDavid Chisnall {
226af0dd31fSDavid Chisnall int align = 0;
227af0dd31fSDavid Chisnall int type_size = sizeof(T);
228af0dd31fSDavid Chisnall if (cursor % type_size != 0)
229af0dd31fSDavid Chisnall {
230af0dd31fSDavid Chisnall align = type_size - (cursor % type_size);
231af0dd31fSDavid Chisnall }
232af0dd31fSDavid Chisnall if (size < cursor + align + type_size)
233af0dd31fSDavid Chisnall {
234af0dd31fSDavid Chisnall return false;
235af0dd31fSDavid Chisnall }
236af0dd31fSDavid Chisnall cursor += align;
237af0dd31fSDavid Chisnall assert(cursor % type_size == 0);
238af0dd31fSDavid Chisnall out = 0;
239af0dd31fSDavid Chisnall for (int i=0 ; i<type_size ; ++i)
240af0dd31fSDavid Chisnall {
241bbe31b70SEd Maste if (size < cursor)
242bbe31b70SEd Maste {
243bbe31b70SEd Maste return false;
244bbe31b70SEd Maste }
245af0dd31fSDavid Chisnall out <<= 8;
246af0dd31fSDavid Chisnall out |= (((T)buffer[cursor++]) & 0xff);
247af0dd31fSDavid Chisnall }
248af0dd31fSDavid Chisnall return true;
249af0dd31fSDavid Chisnall }
250c64a3eafSDavid Chisnall #ifndef NDEBUG
251af0dd31fSDavid Chisnall /**
252af0dd31fSDavid Chisnall * Dumps the current cursor value and the unconsumed values in the
253af0dd31fSDavid Chisnall * input buffer to the standard error. This method is intended solely
254af0dd31fSDavid Chisnall * for debugging.
255af0dd31fSDavid Chisnall */
256af0dd31fSDavid Chisnall void dump();
257c64a3eafSDavid Chisnall #endif
258af0dd31fSDavid Chisnall };
259af0dd31fSDavid Chisnall /**
260af0dd31fSDavid Chisnall * Explicit specialisation for reading a single byte.
261af0dd31fSDavid Chisnall */
262af0dd31fSDavid Chisnall template<>
consume_binary(uint8_t & out)263af0dd31fSDavid Chisnall inline bool input_buffer::consume_binary(uint8_t &out)
264af0dd31fSDavid Chisnall {
265af0dd31fSDavid Chisnall if (size < cursor + 1)
266af0dd31fSDavid Chisnall {
267af0dd31fSDavid Chisnall return false;
268af0dd31fSDavid Chisnall }
269af0dd31fSDavid Chisnall out = buffer[cursor++];
270af0dd31fSDavid Chisnall return true;
271af0dd31fSDavid Chisnall }
272af0dd31fSDavid Chisnall
273af0dd31fSDavid Chisnall /**
274bbe31b70SEd Maste * An input buffer subclass used for parsing DTS files. This manages a stack
275bbe31b70SEd Maste * of input buffers to handle /input/ operations.
276af0dd31fSDavid Chisnall */
277bbe31b70SEd Maste class text_input_buffer
278af0dd31fSDavid Chisnall {
279bbe31b70SEd Maste std::unordered_set<std::string> defines;
280af0dd31fSDavid Chisnall /**
281bbe31b70SEd Maste * The cursor is the input into the input stream where we are currently reading.
282af0dd31fSDavid Chisnall */
283bbe31b70SEd Maste int cursor = 0;
284af0dd31fSDavid Chisnall /**
285bbe31b70SEd Maste * The current stack of includes. The current input is always from the top
286bbe31b70SEd Maste * of the stack.
287af0dd31fSDavid Chisnall */
288bbe31b70SEd Maste std::stack<std::shared_ptr<input_buffer>> input_stack;
289bbe31b70SEd Maste /**
290bbe31b70SEd Maste *
291bbe31b70SEd Maste */
292bbe31b70SEd Maste const std::vector<std::string> include_paths;
293bbe31b70SEd Maste /**
294bbe31b70SEd Maste * Reads forward past any spaces. The DTS format is not whitespace
295bbe31b70SEd Maste * sensitive and so we want to scan past whitespace when reading it.
296bbe31b70SEd Maste */
297bbe31b70SEd Maste void skip_spaces();
298bbe31b70SEd Maste /**
299bbe31b70SEd Maste * Returns the character immediately after the current one.
300bbe31b70SEd Maste *
301bbe31b70SEd Maste * This method does not look between files.
302bbe31b70SEd Maste */
303bbe31b70SEd Maste char peek();
304bbe31b70SEd Maste /**
305bbe31b70SEd Maste * If a /include/ token is encountered, then look up the corresponding
306bbe31b70SEd Maste * input file, push it onto the input stack, and continue.
307bbe31b70SEd Maste */
308bbe31b70SEd Maste void handle_include();
309bbe31b70SEd Maste /**
310bbe31b70SEd Maste * The base directory for this file.
311bbe31b70SEd Maste */
312bbe31b70SEd Maste const std::string dir;
313bbe31b70SEd Maste /**
314bbe31b70SEd Maste * The file where dependencies should be output.
315bbe31b70SEd Maste */
316bbe31b70SEd Maste FILE *depfile;
317bbe31b70SEd Maste public:
318bbe31b70SEd Maste /**
319bbe31b70SEd Maste * Construct a new text input buffer with the specified buffer as the start
320bbe31b70SEd Maste * of parsing and the specified set of input paths for handling new
321bbe31b70SEd Maste * inclusions.
322bbe31b70SEd Maste */
text_input_buffer(std::unique_ptr<input_buffer> && b,std::unordered_set<std::string> && d,std::vector<std::string> && i,const std::string directory,FILE * deps)323bbe31b70SEd Maste text_input_buffer(std::unique_ptr<input_buffer> &&b,
324bbe31b70SEd Maste std::unordered_set<std::string> &&d,
325bbe31b70SEd Maste std::vector<std::string> &&i,
326bbe31b70SEd Maste const std::string directory,
327bbe31b70SEd Maste FILE *deps)
328bbe31b70SEd Maste : defines(d), include_paths(i), dir(directory), depfile(deps)
329bbe31b70SEd Maste {
330bbe31b70SEd Maste input_stack.push(std::move(b));
331bbe31b70SEd Maste }
332bbe31b70SEd Maste /**
333bbe31b70SEd Maste * Skips all characters in the input until the specified character is
334bbe31b70SEd Maste * encountered.
335bbe31b70SEd Maste */
336bbe31b70SEd Maste void skip_to(char);
337bbe31b70SEd Maste /**
338bbe31b70SEd Maste * Parse an expression. If `stopAtParen` is set, then only parse a number
339bbe31b70SEd Maste * or a parenthetical expression, otherwise assume that either is the
340bbe31b70SEd Maste * left-hand side of a binary expression and try to parse the right-hand
341bbe31b70SEd Maste * side.
342bbe31b70SEd Maste */
343bbe31b70SEd Maste expression_ptr parse_expression(bool stopAtParen=false);
344bbe31b70SEd Maste /**
345bbe31b70SEd Maste * Parse a binary expression, having already parsed the right-hand side.
346bbe31b70SEd Maste */
347bbe31b70SEd Maste expression_ptr parse_binary_expression(expression_ptr lhs);
348bbe31b70SEd Maste /**
349bbe31b70SEd Maste * Return whether all input has been consumed.
350bbe31b70SEd Maste */
finished()351bbe31b70SEd Maste bool finished()
352bbe31b70SEd Maste {
353bbe31b70SEd Maste return input_stack.empty() ||
354bbe31b70SEd Maste ((input_stack.size() == 1) && input_stack.top()->finished());
355bbe31b70SEd Maste }
356bbe31b70SEd Maste /**
357bbe31b70SEd Maste * Dereferencing operator. Returns the current character in the top input buffer.
358bbe31b70SEd Maste */
operator *()359bbe31b70SEd Maste inline char operator*()
360bbe31b70SEd Maste {
361bbe31b70SEd Maste if (input_stack.empty())
362bbe31b70SEd Maste {
363bbe31b70SEd Maste return 0;
364bbe31b70SEd Maste }
365bbe31b70SEd Maste return *(*input_stack.top());
366bbe31b70SEd Maste }
367bbe31b70SEd Maste /**
368bbe31b70SEd Maste * Increments the cursor, iterating forward in the buffer.
369bbe31b70SEd Maste */
operator ++()370bbe31b70SEd Maste inline text_input_buffer &operator++()
371bbe31b70SEd Maste {
372bbe31b70SEd Maste if (input_stack.empty())
373bbe31b70SEd Maste {
374bbe31b70SEd Maste return *this;
375bbe31b70SEd Maste }
376bbe31b70SEd Maste cursor++;
377bbe31b70SEd Maste auto &top = *input_stack.top();
378bbe31b70SEd Maste ++top;
379bbe31b70SEd Maste if (top.finished())
380bbe31b70SEd Maste {
381bbe31b70SEd Maste input_stack.pop();
382bbe31b70SEd Maste }
383bbe31b70SEd Maste return *this;
384bbe31b70SEd Maste }
385bbe31b70SEd Maste /**
386bbe31b70SEd Maste * Consumes a character. Moves the cursor one character forward if the
387bbe31b70SEd Maste * next character matches the argument, returning true. If the current
388bbe31b70SEd Maste * character does not match the argument, returns false.
389bbe31b70SEd Maste */
consume(char c)390bbe31b70SEd Maste inline bool consume(char c)
391bbe31b70SEd Maste {
392bbe31b70SEd Maste if (*(*this) == c)
393bbe31b70SEd Maste {
394bbe31b70SEd Maste ++(*this);
395bbe31b70SEd Maste return true;
396bbe31b70SEd Maste }
397bbe31b70SEd Maste return false;
398bbe31b70SEd Maste }
399bbe31b70SEd Maste /**
400bbe31b70SEd Maste * Consumes a string. If the (null-terminated) string passed as the
401bbe31b70SEd Maste * argument appears in the input, advances the cursor to the end and
402bbe31b70SEd Maste * returns true. Returns false if the string does not appear at the
403bbe31b70SEd Maste * current point in the input.
404bbe31b70SEd Maste *
405bbe31b70SEd Maste * This method does not scan between files.
406bbe31b70SEd Maste */
consume(const char * str)407bbe31b70SEd Maste bool consume(const char *str)
408bbe31b70SEd Maste {
409bbe31b70SEd Maste if (input_stack.empty())
410bbe31b70SEd Maste {
411bbe31b70SEd Maste return false;
412bbe31b70SEd Maste }
413bbe31b70SEd Maste return input_stack.top()->consume(str);
414bbe31b70SEd Maste }
415bbe31b70SEd Maste /**
416bbe31b70SEd Maste * Reads an integer in base 8, 10, or 16. Returns true and advances
417bbe31b70SEd Maste * the cursor to the end of the integer if the cursor points to an
418bbe31b70SEd Maste * integer, returns false and does not move the cursor otherwise.
419bbe31b70SEd Maste *
420bbe31b70SEd Maste * The parsed value is returned via the argument.
421bbe31b70SEd Maste *
422bbe31b70SEd Maste * This method does not scan between files.
423bbe31b70SEd Maste */
consume_integer(unsigned long long & outInt)424bbe31b70SEd Maste bool consume_integer(unsigned long long &outInt)
425bbe31b70SEd Maste {
426bbe31b70SEd Maste if (input_stack.empty())
427bbe31b70SEd Maste {
428bbe31b70SEd Maste return false;
429bbe31b70SEd Maste }
430bbe31b70SEd Maste return input_stack.top()->consume_integer(outInt);
431bbe31b70SEd Maste }
432bbe31b70SEd Maste /**
433bbe31b70SEd Maste * Reads an arithmetic expression (containing any of the normal C
434bbe31b70SEd Maste * operators), evaluates it, and returns the result.
435bbe31b70SEd Maste */
436bbe31b70SEd Maste bool consume_integer_expression(unsigned long long &outInt);
437bbe31b70SEd Maste /**
438bbe31b70SEd Maste * Consumes two hex digits and return the resulting byte via the first
439bbe31b70SEd Maste * argument. If the next two characters are hex digits, returns true
440bbe31b70SEd Maste * and advances the cursor. If not, then returns false and leaves the
441bbe31b70SEd Maste * cursor in place.
442bbe31b70SEd Maste *
443bbe31b70SEd Maste * This method does not scan between files.
444bbe31b70SEd Maste */
consume_hex_byte(uint8_t & outByte)445bbe31b70SEd Maste bool consume_hex_byte(uint8_t &outByte)
446bbe31b70SEd Maste {
447bbe31b70SEd Maste if (input_stack.empty())
448bbe31b70SEd Maste {
449bbe31b70SEd Maste return false;
450bbe31b70SEd Maste }
451bbe31b70SEd Maste return input_stack.top()->consume_hex_byte(outByte);
452bbe31b70SEd Maste }
453bbe31b70SEd Maste /**
454bbe31b70SEd Maste * Returns the longest string in the input buffer starting at the
455bbe31b70SEd Maste * current cursor and composed entirely of characters that are valid in
456bbe31b70SEd Maste * node names.
457bbe31b70SEd Maste */
458bbe31b70SEd Maste std::string parse_node_name();
459bbe31b70SEd Maste /**
460bbe31b70SEd Maste * Returns the longest string in the input buffer starting at the
461bbe31b70SEd Maste * current cursor and composed entirely of characters that are valid in
462bbe31b70SEd Maste * property names.
463bbe31b70SEd Maste */
464bbe31b70SEd Maste std::string parse_property_name();
465bbe31b70SEd Maste /**
466bbe31b70SEd Maste * Parses either a node or a property name. If is_property is true on
467bbe31b70SEd Maste * entry, then only property names are parsed. If it is false, then it
468bbe31b70SEd Maste * will be set, on return, to indicate whether the parsed name is only
469bbe31b70SEd Maste * valid as a property.
470bbe31b70SEd Maste */
471bbe31b70SEd Maste std::string parse_node_or_property_name(bool &is_property);
472bbe31b70SEd Maste /**
473bbe31b70SEd Maste * Parses up to a specified character and returns the intervening
474bbe31b70SEd Maste * characters as a string.
475bbe31b70SEd Maste */
476bbe31b70SEd Maste std::string parse_to(char);
477bbe31b70SEd Maste /**
478bbe31b70SEd Maste * Advances the cursor to the start of the next token, skipping
479bbe31b70SEd Maste * comments and whitespace. If the cursor already points to the start
480bbe31b70SEd Maste * of a token, then this function does nothing.
481bbe31b70SEd Maste */
482bbe31b70SEd Maste text_input_buffer &next_token();
483bbe31b70SEd Maste /**
484bbe31b70SEd Maste * Location in the source file. This should never be interpreted by
485bbe31b70SEd Maste * anything other than error reporting functions of this class. It will
486bbe31b70SEd Maste * eventually become something more complex than an `int`.
487bbe31b70SEd Maste */
488bbe31b70SEd Maste class source_location
489bbe31b70SEd Maste {
490bbe31b70SEd Maste friend class text_input_buffer;
491bbe31b70SEd Maste /**
492bbe31b70SEd Maste * The text buffer object that included `b`.
493bbe31b70SEd Maste */
494bbe31b70SEd Maste text_input_buffer &buffer;
495bbe31b70SEd Maste /**
496bbe31b70SEd Maste * The underlying buffer that contains this location.
497bbe31b70SEd Maste */
498bbe31b70SEd Maste std::shared_ptr<input_buffer> b;
499bbe31b70SEd Maste /**
500bbe31b70SEd Maste * The offset within the current buffer of the source location.
501bbe31b70SEd Maste */
502bbe31b70SEd Maste int cursor;
source_location(text_input_buffer & buf)503bbe31b70SEd Maste source_location(text_input_buffer &buf)
504bbe31b70SEd Maste : buffer(buf),
505bbe31b70SEd Maste b(buf.input_stack.empty() ? nullptr : buf.input_stack.top()),
506bbe31b70SEd Maste cursor(b ? b->cursor : 0) {}
507bbe31b70SEd Maste public:
508bbe31b70SEd Maste /**
509bbe31b70SEd Maste * Report an error at this location.
510bbe31b70SEd Maste */
report_error(const char * msg)511bbe31b70SEd Maste void report_error(const char *msg)
512bbe31b70SEd Maste {
513bbe31b70SEd Maste if (b)
514bbe31b70SEd Maste {
515bbe31b70SEd Maste buffer.parse_error(msg, *b, cursor);
516bbe31b70SEd Maste }
517bbe31b70SEd Maste else
518bbe31b70SEd Maste {
519bbe31b70SEd Maste buffer.parse_error(msg);
520bbe31b70SEd Maste }
521bbe31b70SEd Maste }
522af0dd31fSDavid Chisnall };
523af0dd31fSDavid Chisnall /**
524bbe31b70SEd Maste * Returns the current source location.
525af0dd31fSDavid Chisnall */
location()526bbe31b70SEd Maste source_location location()
527af0dd31fSDavid Chisnall {
528bbe31b70SEd Maste return { *this };
529bbe31b70SEd Maste }
530af0dd31fSDavid Chisnall /**
531bbe31b70SEd Maste * Prints a message indicating the location of a parse error.
532af0dd31fSDavid Chisnall */
533bbe31b70SEd Maste void parse_error(const char *msg);
534ca84c67cSKyle Evans /**
535ca84c67cSKyle Evans * Reads the contents of a binary file into `b`. The file name is assumed
536ca84c67cSKyle Evans * to be relative to one of the include paths.
537ca84c67cSKyle Evans *
538ca84c67cSKyle Evans * Returns true if the file exists and can be read, false otherwise.
539ca84c67cSKyle Evans */
540ca84c67cSKyle Evans bool read_binary_file(const std::string &filename, byte_buffer &b);
541bbe31b70SEd Maste private:
542af0dd31fSDavid Chisnall /**
543bbe31b70SEd Maste * Prints a message indicating the location of a parse error, given a
544bbe31b70SEd Maste * specified location. This is used when input has already moved beyond
545bbe31b70SEd Maste * the location that caused the failure.
546af0dd31fSDavid Chisnall */
547bbe31b70SEd Maste void parse_error(const char *msg, input_buffer &b, int loc);
548af0dd31fSDavid Chisnall };
549af0dd31fSDavid Chisnall
550af0dd31fSDavid Chisnall } // namespace dtc
551af0dd31fSDavid Chisnall
552af0dd31fSDavid Chisnall #endif // !_INPUT_BUFFER_HH_
553