xref: /freebsd/usr.bin/dtc/input_buffer.cc (revision 5b9c547c)
1 /*-
2  * Copyright (c) 2013 David Chisnall
3  * All rights reserved.
4  *
5  * This software was developed by SRI International and the University of
6  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7  * ("CTSRD"), as part of the DARPA CRASH research programme.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD$
31  */
32 
33 #include "input_buffer.hh"
34 #include <ctype.h>
35 #include <limits.h>
36 #include <stdint.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 
42 #include <sys/stat.h>
43 #include <sys/mman.h>
44 #include <assert.h>
45 
46 #ifndef MAP_PREFAULT_READ
47 #define MAP_PREFAULT_READ 0
48 #endif
49 
50 namespace dtc
51 {
52 
53 void
54 input_buffer::skip_spaces()
55 {
56 	if (cursor >= size) { return; }
57 	if (cursor < 0) { return; }
58 	char c = buffer[cursor];
59 	while ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\f')
60 	       || (c == '\v') || (c == '\r'))
61 	{
62 		cursor++;
63 		if (cursor > size)
64 		{
65 			c = '\0';
66 		}
67 		else
68 		{
69 			c = buffer[cursor];
70 		}
71 	}
72 }
73 
74 input_buffer
75 input_buffer::buffer_from_offset(int offset, int s)
76 {
77 	if (s == 0)
78 	{
79 		s = size - offset;
80 	}
81 	if (offset > size)
82 	{
83 		return input_buffer();
84 	}
85 	if (s > (size-offset))
86 	{
87 		return input_buffer();
88 	}
89 	return input_buffer(&buffer[offset], s);
90 }
91 
92 bool
93 input_buffer::consume(const char *str)
94 {
95 	int len = strlen(str);
96 	if (len > size - cursor)
97 	{
98 		return false;
99 	}
100 	else
101 	{
102 		for (int i=0 ; i<len ; ++i)
103 		{
104 			if (str[i] != buffer[cursor + i])
105 			{
106 				return false;
107 			}
108 		}
109 		cursor += len;
110 		return true;
111 	}
112 	return false;
113 }
114 
115 bool
116 input_buffer::consume_integer(long long &outInt)
117 {
118 	// The first character must be a digit.  Hex and octal strings
119 	// are prefixed by 0 and 0x, respectively.
120 	if (!isdigit((*this)[0]))
121 	{
122 		return false;
123 	}
124 	char *end=0;
125 	outInt = strtoll(&buffer[cursor], &end, 0);
126 	if (end == &buffer[cursor])
127 	{
128 		return false;
129 	}
130 	cursor = end - buffer;
131 	return true;
132 }
133 
134 bool
135 input_buffer::consume_hex_byte(uint8_t &outByte)
136 {
137 	if (!ishexdigit((*this)[0]) && !ishexdigit((*this)[1]))
138 	{
139 		return false;
140 	}
141 	outByte = (digittoint((*this)[0]) << 4) | digittoint((*this)[1]);
142 	cursor += 2;
143 	return true;
144 }
145 
146 input_buffer&
147 input_buffer::next_token()
148 {
149 	int start;
150 	do {
151 		start = cursor;
152 		skip_spaces();
153 		// Parse /* comments
154 		if ((*this)[0] == '/' && (*this)[1] == '*')
155 		{
156 			// eat the start of the comment
157 			++(*this);
158 			++(*this);
159 			do {
160 				// Find the ending * of */
161 				while ((**this != '\0') && (**this != '*'))
162 				{
163 					++(*this);
164 				}
165 				// Eat the *
166 				++(*this);
167 			} while ((**this != '\0') && (**this != '/'));
168 			// Eat the /
169 			++(*this);
170 		}
171 		// Parse // comments and # comments
172 		if (((*this)[0] == '/' && (*this)[1] == '/') ||
173 		     (*this)[0] == '#')
174 		{
175 			// eat the start of the comment
176 			++(*this);
177 			++(*this);
178 			// Find the ending of the line
179 			while (**this != '\n')
180 			{
181 				++(*this);
182 			}
183 			// Eat the \n
184 			++(*this);
185 		}
186 	} while (start != cursor);
187 	return *this;
188 }
189 
190 void
191 input_buffer::parse_error(const char *msg)
192 {
193 	int line_count = 1;
194 	int line_start = 0;
195 	int line_end = cursor;
196 	for (int i=cursor ; i>0 ; --i)
197 	{
198 		if (buffer[i] == '\n')
199 		{
200 			line_count++;
201 			if (line_start == 0)
202 			{
203 				line_start = i+1;
204 			}
205 		}
206 	}
207 	for (int i=cursor+1 ; i<size ; ++i)
208 	{
209 		if (buffer[i] == '\n')
210 		{
211 			line_end = i;
212 			break;
213 		}
214 	}
215 	fprintf(stderr, "Error on line %d: %s\n", line_count, msg);
216 	fwrite(&buffer[line_start], line_end-line_start, 1, stderr);
217 	putc('\n', stderr);
218 	for (int i=0 ; i<(cursor-line_start) ; ++i)
219 	{
220 		char c = (buffer[i+line_start] == '\t') ? '\t' : ' ';
221 		putc(c, stderr);
222 	}
223 	putc('^', stderr);
224 	putc('\n', stderr);
225 }
226 void
227 input_buffer::dump()
228 {
229 	fprintf(stderr, "Current cursor: %d\n", cursor);
230 	fwrite(&buffer[cursor], size-cursor, 1, stderr);
231 }
232 
233 mmap_input_buffer::mmap_input_buffer(int fd) : input_buffer(0, 0)
234 {
235 	struct stat sb;
236 	if (fstat(fd, &sb))
237 	{
238 		perror("Failed to stat file");
239 	}
240 	size = sb.st_size;
241 	buffer = (const char*)mmap(0, size, PROT_READ,
242 		MAP_PREFAULT_READ, fd, 0);
243 	if (buffer == 0)
244 	{
245 		perror("Failed to mmap file");
246 	}
247 }
248 
249 mmap_input_buffer::~mmap_input_buffer()
250 {
251 	if (buffer != 0)
252 	{
253 		munmap((void*)buffer, size);
254 	}
255 }
256 
257 stream_input_buffer::stream_input_buffer() : input_buffer(0, 0)
258 {
259 	int c;
260 	while ((c = fgetc(stdin)) != EOF)
261 	{
262 		b.push_back(c);
263 	}
264 	buffer = b.data();
265 	size = b.size();
266 }
267 
268 } // namespace dtc
269 
270