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