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