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 <string.h> 35 #include <stdint.h> 36 37 #include <sys/stat.h> 38 #include <sys/mman.h> 39 #include <assert.h> 40 41 namespace dtc 42 { 43 44 void 45 input_buffer::skip_spaces() 46 { 47 if (cursor >= size) { return; } 48 if (cursor < 0) { return; } 49 char c = buffer[cursor]; 50 while ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\f') 51 || (c == '\v') || (c == '\r')) 52 { 53 cursor++; 54 if (cursor > size) 55 { 56 c = '\0'; 57 } 58 else 59 { 60 c = buffer[cursor]; 61 } 62 } 63 } 64 65 input_buffer 66 input_buffer::buffer_from_offset(int offset, int s) 67 { 68 if (s == 0) 69 { 70 s = size - offset; 71 } 72 if (offset > size) 73 { 74 return input_buffer(); 75 } 76 if (s > (size-offset)) 77 { 78 return input_buffer(); 79 } 80 return input_buffer(&buffer[offset], s); 81 } 82 83 bool 84 input_buffer::consume(const char *str) 85 { 86 int len = strlen(str); 87 if (len > size - cursor) 88 { 89 return false; 90 } 91 else 92 { 93 for (int i=0 ; i<len ; ++i) 94 { 95 if (str[i] != buffer[cursor + i]) 96 { 97 return false; 98 } 99 } 100 cursor += len; 101 return true; 102 } 103 return false; 104 } 105 106 bool 107 input_buffer::consume_integer(long long &outInt) 108 { 109 // The first character must be a digit. Hex and octal strings 110 // are prefixed by 0 and 0x, respectively. 111 if (!isdigit((*this)[0])) 112 { 113 return false; 114 } 115 char *end=0; 116 outInt = strtoll(&buffer[cursor], &end, 0); 117 if (end == &buffer[cursor]) 118 { 119 return false; 120 } 121 cursor = end - buffer; 122 return true; 123 } 124 125 bool 126 input_buffer::consume_hex_byte(uint8_t &outByte) 127 { 128 if (!ishexdigit((*this)[0]) && !ishexdigit((*this)[1])) 129 { 130 return false; 131 } 132 outByte = (digittoint((*this)[0]) << 4) | digittoint((*this)[1]); 133 cursor += 2; 134 return true; 135 } 136 137 input_buffer& 138 input_buffer::next_token() 139 { 140 int start; 141 do { 142 start = cursor; 143 skip_spaces(); 144 // Parse /* comments 145 if (((*this)[0] == '/') && ((*this)[1] == '*')) 146 { 147 // eat the start of the comment 148 ++(*this); 149 ++(*this); 150 do { 151 // Find the ending * of */ 152 while ((**this != '\0') && (**this != '*')) 153 { 154 ++(*this); 155 } 156 // Eat the * 157 ++(*this); 158 } while ((**this != '\0') && (**this != '/')); 159 // Eat the / 160 ++(*this); 161 } 162 // Parse // comments 163 if (((*this)[0] == '/') && ((*this)[1] == '/')) 164 { 165 // eat the start of the comment 166 ++(*this); 167 ++(*this); 168 // Find the ending * of */ 169 while (**this != '\n') 170 { 171 ++(*this); 172 } 173 // Eat the \n 174 ++(*this); 175 } 176 } while (start != cursor); 177 return *this; 178 } 179 180 void 181 input_buffer::parse_error(const char *msg) 182 { 183 int line_count = 1; 184 int line_start = 0; 185 int line_end = cursor; 186 for (int i=cursor ; i>0 ; --i) 187 { 188 if (buffer[i] == '\n') 189 { 190 line_count++; 191 if (line_start == 0) 192 { 193 line_start = i+1; 194 } 195 } 196 } 197 for (int i=cursor+1 ; i<size ; ++i) 198 { 199 if (buffer[i] == '\n') 200 { 201 line_end = i; 202 break; 203 } 204 } 205 fprintf(stderr, "Error on line %d: %s\n", line_count, msg); 206 fwrite(&buffer[line_start], line_end-line_start, 1, stderr); 207 putc('\n', stderr); 208 for (int i=0 ; i<(cursor-line_start) ; ++i) 209 { 210 putc(' ', stderr); 211 } 212 putc('^', stderr); 213 putc('\n', stderr); 214 } 215 void 216 input_buffer::dump() 217 { 218 fprintf(stderr, "Current cursor: %d\n", cursor); 219 fwrite(&buffer[cursor], size-cursor, 1, stderr); 220 } 221 222 mmap_input_buffer::mmap_input_buffer(int fd) : input_buffer(0, 0) 223 { 224 struct stat sb; 225 if (fstat(fd, &sb)) 226 { 227 perror("Failed to stat file"); 228 } 229 size = sb.st_size; 230 buffer = (const char*)mmap(0, size, PROT_READ, 231 MAP_PREFAULT_READ, fd, 0); 232 if (buffer == 0) 233 { 234 perror("Failed to mmap file"); 235 } 236 } 237 238 mmap_input_buffer::~mmap_input_buffer() 239 { 240 if (buffer != 0) 241 { 242 munmap((void*)buffer, size); 243 } 244 } 245 246 stream_input_buffer::stream_input_buffer() : input_buffer(0, 0) 247 { 248 int c; 249 while ((c = fgetc(stdin)) != EOF) 250 { 251 b.push_back(c); 252 } 253 buffer = b.data(); 254 size = b.size(); 255 } 256 257 } // namespace dtc 258 259