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