a0706eb457
- Various fixes to includes (including recursive includes) - Lots of testing that the output exactly matches GPL'd dtc - Lots of bug fixes to merging - Fix incorrect mmap usage - Ad-hoc memory management replaced with C++11 unique_ptr and similar Patrick Wildt has successfully run many (all?) of the GPL dtc test suite.
270 lines
5.4 KiB
C++
270 lines
5.4 KiB
C++
/*-
|
|
* Copyright (c) 2013 David Chisnall
|
|
* All rights reserved.
|
|
*
|
|
* This software was developed by SRI International and the University of
|
|
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
|
|
* ("CTSRD"), as part of the DARPA CRASH research programme.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include "input_buffer.hh"
|
|
#include <ctype.h>
|
|
#include <limits.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
|
|
#include <sys/stat.h>
|
|
#include <sys/mman.h>
|
|
#include <assert.h>
|
|
|
|
#ifndef MAP_PREFAULT_READ
|
|
#define MAP_PREFAULT_READ 0
|
|
#endif
|
|
|
|
namespace dtc
|
|
{
|
|
|
|
void
|
|
input_buffer::skip_spaces()
|
|
{
|
|
if (cursor >= size) { return; }
|
|
if (cursor < 0) { return; }
|
|
char c = buffer[cursor];
|
|
while ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\f')
|
|
|| (c == '\v') || (c == '\r'))
|
|
{
|
|
cursor++;
|
|
if (cursor > size)
|
|
{
|
|
c = '\0';
|
|
}
|
|
else
|
|
{
|
|
c = buffer[cursor];
|
|
}
|
|
}
|
|
}
|
|
|
|
input_buffer
|
|
input_buffer::buffer_from_offset(int offset, int s)
|
|
{
|
|
if (s == 0)
|
|
{
|
|
s = size - offset;
|
|
}
|
|
if (offset > size)
|
|
{
|
|
return input_buffer();
|
|
}
|
|
if (s > (size-offset))
|
|
{
|
|
return input_buffer();
|
|
}
|
|
return input_buffer(&buffer[offset], s);
|
|
}
|
|
|
|
bool
|
|
input_buffer::consume(const char *str)
|
|
{
|
|
int len = strlen(str);
|
|
if (len > size - cursor)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
for (int i=0 ; i<len ; ++i)
|
|
{
|
|
if (str[i] != buffer[cursor + i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
cursor += len;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
input_buffer::consume_integer(unsigned long long &outInt)
|
|
{
|
|
// The first character must be a digit. Hex and octal strings
|
|
// are prefixed by 0 and 0x, respectively.
|
|
if (!isdigit((*this)[0]))
|
|
{
|
|
return false;
|
|
}
|
|
char *end=0;
|
|
outInt = strtoull(&buffer[cursor], &end, 0);
|
|
if (end == &buffer[cursor])
|
|
{
|
|
return false;
|
|
}
|
|
cursor = end - buffer;
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
input_buffer::consume_hex_byte(uint8_t &outByte)
|
|
{
|
|
if (!ishexdigit((*this)[0]) && !ishexdigit((*this)[1]))
|
|
{
|
|
return false;
|
|
}
|
|
outByte = (digittoint((*this)[0]) << 4) | digittoint((*this)[1]);
|
|
cursor += 2;
|
|
return true;
|
|
}
|
|
|
|
input_buffer&
|
|
input_buffer::next_token()
|
|
{
|
|
int start;
|
|
do {
|
|
start = cursor;
|
|
skip_spaces();
|
|
// Parse /* comments
|
|
if ((*this)[0] == '/' && (*this)[1] == '*')
|
|
{
|
|
// eat the start of the comment
|
|
++(*this);
|
|
++(*this);
|
|
do {
|
|
// Find the ending * of */
|
|
while ((**this != '\0') && (**this != '*'))
|
|
{
|
|
++(*this);
|
|
}
|
|
// Eat the *
|
|
++(*this);
|
|
} while ((**this != '\0') && (**this != '/'));
|
|
// Eat the /
|
|
++(*this);
|
|
}
|
|
// Parse // comments
|
|
if (((*this)[0] == '/' && (*this)[1] == '/'))
|
|
{
|
|
// eat the start of the comment
|
|
++(*this);
|
|
++(*this);
|
|
// Find the ending of the line
|
|
while (**this != '\n')
|
|
{
|
|
++(*this);
|
|
}
|
|
// Eat the \n
|
|
++(*this);
|
|
}
|
|
} while (start != cursor);
|
|
return *this;
|
|
}
|
|
|
|
void
|
|
input_buffer::parse_error(const char *msg)
|
|
{
|
|
int line_count = 1;
|
|
int line_start = 0;
|
|
int line_end = cursor;
|
|
for (int i=cursor ; i>0 ; --i)
|
|
{
|
|
if (buffer[i] == '\n')
|
|
{
|
|
line_count++;
|
|
if (line_start == 0)
|
|
{
|
|
line_start = i+1;
|
|
}
|
|
}
|
|
}
|
|
for (int i=cursor+1 ; i<size ; ++i)
|
|
{
|
|
if (buffer[i] == '\n')
|
|
{
|
|
line_end = i;
|
|
break;
|
|
}
|
|
}
|
|
fprintf(stderr, "Error on line %d: %s\n", line_count, msg);
|
|
fwrite(&buffer[line_start], line_end-line_start, 1, stderr);
|
|
putc('\n', stderr);
|
|
for (int i=0 ; i<(cursor-line_start) ; ++i)
|
|
{
|
|
char c = (buffer[i+line_start] == '\t') ? '\t' : ' ';
|
|
putc(c, stderr);
|
|
}
|
|
putc('^', stderr);
|
|
putc('\n', stderr);
|
|
}
|
|
void
|
|
input_buffer::dump()
|
|
{
|
|
fprintf(stderr, "Current cursor: %d\n", cursor);
|
|
fwrite(&buffer[cursor], size-cursor, 1, stderr);
|
|
}
|
|
|
|
mmap_input_buffer::mmap_input_buffer(int fd) : input_buffer(0, 0)
|
|
{
|
|
struct stat sb;
|
|
if (fstat(fd, &sb))
|
|
{
|
|
perror("Failed to stat file");
|
|
}
|
|
size = sb.st_size;
|
|
buffer = (const char*)mmap(0, size, PROT_READ, MAP_PRIVATE |
|
|
MAP_PREFAULT_READ, fd, 0);
|
|
if (buffer == MAP_FAILED)
|
|
{
|
|
perror("Failed to mmap file");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
mmap_input_buffer::~mmap_input_buffer()
|
|
{
|
|
if (buffer != 0)
|
|
{
|
|
munmap((void*)buffer, size);
|
|
}
|
|
}
|
|
|
|
stream_input_buffer::stream_input_buffer() : input_buffer(0, 0)
|
|
{
|
|
int c;
|
|
while ((c = fgetc(stdin)) != EOF)
|
|
{
|
|
b.push_back(c);
|
|
}
|
|
buffer = b.data();
|
|
size = b.size();
|
|
}
|
|
|
|
} // namespace dtc
|
|
|