diff options
Diffstat (limited to 'tools/preproc')
-rw-r--r-- | tools/preproc/asm_file.cpp | 39 | ||||
-rw-r--r-- | tools/preproc/c_file.cpp | 334 | ||||
-rw-r--r-- | tools/preproc/c_file.h | 8 | ||||
-rw-r--r-- | tools/preproc/char_util.h | 4 | ||||
-rw-r--r-- | tools/preproc/preproc.cpp | 14 |
5 files changed, 298 insertions, 101 deletions
diff --git a/tools/preproc/asm_file.cpp b/tools/preproc/asm_file.cpp index 7deaccc8a..bb296b78b 100644 --- a/tools/preproc/asm_file.cpp +++ b/tools/preproc/asm_file.cpp @@ -111,45 +111,22 @@ void AsmFile::RemoveComments() m_buffer[pos++] = ' '; m_buffer[pos++] = ' '; - char commentStringChar = 0; - for (;;) { if (m_buffer[pos] == 0) return; - if (commentStringChar != 0) + if (m_buffer[pos] == '*' && m_buffer[pos + 1] == '/') { - if (m_buffer[pos] == '\\' && m_buffer[pos + 1] == commentStringChar) - { - m_buffer[pos++] = ' '; - m_buffer[pos++] = ' '; - } - else - { - if (m_buffer[pos] == commentStringChar) - commentStringChar = 0; - if (m_buffer[pos] != '\n') - m_buffer[pos] = ' '; - pos++; - } + m_buffer[pos++] = ' '; + m_buffer[pos++] = ' '; + break; } else { - if (m_buffer[pos] == '*' && m_buffer[pos + 1] == '/') - { - m_buffer[pos++] = ' '; - m_buffer[pos++] = ' '; - break; - } - else - { - if (m_buffer[pos] == '"' || m_buffer[pos] == '\'') - commentStringChar = m_buffer[pos]; - if (m_buffer[pos] != '\n') - m_buffer[pos] = ' '; - pos++; - } + if (m_buffer[pos] != '\n') + m_buffer[pos] = ' '; + pos++; } } } @@ -517,7 +494,7 @@ bool AsmFile::IsAtEnd() // Output the current location to set gas's logical file and line numbers. void AsmFile::OutputLocation() { - printf("# %ld \"%s\"\n", m_lineNum, m_filename.c_str()); + std::printf("# %ld \"%s\"\n", m_lineNum, m_filename.c_str()); } // Reports a diagnostic message. diff --git a/tools/preproc/c_file.cpp b/tools/preproc/c_file.cpp index aed53d44b..5bfdee086 100644 --- a/tools/preproc/c_file.cpp +++ b/tools/preproc/c_file.cpp @@ -20,6 +20,8 @@ #include <cstdio> #include <cstdarg> +#include <string> +#include <memory> #include "preproc.h" #include "c_file.h" #include "char_util.h" @@ -72,8 +74,6 @@ CFile::~CFile() void CFile::Preproc() { - bool inConcatMode = false; - bool noTerminator = false; char stringChar = 0; while (m_pos < m_size) @@ -94,85 +94,297 @@ void CFile::Preproc() } else { + if (m_buffer[m_pos] == '\n') + m_lineNum++; std::putchar(m_buffer[m_pos]); m_pos++; } } else { - if (inConcatMode ? m_buffer[m_pos] == '"' - : (m_buffer[m_pos] == '_' || m_buffer[m_pos] == '@') && m_buffer[m_pos + 1] == '"') + TryConvertString(); + TryConvertIncbin(); + + if (m_pos >= m_size) + break; + + char c = m_buffer[m_pos++]; + + std::putchar(c); + + if (c == '\n') + m_lineNum++; + else if (c == '"') + stringChar = '"'; + else if (c == '\'') + stringChar = '\''; + } + } +} + +bool CFile::ConsumeHorizontalWhitespace() +{ + if (m_buffer[m_pos] == '\t' || m_buffer[m_pos] == ' ') + { + m_pos++; + return true; + } + + return false; +} + +bool CFile::ConsumeNewline() +{ + if (m_buffer[m_pos] == '\r' && m_buffer[m_pos + 1] == '\n') + { + m_pos += 2; + m_lineNum++; + return true; + } + + if (m_buffer[m_pos] == '\n') + { + m_pos++; + m_lineNum++; + return true; + } + + return false; +} + +void CFile::SkipWhitespace() +{ + while (ConsumeHorizontalWhitespace() || ConsumeNewline()) + ; +} + +void CFile::TryConvertString() +{ + long oldPos = m_pos; + long oldLineNum = m_lineNum; + bool noTerminator = false; + + if (m_buffer[m_pos] != '_' || (m_pos > 0 && IsIdentifierChar(m_buffer[m_pos - 1]))) + return; + + m_pos++; + + if (m_buffer[m_pos] == '_') + { + noTerminator = true; + m_pos++; + } + + SkipWhitespace(); + + if (m_buffer[m_pos] != '(') + { + m_pos = oldPos; + m_lineNum = oldLineNum; + return; + } + + m_pos++; + + SkipWhitespace(); + + std::printf("{ "); + + while (1) + { + SkipWhitespace(); + + if (m_buffer[m_pos] == '"') + { + unsigned char s[kMaxStringLength]; + int length; + StringParser stringParser(m_buffer, m_size); + + try { - if (!inConcatMode) - { - noTerminator = (m_buffer[m_pos] == '@'); - m_pos++; // skip past underscore or at-sign - } - - unsigned char s[kMaxStringLength]; - int length; - StringParser stringParser(m_buffer, m_size); - - try - { - m_pos += stringParser.ParseString(m_pos, s, length); - } - catch (std::runtime_error e) - { - RaiseError(e.what()); - } - - if (!inConcatMode) - { - std::printf("{ "); - } - - inConcatMode = true; - - for (int i = 0; i < length; i++) - printf("0x%02X, ", s[i]); + m_pos += stringParser.ParseString(m_pos, s, length); } - else + catch (std::runtime_error e) { - char c = m_buffer[m_pos++]; + RaiseError(e.what()); + } + + for (int i = 0; i < length; i++) + printf("0x%02X, ", s[i]); + } + else if (m_buffer[m_pos] == ')') + { + m_pos++; + break; + } + else + { + if (m_pos >= m_size) + RaiseError("unexpected EOF"); + if (IsAsciiPrintable(m_buffer[m_pos])) + RaiseError("unexpected character '%c'", m_buffer[m_pos]); + else + RaiseError("unexpected character '\\x%02X'", m_buffer[m_pos]); + } + } + + if (noTerminator) + std::printf(" }"); + else + std::printf("0xFF }"); +} + +bool CFile::CheckIdentifier(const std::string& ident) +{ + unsigned int i; - if (c == '\r') - { - if (m_buffer[m_pos] == '\n') - { - m_pos++; - } + for (i = 0; i < ident.length() && m_pos + i < (unsigned)m_size; i++) + if (ident[i] != m_buffer[m_pos + i]) + return false; - c = '\n'; - } + return (i == ident.length()); +} - if ((c != ' ' && c != '\t' && c != '\n') && inConcatMode) - { - if (noTerminator) - std::printf(" }"); - else - std::printf("0xFF }"); +std::unique_ptr<unsigned char[]> CFile::ReadWholeFile(const std::string& path, int& size) +{ + FILE* fp = std::fopen(path.c_str(), "rb"); - inConcatMode = false; - } + if (fp == nullptr) + RaiseError("Failed to open \"%s\" for reading.\n", path.c_str()); - std::putchar(c); + std::fseek(fp, 0, SEEK_END); - if (c == '\n') - m_lineNum++; - else if (c == '"') - stringChar = '"'; - else if (m_buffer[m_pos] == '\'') - stringChar = '\''; - } + size = std::ftell(fp); + + std::unique_ptr<unsigned char[]> buffer = std::unique_ptr<unsigned char[]>(new unsigned char[size]); + + std::rewind(fp); + + if (std::fread(buffer.get(), size, 1, fp) != 1) + RaiseError("Failed to read \"%s\".\n", path.c_str()); + + std::fclose(fp); + + return buffer; +} + +int ExtractData(const std::unique_ptr<unsigned char[]>& buffer, int offset, int size) +{ + switch (size) + { + case 1: + return buffer[offset]; + case 2: + return (buffer[offset + 1] << 8) + | buffer[offset]; + case 4: + return (buffer[offset + 3] << 24) + | (buffer[offset + 2] << 16) + | (buffer[offset + 1] << 8) + | buffer[offset]; + default: + FATAL_ERROR("Invalid size passed to ExtractData.\n"); + } +} + +void CFile::TryConvertIncbin() +{ + std::string idents[6] = { "INCBIN_S8", "INCBIN_U8", "INCBIN_S16", "INCBIN_U16", "INCBIN_S32", "INCBIN_U32" }; + int incbinType = -1; + + for (int i = 0; i < 6; i++) + { + if (CheckIdentifier(idents[i])) + { + incbinType = i; + break; } } - if (inConcatMode) + if (incbinType == -1) + return; + + int size = 1 << (incbinType / 2); + bool isSigned = ((incbinType % 2) == 0); + + long oldPos = m_pos; + long oldLineNum = m_lineNum; + + m_pos += idents[incbinType].length(); + + SkipWhitespace(); + + if (m_buffer[m_pos] != '(') { - printf("0xFF }"); - RaiseWarning("string at end of file"); + m_pos = oldPos; + m_lineNum = oldLineNum; + return; } + + m_pos++; + + SkipWhitespace(); + + if (m_buffer[m_pos] != '"') + RaiseError("expected double quote"); + + m_pos++; + + int startPos = m_pos; + + while (m_buffer[m_pos] != '"') + { + if (m_buffer[m_pos] == 0) + { + if (m_pos >= m_size) + RaiseError("unexpected EOF in path string"); + else + RaiseError("unexpected null character in path string"); + } + + if (m_buffer[m_pos] == '\r' || m_buffer[m_pos] == '\n') + RaiseError("unexpected end of line character in path string"); + + if (m_buffer[m_pos] == '\\') + RaiseError("unexpected escape in path string"); + + m_pos++; + } + + std::string path(&m_buffer[startPos], m_pos - startPos); + + m_pos++; + + SkipWhitespace(); + + if (m_buffer[m_pos] != ')') + RaiseError("expected ')'"); + + m_pos++; + + std::printf("{"); + + int fileSize; + std::unique_ptr<unsigned char[]> buffer = ReadWholeFile(path, fileSize); + + if ((fileSize % size) != 0) + RaiseError("Size %d doesn't evenly divide file size %d.\n", size, fileSize); + + int count = fileSize / size; + int offset = 0; + + for (int i = 0; i < count; i++) + { + int data = ExtractData(buffer, offset, size); + offset += size; + + if (isSigned) + std::printf("%d,", data); + else + std::printf("%uu,", data); + } + + std::printf("}"); } // Reports a diagnostic message. diff --git a/tools/preproc/c_file.h b/tools/preproc/c_file.h index b6041cc00..7369aba85 100644 --- a/tools/preproc/c_file.h +++ b/tools/preproc/c_file.h @@ -24,6 +24,7 @@ #include <cstdarg> #include <cstdint> #include <string> +#include <memory> #include "preproc.h" class CFile @@ -42,6 +43,13 @@ private: long m_lineNum; std::string m_filename; + bool ConsumeHorizontalWhitespace(); + bool ConsumeNewline(); + void SkipWhitespace(); + void TryConvertString(); + std::unique_ptr<unsigned char[]> ReadWholeFile(const std::string& path, int& size); + bool CheckIdentifier(const std::string& ident); + void TryConvertIncbin(); void ReportDiagnostic(const char* type, const char* format, std::va_list args); void RaiseError(const char* format, ...); void RaiseWarning(const char* format, ...); diff --git a/tools/preproc/char_util.h b/tools/preproc/char_util.h index ab20dbc53..02a6e1ceb 100644 --- a/tools/preproc/char_util.h +++ b/tools/preproc/char_util.h @@ -56,13 +56,13 @@ inline bool IsAsciiPrintable(unsigned char c) return (c >= ' ' && c <= '~'); } -// Returns whether the character can start the identifier of a "{FOO}" constant in strings. +// Returns whether the character can start a C identifier or the identifier of a "{FOO}" constant in strings. inline bool IsIdentifierStartingChar(unsigned char c) { return IsAsciiAlpha(c) || c == '_'; } -// Returns whether the character can be used in the identifier of a "{FOO}" constant in strings. +// Returns whether the character can be used in a C identifier or the identifier of a "{FOO}" constant in strings. inline bool IsIdentifierChar(unsigned char c) { return IsAsciiAlphanum(c) || c == '_'; diff --git a/tools/preproc/preproc.cpp b/tools/preproc/preproc.cpp index b51861580..8320a2d27 100644 --- a/tools/preproc/preproc.cpp +++ b/tools/preproc/preproc.cpp @@ -31,15 +31,15 @@ void PrintAsmBytes(unsigned char *s, int length) { if (length > 0) { - printf("\t.byte "); + std::printf("\t.byte "); for (int i = 0; i < length; i++) { - printf("0x%02X", s[i]); + std::printf("0x%02X", s[i]); if (i < length - 1) - printf(", "); + std::printf(", "); } - putchar('\n'); + std::putchar('\n'); } } @@ -89,8 +89,8 @@ void PreprocAsmFile(std::string filename) if (globalLabel.length() != 0) { - printf("\t.global %s\n", globalLabel.c_str()); - printf("%s:\n", globalLabel.c_str()); + std::printf("\t.global %s\n", globalLabel.c_str()); + std::printf("%s:\n", globalLabel.c_str()); } else { @@ -134,7 +134,7 @@ int main(int argc, char **argv) { if (argc != 3) { - fprintf(stderr, "Usage: %s SRC_FILE CHARMAP_FILE", argv[0]); + std::fprintf(stderr, "Usage: %s SRC_FILE CHARMAP_FILE", argv[0]); return 1; } |