From 62e1033a01912566720cb18088514e05df148040 Mon Sep 17 00:00:00 2001 From: sbird Date: Fri, 29 Mar 2024 01:15:39 +0100 Subject: [PATCH 1/5] [preproc] asm files parseable from stdin, 2nd preproc pass --- Makefile | 6 ++--- tools/preproc/Makefile | 4 +-- tools/preproc/asm_file.cpp | 28 +++------------------ tools/preproc/asm_file.h | 2 +- tools/preproc/c_file.cpp | 48 +++--------------------------------- tools/preproc/c_file.h | 2 -- tools/preproc/io.cpp | 50 ++++++++++++++++++++++++++++++++++++++ tools/preproc/io.h | 8 ++++++ tools/preproc/preproc.cpp | 20 +++++++++++---- 9 files changed, 86 insertions(+), 82 deletions(-) create mode 100644 tools/preproc/io.cpp create mode 100644 tools/preproc/io.h diff --git a/Makefile b/Makefile index 50953be79cd7..fceee4e138f3 100644 --- a/Makefile +++ b/Makefile @@ -363,11 +363,11 @@ endif ifeq ($(NODEP),1) $(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s - $(PREPROC) $< charmap.txt | $(CPP) -I include - | $(AS) $(ASFLAGS) -o $@ + $(PREPROC) $< charmap.txt | $(CPP) -I include - | $(PREPROC) $$< charmap.txt -i | $(AS) $(ASFLAGS) -o $@ else define SRC_ASM_DATA_DEP $1: $2 $$(shell $(SCANINC) -I include -I "" $2) - $$(PREPROC) $$< charmap.txt | $$(CPP) -I include - | $$(AS) $$(ASFLAGS) -o $$@ + $$(PREPROC) $$< charmap.txt | $$(CPP) -I include - | $$(PREPROC) $$< charmap.txt -i | $$(AS) $$(ASFLAGS) -o $$@ endef $(foreach src, $(C_ASM_SRCS), $(eval $(call SRC_ASM_DATA_DEP,$(patsubst $(C_SUBDIR)/%.s,$(C_BUILDDIR)/%.o, $(src)),$(src)))) endif @@ -385,7 +385,7 @@ endif ifeq ($(NODEP),1) $(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s - $(PREPROC) $< charmap.txt | $(CPP) -I include - | $(AS) $(ASFLAGS) -o $@ + $(PREPROC) $< charmap.txt | $(CPP) -I include - | $(PREPROC) $$< charmap.txt -i | $(AS) $(ASFLAGS) -o $@ else $(foreach src, $(REGULAR_DATA_ASM_SRCS), $(eval $(call SRC_ASM_DATA_DEP,$(patsubst $(DATA_ASM_SUBDIR)/%.s,$(DATA_ASM_BUILDDIR)/%.o, $(src)),$(src)))) endif diff --git a/tools/preproc/Makefile b/tools/preproc/Makefile index 1507c973f27e..606318944c63 100644 --- a/tools/preproc/Makefile +++ b/tools/preproc/Makefile @@ -3,10 +3,10 @@ CXX ?= g++ CXXFLAGS := -std=c++11 -O2 -Wall -Wno-switch -Werror SRCS := asm_file.cpp c_file.cpp charmap.cpp preproc.cpp string_parser.cpp \ - utf8.cpp + utf8.cpp io.cpp HEADERS := asm_file.h c_file.h char_util.h charmap.h preproc.h string_parser.h \ - utf8.h + utf8.h io.h ifeq ($(OS),Windows_NT) EXE := .exe diff --git a/tools/preproc/asm_file.cpp b/tools/preproc/asm_file.cpp index 04a7410e00bf..5a2a54aac062 100644 --- a/tools/preproc/asm_file.cpp +++ b/tools/preproc/asm_file.cpp @@ -27,33 +27,11 @@ #include "utf8.h" #include "string_parser.h" #include "../../gflib/characters.h" +#include "io.h" -AsmFile::AsmFile(std::string filename) : m_filename(filename) +AsmFile::AsmFile(std::string filename, bool isStdin) : m_filename(filename) { - FILE *fp = std::fopen(filename.c_str(), "rb"); - - if (fp == NULL) - FATAL_ERROR("Failed to open \"%s\" for reading.\n", filename.c_str()); - - std::fseek(fp, 0, SEEK_END); - - m_size = std::ftell(fp); - - if (m_size < 0) - FATAL_ERROR("File size of \"%s\" is less than zero.\n", filename.c_str()); - else if (m_size == 0) - return; // Empty file - - m_buffer = new char[m_size + 1]; - - std::rewind(fp); - - if (std::fread(m_buffer, m_size, 1, fp) != 1) - FATAL_ERROR("Failed to read \"%s\".\n", filename.c_str()); - - m_buffer[m_size] = 0; - - std::fclose(fp); + m_buffer = ReadFileToBuffer(filename.c_str(), isStdin, &m_size); m_pos = 0; m_lineNum = 1; diff --git a/tools/preproc/asm_file.h b/tools/preproc/asm_file.h index 29435f76a47a..ec0291827c36 100644 --- a/tools/preproc/asm_file.h +++ b/tools/preproc/asm_file.h @@ -37,7 +37,7 @@ enum class Directive class AsmFile { public: - AsmFile(std::string filename); + AsmFile(std::string filename, bool isStdin); AsmFile(AsmFile&& other); AsmFile(const AsmFile&) = delete; ~AsmFile(); diff --git a/tools/preproc/c_file.cpp b/tools/preproc/c_file.cpp index 508c6287313a..191ca4c152e6 100644 --- a/tools/preproc/c_file.cpp +++ b/tools/preproc/c_file.cpp @@ -30,56 +30,16 @@ #include "char_util.h" #include "utf8.h" #include "string_parser.h" +#include "io.h" CFile::CFile(const char * filenameCStr, bool isStdin) { - FILE *fp; - - if (isStdin) { - fp = stdin; + if (isStdin) m_filename = std::string{"/"}.append(filenameCStr); - } else { - fp = std::fopen(filenameCStr, "rb"); + else m_filename = std::string(filenameCStr); - } - - std::string& filename = m_filename; - - if (fp == NULL) - FATAL_ERROR("Failed to open \"%s\" for reading.\n", filename.c_str()); - - m_size = 0; - m_buffer = (char *)malloc(CHUNK_SIZE + 1); - if (m_buffer == NULL) { - FATAL_ERROR("Failed to allocate memory to process file \"%s\"!", filename.c_str()); - } - - std::size_t numAllocatedBytes = CHUNK_SIZE + 1; - std::size_t bufferOffset = 0; - std::size_t count; - - while ((count = std::fread(m_buffer + bufferOffset, 1, CHUNK_SIZE, fp)) != 0) { - if (!std::ferror(fp)) { - m_size += count; - if (std::feof(fp)) { - break; - } - - numAllocatedBytes += CHUNK_SIZE; - bufferOffset += CHUNK_SIZE; - m_buffer = (char *)realloc(m_buffer, numAllocatedBytes); - if (m_buffer == NULL) { - FATAL_ERROR("Failed to allocate memory to process file \"%s\"!", filename.c_str()); - } - } else { - FATAL_ERROR("Failed to read \"%s\". (error: %s)", filename.c_str(), std::strerror(errno)); - } - } - - m_buffer[m_size] = 0; - - std::fclose(fp); + m_buffer = ReadFileToBuffer(filenameCStr, isStdin, &m_size); m_pos = 0; m_lineNum = 1; diff --git a/tools/preproc/c_file.h b/tools/preproc/c_file.h index 49e633a18dd4..c40c33c96277 100644 --- a/tools/preproc/c_file.h +++ b/tools/preproc/c_file.h @@ -56,6 +56,4 @@ class CFile void RaiseWarning(const char* format, ...); }; -#define CHUNK_SIZE 4096 - #endif // C_FILE_H diff --git a/tools/preproc/io.cpp b/tools/preproc/io.cpp new file mode 100644 index 000000000000..1572072cb4e4 --- /dev/null +++ b/tools/preproc/io.cpp @@ -0,0 +1,50 @@ +#include "preproc.h" +#include "io.h" +#include +#include + +char *ReadFileToBuffer(const char *filename, bool isStdin, long *size) +{ + FILE *fp; + if (isStdin) + fp = stdin; + else + fp = std::fopen(filename, "rb"); + + if (fp == NULL) + FATAL_ERROR("Failed to open \"%s\" for reading.\n", filename); + + *size = 0; + char *buffer = (char *)malloc(CHUNK_SIZE + 1); + if (buffer == NULL) { + FATAL_ERROR("Failed to allocate memory to process file \"%s\"!", filename); + } + + std::size_t numAllocatedBytes = CHUNK_SIZE + 1; + std::size_t bufferOffset = 0; + std::size_t count; + + while ((count = std::fread(buffer + bufferOffset, 1, CHUNK_SIZE, fp)) != 0) { + if (!std::ferror(fp)) { + *size += count; + + if (std::feof(fp)) { + break; + } + + numAllocatedBytes += CHUNK_SIZE; + bufferOffset += CHUNK_SIZE; + buffer = (char *)realloc(buffer, numAllocatedBytes); + if (buffer == NULL) { + FATAL_ERROR("Failed to allocate memory to process file \"%s\"!", filename); + } + } else { + FATAL_ERROR("Failed to read \"%s\". (error: %s)", filename, std::strerror(errno)); + } + } + + buffer[*size] = 0; + + std::fclose(fp); + return buffer; +} diff --git a/tools/preproc/io.h b/tools/preproc/io.h new file mode 100644 index 000000000000..b7b1994d1d21 --- /dev/null +++ b/tools/preproc/io.h @@ -0,0 +1,8 @@ +#ifndef IO_H_ +#define IO_H_ + +#define CHUNK_SIZE 4096 + +char *ReadFileToBuffer(const char *filename, bool isStdin, long *size); + +#endif // IO_H_ \ No newline at end of file diff --git a/tools/preproc/preproc.cpp b/tools/preproc/preproc.cpp index eb2d4c8a23f7..ed6fd32839e6 100644 --- a/tools/preproc/preproc.cpp +++ b/tools/preproc/preproc.cpp @@ -43,11 +43,11 @@ void PrintAsmBytes(unsigned char *s, int length) } } -void PreprocAsmFile(std::string filename) +void PreprocAsmFile(std::string filename, bool isStdin) { std::stack stack; - stack.push(AsmFile(filename)); + stack.push(AsmFile(filename, isStdin)); for (;;) { @@ -66,7 +66,7 @@ void PreprocAsmFile(std::string filename) switch (directive) { case Directive::Include: - stack.push(AsmFile(stack.top().ReadPath())); + stack.push(AsmFile(stack.top().ReadPath(), false)); stack.top().OutputLocation(); break; case Directive::String: @@ -145,8 +145,18 @@ int main(int argc, char **argv) if (!extension) FATAL_ERROR("\"%s\" has no file extension.\n", argv[1]); - if ((extension[0] == 's') && extension[1] == 0) - PreprocAsmFile(argv[1]); + if ((extension[0] == 's') && extension[1] == 0) { + if (argc == 4) { + if (argv[3][0] == '-' && argv[3][1] == 'i' && argv[3][2] == '\0') { + PreprocAsmFile(argv[1], true); + } else { + FATAL_ERROR("unknown argument flag \"%s\".\n", argv[3]); + } + } else { + PreprocAsmFile(argv[1], false); + } + + } else if ((extension[0] == 'c' || extension[0] == 'i') && extension[1] == 0) { if (argc == 4) { if (argv[3][0] == '-' && argv[3][1] == 'i' && argv[3][2] == '\0') { From aef617015ef61ddaf6264e4c80b511efc90d2113 Mon Sep 17 00:00:00 2001 From: sbird Date: Sun, 31 Mar 2024 12:52:26 +0200 Subject: [PATCH 2/5] [preproc] add parser for c-style `enum` --- tools/preproc/asm_file.cpp | 186 +++++++++++++++++++++++++++++++++++++ tools/preproc/asm_file.h | 6 ++ tools/preproc/io.h | 2 +- tools/preproc/preproc.cpp | 7 ++ 4 files changed, 200 insertions(+), 1 deletion(-) diff --git a/tools/preproc/asm_file.cpp b/tools/preproc/asm_file.cpp index 5a2a54aac062..7eca0850401a 100644 --- a/tools/preproc/asm_file.cpp +++ b/tools/preproc/asm_file.cpp @@ -152,6 +152,8 @@ Directive AsmFile::GetDirective() return Directive::String; else if (CheckForDirective(".braille")) return Directive::Braille; + else if (CheckForDirective("enum")) + return Directive::Enum; else return Directive::Unknown; } @@ -505,6 +507,63 @@ void AsmFile::OutputLine() } } +// parses an assumed C `enum`. Returns false if `enum { ...` is not matched +bool AsmFile::ParseEnum() +{ + long fallbackPosition = m_pos; + std::string headerFilename = ""; + long currentHeaderLine = SkipWhitespaceAndEol(); + std::string enumName = ReadIdentifier(); + currentHeaderLine += SkipWhitespaceAndEol(); + long enumCounter = 0; + long symbolCount = 0; + + if (m_buffer[m_pos] != '{') // assume assembly macro, otherwise assume enum and report errors accordingly + { + m_pos = fallbackPosition - 4; + return false; + } + + currentHeaderLine += FindLastLineNumber(headerFilename); + m_pos++; + for (;;) + { + currentHeaderLine += SkipWhitespaceAndEol(); + std::string currentIdentName = ReadIdentifier(); + if (currentIdentName.empty() && symbolCount == 0) + { + RaiseError("%s:%ld: empty enum is invalid", headerFilename.c_str(), currentHeaderLine); + } + std::printf("# %ld \"%s\"\n", currentHeaderLine, headerFilename.c_str()); + currentHeaderLine += SkipWhitespaceAndEol(); + if (m_buffer[m_pos] == '=') + { + m_pos++; + currentHeaderLine += SkipWhitespaceAndEol(); + enumCounter = ReadInteger(headerFilename, currentHeaderLine); + currentHeaderLine += SkipWhitespaceAndEol(); + } + + std::printf(".equiv %s, %ld\n", currentIdentName.c_str(), enumCounter); + enumCounter++; + if (m_buffer[m_pos] != ',') + { + currentHeaderLine += SkipWhitespaceAndEol(); + if (m_buffer[m_pos++] == '}' && m_buffer[m_pos++] == ';') + { + ExpectEmptyRestOfLine(); + break; + } + else + { + RaiseError("unterminated enum from included file %s:%ld", headerFilename.c_str(), currentHeaderLine); + } + } + m_pos++; + } + return true; +} + // Asserts that the rest of the line is empty and moves to the next one. void AsmFile::ExpectEmptyRestOfLine() { @@ -577,3 +636,130 @@ void AsmFile::RaiseWarning(const char* format, ...) { DO_REPORT("warning"); } + +// Skips Whitespace including newlines and returns the amount of newlines skipped +int AsmFile::SkipWhitespaceAndEol() +{ + int newlines = 0; + while (m_buffer[m_pos] == '\t' || m_buffer[m_pos] == ' ' || m_buffer[m_pos] == '\n') + { + if (m_buffer[m_pos] == '\n') + newlines++; + m_pos++; + } + return newlines; +} + +// returns the last line indicator and its corresponding file name without modifying the token index +int AsmFile::FindLastLineNumber(std::string& filename) +{ + long pos = m_pos; + long linebreaks = 0; + while (m_buffer[pos] != '#' && pos >= 0) + { + if (m_buffer[pos] == '\n') + linebreaks++; + pos--; + } + + if (pos < 0) + RaiseError("line indicator for header file not found before `enum`"); + + pos++; + while (m_buffer[pos] == ' ' || m_buffer[pos] == '\t') + pos++; + + if (!IsAsciiDigit(m_buffer[pos])) + RaiseError("malformatted line indicator found before `enum`, expected line number"); + + unsigned n = 0; + int digit = 0; + while ((digit = ConvertDigit(m_buffer[pos++], 10)) != -1) + n = 10 * n + digit; + + while (m_buffer[pos] == ' ' || m_buffer[pos] == '\t') + pos++; + + if (m_buffer[pos++] != '"') + RaiseError("malformatted line indicator found before `enum`, expected filename"); + + while (m_buffer[pos] != '"') + { + unsigned char c = m_buffer[pos++]; + + if (c == 0) + { + if (pos >= m_size) + RaiseError("unexpected EOF in line indicator"); + else + RaiseError("unexpected null character in line indicator"); + } + + if (!IsAsciiPrintable(c)) + RaiseError("unexpected character '\\x%02X' in line indicator", c); + + if (c == '\\') + { + c = m_buffer[pos]; + RaiseError("unexpected escape '\\%c' in line indicator", c); + } + + filename += c; + } + + return n + linebreaks - 1; +} + +std::string AsmFile::ReadIdentifier() +{ + long start = m_pos; + if (!IsIdentifierStartingChar(m_buffer[m_pos])) + return std::string(); + + m_pos++; + + while (IsIdentifierChar(m_buffer[m_pos])) + m_pos++; + + return std::string(&m_buffer[start], m_pos - start); +} + +long AsmFile::ReadInteger(std::string filename, long line) +{ + bool negate = false; + int radix = 10; + if (!IsAsciiDigit(m_buffer[m_pos])) + { + if (m_buffer[m_pos++] == '-') + negate = true; + else + RaiseError("expected number in included file %s:%ld", filename.c_str(), line); + } + + if (m_buffer[m_pos] == '0' && m_buffer[m_pos + 1] == 'x') + { + radix = 16; + m_pos += 2; + } + else if (m_buffer[m_pos] == '0' && m_buffer[m_pos + 1] == 'b') + { + radix = 2; + m_pos += 2; + } + else if (m_buffer[m_pos] == '0' && IsAsciiDigit(m_buffer[m_pos+1])) + { + radix = 8; + m_pos++; + } + + long n = 0; + int digit; + + while ((digit = ConvertDigit(m_buffer[m_pos], radix)) != -1) + { + n = n * radix + digit; + m_pos++; + } + + return negate ? -n : n; +} diff --git a/tools/preproc/asm_file.h b/tools/preproc/asm_file.h index ec0291827c36..83ed9c2e0deb 100644 --- a/tools/preproc/asm_file.h +++ b/tools/preproc/asm_file.h @@ -31,6 +31,7 @@ enum class Directive Include, String, Braille, + Enum, Unknown }; @@ -49,6 +50,7 @@ class AsmFile bool IsAtEnd(); void OutputLine(); void OutputLocation(); + bool ParseEnum(); private: char* m_buffer; @@ -68,6 +70,10 @@ class AsmFile void RaiseError(const char* format, ...); void RaiseWarning(const char* format, ...); void VerifyStringLength(int length); + int SkipWhitespaceAndEol(); + int FindLastLineNumber(std::string& filename); + std::string ReadIdentifier(); + long ReadInteger(std::string filename, long line); }; #endif // ASM_FILE_H diff --git a/tools/preproc/io.h b/tools/preproc/io.h index b7b1994d1d21..ac4e91051f1c 100644 --- a/tools/preproc/io.h +++ b/tools/preproc/io.h @@ -5,4 +5,4 @@ char *ReadFileToBuffer(const char *filename, bool isStdin, long *size); -#endif // IO_H_ \ No newline at end of file +#endif // IO_H_ diff --git a/tools/preproc/preproc.cpp b/tools/preproc/preproc.cpp index ed6fd32839e6..9926a04b812f 100644 --- a/tools/preproc/preproc.cpp +++ b/tools/preproc/preproc.cpp @@ -48,6 +48,7 @@ void PreprocAsmFile(std::string filename, bool isStdin) std::stack stack; stack.push(AsmFile(filename, isStdin)); + std::printf("# 1 \"%s\"\n", filename.c_str()); for (;;) { @@ -83,6 +84,12 @@ void PreprocAsmFile(std::string filename, bool isStdin) PrintAsmBytes(s, length); break; } + case Directive::Enum: + { + if (!stack.top().ParseEnum()) + stack.top().OutputLine(); + break; + } case Directive::Unknown: { std::string globalLabel = stack.top().GetGlobalLabel(); From f28f3af4a51d54dd1eec08a2c989ad3f429b631a Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Tue, 9 Jul 2024 07:49:16 +0100 Subject: [PATCH 3/5] [preproc] parse enum only in 2nd pass --- Makefile | 4 +- tools/preproc/asm_file.cpp | 35 +++++++++----- tools/preproc/asm_file.h | 3 +- tools/preproc/preproc.cpp | 97 +++++++++++++++++++++++++------------- 4 files changed, 91 insertions(+), 48 deletions(-) diff --git a/Makefile b/Makefile index fceee4e138f3..93448b1272c3 100644 --- a/Makefile +++ b/Makefile @@ -367,7 +367,7 @@ $(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s else define SRC_ASM_DATA_DEP $1: $2 $$(shell $(SCANINC) -I include -I "" $2) - $$(PREPROC) $$< charmap.txt | $$(CPP) -I include - | $$(PREPROC) $$< charmap.txt -i | $$(AS) $$(ASFLAGS) -o $$@ + $$(PREPROC) $$< charmap.txt | $$(CPP) -I include - | $$(PREPROC) $$< charmap.txt -i -e | $$(AS) $$(ASFLAGS) -o $$@ endef $(foreach src, $(C_ASM_SRCS), $(eval $(call SRC_ASM_DATA_DEP,$(patsubst $(C_SUBDIR)/%.s,$(C_BUILDDIR)/%.o, $(src)),$(src)))) endif @@ -385,7 +385,7 @@ endif ifeq ($(NODEP),1) $(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s - $(PREPROC) $< charmap.txt | $(CPP) -I include - | $(PREPROC) $$< charmap.txt -i | $(AS) $(ASFLAGS) -o $@ + $(PREPROC) $< charmap.txt | $(CPP) -I include - | $(PREPROC) $$< charmap.txt -i -e | $(AS) $(ASFLAGS) -o $@ else $(foreach src, $(REGULAR_DATA_ASM_SRCS), $(eval $(call SRC_ASM_DATA_DEP,$(patsubst $(DATA_ASM_SUBDIR)/%.s,$(DATA_ASM_BUILDDIR)/%.o, $(src)),$(src)))) endif diff --git a/tools/preproc/asm_file.cpp b/tools/preproc/asm_file.cpp index 7eca0850401a..ca8b8cc4ae96 100644 --- a/tools/preproc/asm_file.cpp +++ b/tools/preproc/asm_file.cpp @@ -29,9 +29,10 @@ #include "../../gflib/characters.h" #include "io.h" -AsmFile::AsmFile(std::string filename, bool isStdin) : m_filename(filename) +AsmFile::AsmFile(std::string filename, bool isStdin, bool doEnum) : m_filename(filename) { m_buffer = ReadFileToBuffer(filename.c_str(), isStdin, &m_size); + m_doEnum = doEnum; m_pos = 0; m_lineNum = 1; @@ -43,6 +44,7 @@ AsmFile::AsmFile(std::string filename, bool isStdin) : m_filename(filename) AsmFile::AsmFile(AsmFile&& other) : m_filename(std::move(other.m_filename)) { m_buffer = other.m_buffer; + m_doEnum = other.m_doEnum; m_pos = other.m_pos; m_size = other.m_size; m_lineNum = other.m_lineNum; @@ -510,6 +512,9 @@ void AsmFile::OutputLine() // parses an assumed C `enum`. Returns false if `enum { ...` is not matched bool AsmFile::ParseEnum() { + if (!m_doEnum) + return false; + long fallbackPosition = m_pos; std::string headerFilename = ""; long currentHeaderLine = SkipWhitespaceAndEol(); @@ -530,22 +535,26 @@ bool AsmFile::ParseEnum() { currentHeaderLine += SkipWhitespaceAndEol(); std::string currentIdentName = ReadIdentifier(); - if (currentIdentName.empty() && symbolCount == 0) + if (!currentIdentName.empty()) { - RaiseError("%s:%ld: empty enum is invalid", headerFilename.c_str(), currentHeaderLine); + std::printf("# %ld \"%s\"\n", currentHeaderLine, headerFilename.c_str()); + currentHeaderLine += SkipWhitespaceAndEol(); + if (m_buffer[m_pos] == '=') + { + m_pos++; + currentHeaderLine += SkipWhitespaceAndEol(); + enumCounter = ReadInteger(headerFilename, currentHeaderLine); + currentHeaderLine += SkipWhitespaceAndEol(); + } + std::printf(".equiv %s, %ld\n", currentIdentName.c_str(), enumCounter); + enumCounter++; + symbolCount++; } - std::printf("# %ld \"%s\"\n", currentHeaderLine, headerFilename.c_str()); - currentHeaderLine += SkipWhitespaceAndEol(); - if (m_buffer[m_pos] == '=') + else if (symbolCount == 0) { - m_pos++; - currentHeaderLine += SkipWhitespaceAndEol(); - enumCounter = ReadInteger(headerFilename, currentHeaderLine); - currentHeaderLine += SkipWhitespaceAndEol(); + RaiseError("%s:%ld: empty enum is invalid", headerFilename.c_str(), currentHeaderLine); } - - std::printf(".equiv %s, %ld\n", currentIdentName.c_str(), enumCounter); - enumCounter++; + if (m_buffer[m_pos] != ',') { currentHeaderLine += SkipWhitespaceAndEol(); diff --git a/tools/preproc/asm_file.h b/tools/preproc/asm_file.h index 83ed9c2e0deb..33e6ce5c49c1 100644 --- a/tools/preproc/asm_file.h +++ b/tools/preproc/asm_file.h @@ -38,7 +38,7 @@ enum class Directive class AsmFile { public: - AsmFile(std::string filename, bool isStdin); + AsmFile(std::string filename, bool isStdin, bool doEnum); AsmFile(AsmFile&& other); AsmFile(const AsmFile&) = delete; ~AsmFile(); @@ -54,6 +54,7 @@ class AsmFile private: char* m_buffer; + bool m_doEnum; long m_pos; long m_size; long m_lineNum; diff --git a/tools/preproc/preproc.cpp b/tools/preproc/preproc.cpp index 9926a04b812f..f573ccb90216 100644 --- a/tools/preproc/preproc.cpp +++ b/tools/preproc/preproc.cpp @@ -20,11 +20,14 @@ #include #include +#include #include "preproc.h" #include "asm_file.h" #include "c_file.h" #include "charmap.h" +static void UsageAndExit(const char *program); + Charmap* g_charmap; void PrintAsmBytes(unsigned char *s, int length) @@ -43,11 +46,11 @@ void PrintAsmBytes(unsigned char *s, int length) } } -void PreprocAsmFile(std::string filename, bool isStdin) +void PreprocAsmFile(std::string filename, bool isStdin, bool doEnum) { std::stack stack; - stack.push(AsmFile(filename, isStdin)); + stack.push(AsmFile(filename, isStdin, doEnum)); std::printf("# 1 \"%s\"\n", filename.c_str()); for (;;) @@ -67,7 +70,7 @@ void PreprocAsmFile(std::string filename, bool isStdin) switch (directive) { case Directive::Include: - stack.push(AsmFile(stack.top().ReadPath(), false)); + stack.push(AsmFile(stack.top().ReadPath(), false, doEnum)); stack.top().OutputLocation(); break; case Directive::String: @@ -116,9 +119,9 @@ void PreprocCFile(const char * filename, bool isStdin) cFile.Preproc(); } -char* GetFileExtension(char* filename) +const char* GetFileExtension(const char* filename) { - char* extension = filename; + const char* extension = filename; while (*extension != 0) extension++; @@ -137,45 +140,75 @@ char* GetFileExtension(char* filename) return extension; } +static void UsageAndExit(const char *program) +{ + std::fprintf(stderr, "Usage: %s SRC_FILE CHARMAP_FILE [-i] [-e]\nwhere -i denotes if input is from stdin\n -e enables enum handling\n", program); + std::exit(EXIT_FAILURE); +} + int main(int argc, char **argv) { - if (argc < 3 || argc > 4) + int opt; + const char *source = NULL; + const char *charmap = NULL; + bool isStdin = false; + bool doEnum = false; + + /* preproc SRC_FILE CHARMAP_FILE [-i] [-e] */ + while ((opt = getopt(argc, argv, "-ie")) != -1) { - std::fprintf(stderr, "Usage: %s SRC_FILE CHARMAP_FILE [-i]\nwhere -i denotes if input is from stdin\n", argv[0]); - return 1; + switch (opt) + { + case 1: // positional. + switch (optind) + { + case 2: + source = optarg; + break; + case 3: + charmap = optarg; + break; + default: + UsageAndExit(argv[0]); + break; + } + break; + case 'i': + isStdin = true; + break; + case 'e': + doEnum = true; + break; + default: + UsageAndExit(argv[0]); + break; + } } - g_charmap = new Charmap(argv[2]); + if (optind != argc || !source || !charmap) + UsageAndExit(argv[0]); + + g_charmap = new Charmap(charmap); - char* extension = GetFileExtension(argv[1]); + const char* extension = GetFileExtension(source); if (!extension) FATAL_ERROR("\"%s\" has no file extension.\n", argv[1]); - if ((extension[0] == 's') && extension[1] == 0) { - if (argc == 4) { - if (argv[3][0] == '-' && argv[3][1] == 'i' && argv[3][2] == '\0') { - PreprocAsmFile(argv[1], true); - } else { - FATAL_ERROR("unknown argument flag \"%s\".\n", argv[3]); - } - } else { - PreprocAsmFile(argv[1], false); - } - + if ((extension[0] == 's') && extension[1] == 0) + { + PreprocAsmFile(source, isStdin, doEnum); } - else if ((extension[0] == 'c' || extension[0] == 'i') && extension[1] == 0) { - if (argc == 4) { - if (argv[3][0] == '-' && argv[3][1] == 'i' && argv[3][2] == '\0') { - PreprocCFile(argv[1], true); - } else { - FATAL_ERROR("unknown argument flag \"%s\".\n", argv[3]); - } - } else { - PreprocCFile(argv[1], false); - } - } else + else if ((extension[0] == 'c' || extension[0] == 'i') && extension[1] == 0) + { + if (doEnum) + FATAL_ERROR("-e is invalid for C sources\n"); + PreprocCFile(source, isStdin); + } + else + { FATAL_ERROR("\"%s\" has an unknown file extension of \"%s\".\n", argv[1], extension); + } return 0; } From cdda6733389b397baeca29fd1ca71620fee8ae78 Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Tue, 9 Jul 2024 07:59:09 +0100 Subject: [PATCH 4/5] cerrno --- tools/preproc/io.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/preproc/io.cpp b/tools/preproc/io.cpp index 1572072cb4e4..321676180d70 100644 --- a/tools/preproc/io.cpp +++ b/tools/preproc/io.cpp @@ -1,6 +1,7 @@ #include "preproc.h" #include "io.h" #include +#include #include char *ReadFileToBuffer(const char *filename, bool isStdin, long *size) From c1d6ef35c9cc2b7741bf29b663736b6239aed68f Mon Sep 17 00:00:00 2001 From: Martin Griffin Date: Fri, 12 Jul 2024 14:44:22 +0100 Subject: [PATCH 5/5] [preproc] positional arguments at end of command --- Makefile | 14 +++++++------- tools/preproc/preproc.cpp | 25 +++++++------------------ 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/Makefile b/Makefile index 93448b1272c3..8a3b3020df8e 100644 --- a/Makefile +++ b/Makefile @@ -311,7 +311,7 @@ ifeq ($(NODEP),1) $(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.c ifeq (,$(KEEP_TEMPS)) @echo "$(CC1) -o $@ $<" - @$(CPP) $(CPPFLAGS) $< | $(PREPROC) $< charmap.txt -i | $(CC1) $(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $(AS) $(ASFLAGS) -o $@ - + @$(CPP) $(CPPFLAGS) $< | $(PREPROC) -i $< charmap.txt | $(CC1) $(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $(AS) $(ASFLAGS) -o $@ - else @$(CPP) $(CPPFLAGS) $< -o $(C_BUILDDIR)/$*.i @$(PREPROC) $(C_BUILDDIR)/$*.i charmap.txt | $(CC1) $(CFLAGS) -o $(C_BUILDDIR)/$*.s @@ -323,7 +323,7 @@ define C_DEP $1: $2 $$(shell $(SCANINC) -I include -I tools/agbcc/include -I gflib $2) ifeq (,$$(KEEP_TEMPS)) @echo "$$(CC1) -o $$@ $$<" - @$$(CPP) $$(CPPFLAGS) $$< | $$(PREPROC) $$< charmap.txt -i | $$(CC1) $$(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $$(AS) $$(ASFLAGS) -o $$@ - + @$$(CPP) $$(CPPFLAGS) $$< | $$(PREPROC) -i $$< charmap.txt | $$(CC1) $$(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $$(AS) $$(ASFLAGS) -o $$@ - else @$$(CPP) $$(CPPFLAGS) $$< -o $$(C_BUILDDIR)/$3.i @$$(PREPROC) $$(C_BUILDDIR)/$3.i charmap.txt | $$(CC1) $$(CFLAGS) -o $$(C_BUILDDIR)/$3.s @@ -338,7 +338,7 @@ ifeq ($(NODEP),1) $(GFLIB_BUILDDIR)/%.o: $(GFLIB_SUBDIR)/%.c $$(c_dep) ifeq (,$(KEEP_TEMPS)) @echo "$(CC1) -o $@ $<" - @$(CPP) $(CPPFLAGS) $< | $(PREPROC) $< charmap.txt -i | $(CC1) $(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $(AS) $(ASFLAGS) -o $@ - + @$(CPP) $(CPPFLAGS) $< | $(PREPROC) -i $< charmap.txt | $(CC1) $(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $(AS) $(ASFLAGS) -o $@ - else @$(CPP) $(CPPFLAGS) $< -o $(GFLIB_BUILDDIR)/$*.i @$(PREPROC) $(GFLIB_BUILDDIR)/$*.i charmap.txt | $(CC1) $(CFLAGS) -o $(GFLIB_BUILDDIR)/$*.s @@ -350,7 +350,7 @@ define GFLIB_DEP $1: $2 $$(shell $(SCANINC) -I include -I tools/agbcc/include -I gflib $2) ifeq (,$$(KEEP_TEMPS)) @echo "$$(CC1) -o $$@ $$<" - @$$(CPP) $$(CPPFLAGS) $$< | $$(PREPROC) $$< charmap.txt -i | $$(CC1) $$(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $$(AS) $$(ASFLAGS) -o $$@ - + @$$(CPP) $$(CPPFLAGS) $$< | $$(PREPROC) -i $$< charmap.txt | $$(CC1) $$(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $$(AS) $$(ASFLAGS) -o $$@ - else @$$(CPP) $$(CPPFLAGS) $$< -o $$(GFLIB_BUILDDIR)/$3.i @$$(PREPROC) $$(GFLIB_BUILDDIR)/$3.i charmap.txt | $$(CC1) $$(CFLAGS) -o $$(GFLIB_BUILDDIR)/$3.s @@ -363,11 +363,11 @@ endif ifeq ($(NODEP),1) $(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s - $(PREPROC) $< charmap.txt | $(CPP) -I include - | $(PREPROC) $$< charmap.txt -i | $(AS) $(ASFLAGS) -o $@ + $(PREPROC) $< charmap.txt | $(CPP) -I include - | $(PREPROC) -i $$< charmap.txt | $(AS) $(ASFLAGS) -o $@ else define SRC_ASM_DATA_DEP $1: $2 $$(shell $(SCANINC) -I include -I "" $2) - $$(PREPROC) $$< charmap.txt | $$(CPP) -I include - | $$(PREPROC) $$< charmap.txt -i -e | $$(AS) $$(ASFLAGS) -o $$@ + $$(PREPROC) $$< charmap.txt | $$(CPP) -I include - | $$(PREPROC) -ie $$< charmap.txt | $$(AS) $$(ASFLAGS) -o $$@ endef $(foreach src, $(C_ASM_SRCS), $(eval $(call SRC_ASM_DATA_DEP,$(patsubst $(C_SUBDIR)/%.s,$(C_BUILDDIR)/%.o, $(src)),$(src)))) endif @@ -385,7 +385,7 @@ endif ifeq ($(NODEP),1) $(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s - $(PREPROC) $< charmap.txt | $(CPP) -I include - | $(PREPROC) $$< charmap.txt -i -e | $(AS) $(ASFLAGS) -o $@ + $(PREPROC) $< charmap.txt | $(CPP) -I include - | $(PREPROC) -ie $$< charmap.txt | $(AS) $(ASFLAGS) -o $@ else $(foreach src, $(REGULAR_DATA_ASM_SRCS), $(eval $(call SRC_ASM_DATA_DEP,$(patsubst $(DATA_ASM_SUBDIR)/%.s,$(DATA_ASM_BUILDDIR)/%.o, $(src)),$(src)))) endif diff --git a/tools/preproc/preproc.cpp b/tools/preproc/preproc.cpp index f573ccb90216..20c2de51b635 100644 --- a/tools/preproc/preproc.cpp +++ b/tools/preproc/preproc.cpp @@ -142,7 +142,7 @@ const char* GetFileExtension(const char* filename) static void UsageAndExit(const char *program) { - std::fprintf(stderr, "Usage: %s SRC_FILE CHARMAP_FILE [-i] [-e]\nwhere -i denotes if input is from stdin\n -e enables enum handling\n", program); + std::fprintf(stderr, "Usage: %s [-i] [-e] SRC_FILE CHARMAP_FILE\nwhere -i denotes if input is from stdin\n -e enables enum handling\n", program); std::exit(EXIT_FAILURE); } @@ -154,25 +154,11 @@ int main(int argc, char **argv) bool isStdin = false; bool doEnum = false; - /* preproc SRC_FILE CHARMAP_FILE [-i] [-e] */ - while ((opt = getopt(argc, argv, "-ie")) != -1) + /* preproc [-i] [-e] SRC_FILE CHARMAP_FILE */ + while ((opt = getopt(argc, argv, "ie")) != -1) { switch (opt) { - case 1: // positional. - switch (optind) - { - case 2: - source = optarg; - break; - case 3: - charmap = optarg; - break; - default: - UsageAndExit(argv[0]); - break; - } - break; case 'i': isStdin = true; break; @@ -185,9 +171,12 @@ int main(int argc, char **argv) } } - if (optind != argc || !source || !charmap) + if (optind + 2 != argc) UsageAndExit(argv[0]); + source = argv[optind + 0]; + charmap = argv[optind + 1]; + g_charmap = new Charmap(charmap); const char* extension = GetFileExtension(source);