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