Support C-Style enum in preproc (#1984)
* [preproc] C-style enums - asm files parseable from stdin - 2nd preproc pass - add parser for C-style `enum` - positional arguments at end of command --------- Co-authored-by: sbird <sbird@no.tld> Co-authored-by: Martin Griffin <martinrgriffin@gmail.com>
This commit is contained in:
@@ -311,7 +311,7 @@ ifeq ($(NODEP),1)
|
|||||||
$(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.c
|
$(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.c
|
||||||
ifeq (,$(KEEP_TEMPS))
|
ifeq (,$(KEEP_TEMPS))
|
||||||
@echo "$(CC1) <flags> -o $@ $<"
|
@echo "$(CC1) <flags> -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
|
else
|
||||||
@$(CPP) $(CPPFLAGS) $< -o $(C_BUILDDIR)/$*.i
|
@$(CPP) $(CPPFLAGS) $< -o $(C_BUILDDIR)/$*.i
|
||||||
@$(PREPROC) $(C_BUILDDIR)/$*.i charmap.txt | $(CC1) $(CFLAGS) -o $(C_BUILDDIR)/$*.s
|
@$(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)
|
$1: $2 $$(shell $(SCANINC) -I include -I tools/agbcc/include -I gflib $2)
|
||||||
ifeq (,$$(KEEP_TEMPS))
|
ifeq (,$$(KEEP_TEMPS))
|
||||||
@echo "$$(CC1) <flags> -o $$@ $$<"
|
@echo "$$(CC1) <flags> -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
|
else
|
||||||
@$$(CPP) $$(CPPFLAGS) $$< -o $$(C_BUILDDIR)/$3.i
|
@$$(CPP) $$(CPPFLAGS) $$< -o $$(C_BUILDDIR)/$3.i
|
||||||
@$$(PREPROC) $$(C_BUILDDIR)/$3.i charmap.txt | $$(CC1) $$(CFLAGS) -o $$(C_BUILDDIR)/$3.s
|
@$$(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)
|
$(GFLIB_BUILDDIR)/%.o: $(GFLIB_SUBDIR)/%.c $$(c_dep)
|
||||||
ifeq (,$(KEEP_TEMPS))
|
ifeq (,$(KEEP_TEMPS))
|
||||||
@echo "$(CC1) <flags> -o $@ $<"
|
@echo "$(CC1) <flags> -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
|
else
|
||||||
@$(CPP) $(CPPFLAGS) $< -o $(GFLIB_BUILDDIR)/$*.i
|
@$(CPP) $(CPPFLAGS) $< -o $(GFLIB_BUILDDIR)/$*.i
|
||||||
@$(PREPROC) $(GFLIB_BUILDDIR)/$*.i charmap.txt | $(CC1) $(CFLAGS) -o $(GFLIB_BUILDDIR)/$*.s
|
@$(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)
|
$1: $2 $$(shell $(SCANINC) -I include -I tools/agbcc/include -I gflib $2)
|
||||||
ifeq (,$$(KEEP_TEMPS))
|
ifeq (,$$(KEEP_TEMPS))
|
||||||
@echo "$$(CC1) <flags> -o $$@ $$<"
|
@echo "$$(CC1) <flags> -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
|
else
|
||||||
@$$(CPP) $$(CPPFLAGS) $$< -o $$(GFLIB_BUILDDIR)/$3.i
|
@$$(CPP) $$(CPPFLAGS) $$< -o $$(GFLIB_BUILDDIR)/$3.i
|
||||||
@$$(PREPROC) $$(GFLIB_BUILDDIR)/$3.i charmap.txt | $$(CC1) $$(CFLAGS) -o $$(GFLIB_BUILDDIR)/$3.s
|
@$$(PREPROC) $$(GFLIB_BUILDDIR)/$3.i charmap.txt | $$(CC1) $$(CFLAGS) -o $$(GFLIB_BUILDDIR)/$3.s
|
||||||
@@ -363,11 +363,11 @@ endif
|
|||||||
|
|
||||||
ifeq ($(NODEP),1)
|
ifeq ($(NODEP),1)
|
||||||
$(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s
|
$(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s
|
||||||
$(PREPROC) $< charmap.txt | $(CPP) -I include - | $(AS) $(ASFLAGS) -o $@
|
$(PREPROC) $< charmap.txt | $(CPP) -I include - | $(PREPROC) -i $$< charmap.txt | $(AS) $(ASFLAGS) -o $@
|
||||||
else
|
else
|
||||||
define SRC_ASM_DATA_DEP
|
define SRC_ASM_DATA_DEP
|
||||||
$1: $2 $$(shell $(SCANINC) -I include -I "" $2)
|
$1: $2 $$(shell $(SCANINC) -I include -I "" $2)
|
||||||
$$(PREPROC) $$< charmap.txt | $$(CPP) -I include - | $$(AS) $$(ASFLAGS) -o $$@
|
$$(PREPROC) $$< charmap.txt | $$(CPP) -I include - | $$(PREPROC) -ie $$< charmap.txt | $$(AS) $$(ASFLAGS) -o $$@
|
||||||
endef
|
endef
|
||||||
$(foreach src, $(C_ASM_SRCS), $(eval $(call SRC_ASM_DATA_DEP,$(patsubst $(C_SUBDIR)/%.s,$(C_BUILDDIR)/%.o, $(src)),$(src))))
|
$(foreach src, $(C_ASM_SRCS), $(eval $(call SRC_ASM_DATA_DEP,$(patsubst $(C_SUBDIR)/%.s,$(C_BUILDDIR)/%.o, $(src)),$(src))))
|
||||||
endif
|
endif
|
||||||
@@ -385,7 +385,7 @@ endif
|
|||||||
|
|
||||||
ifeq ($(NODEP),1)
|
ifeq ($(NODEP),1)
|
||||||
$(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s
|
$(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s
|
||||||
$(PREPROC) $< charmap.txt | $(CPP) -I include - | $(AS) $(ASFLAGS) -o $@
|
$(PREPROC) $< charmap.txt | $(CPP) -I include - | $(PREPROC) -ie $$< charmap.txt | $(AS) $(ASFLAGS) -o $@
|
||||||
else
|
else
|
||||||
$(foreach src, $(REGULAR_DATA_ASM_SRCS), $(eval $(call SRC_ASM_DATA_DEP,$(patsubst $(DATA_ASM_SUBDIR)/%.s,$(DATA_ASM_BUILDDIR)/%.o, $(src)),$(src))))
|
$(foreach src, $(REGULAR_DATA_ASM_SRCS), $(eval $(call SRC_ASM_DATA_DEP,$(patsubst $(DATA_ASM_SUBDIR)/%.s,$(DATA_ASM_BUILDDIR)/%.o, $(src)),$(src))))
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ CXX ?= g++
|
|||||||
CXXFLAGS := -std=c++11 -O2 -Wall -Wno-switch -Werror
|
CXXFLAGS := -std=c++11 -O2 -Wall -Wno-switch -Werror
|
||||||
|
|
||||||
SRCS := asm_file.cpp c_file.cpp charmap.cpp preproc.cpp string_parser.cpp \
|
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 \
|
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)
|
ifeq ($(OS),Windows_NT)
|
||||||
EXE := .exe
|
EXE := .exe
|
||||||
|
|||||||
+198
-25
@@ -27,33 +27,12 @@
|
|||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
#include "string_parser.h"
|
#include "string_parser.h"
|
||||||
#include "../../gflib/characters.h"
|
#include "../../gflib/characters.h"
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
AsmFile::AsmFile(std::string filename) : m_filename(filename)
|
AsmFile::AsmFile(std::string filename, bool isStdin, bool doEnum) : m_filename(filename)
|
||||||
{
|
{
|
||||||
FILE *fp = std::fopen(filename.c_str(), "rb");
|
m_buffer = ReadFileToBuffer(filename.c_str(), isStdin, &m_size);
|
||||||
|
m_doEnum = doEnum;
|
||||||
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_pos = 0;
|
m_pos = 0;
|
||||||
m_lineNum = 1;
|
m_lineNum = 1;
|
||||||
@@ -65,6 +44,7 @@ AsmFile::AsmFile(std::string filename) : m_filename(filename)
|
|||||||
AsmFile::AsmFile(AsmFile&& other) : m_filename(std::move(other.m_filename))
|
AsmFile::AsmFile(AsmFile&& other) : m_filename(std::move(other.m_filename))
|
||||||
{
|
{
|
||||||
m_buffer = other.m_buffer;
|
m_buffer = other.m_buffer;
|
||||||
|
m_doEnum = other.m_doEnum;
|
||||||
m_pos = other.m_pos;
|
m_pos = other.m_pos;
|
||||||
m_size = other.m_size;
|
m_size = other.m_size;
|
||||||
m_lineNum = other.m_lineNum;
|
m_lineNum = other.m_lineNum;
|
||||||
@@ -174,6 +154,8 @@ Directive AsmFile::GetDirective()
|
|||||||
return Directive::String;
|
return Directive::String;
|
||||||
else if (CheckForDirective(".braille"))
|
else if (CheckForDirective(".braille"))
|
||||||
return Directive::Braille;
|
return Directive::Braille;
|
||||||
|
else if (CheckForDirective("enum"))
|
||||||
|
return Directive::Enum;
|
||||||
else
|
else
|
||||||
return Directive::Unknown;
|
return Directive::Unknown;
|
||||||
}
|
}
|
||||||
@@ -527,6 +509,70 @@ 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();
|
||||||
|
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())
|
||||||
|
{
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
else if (symbolCount == 0)
|
||||||
|
{
|
||||||
|
RaiseError("%s:%ld: empty enum is invalid", headerFilename.c_str(), currentHeaderLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
// Asserts that the rest of the line is empty and moves to the next one.
|
||||||
void AsmFile::ExpectEmptyRestOfLine()
|
void AsmFile::ExpectEmptyRestOfLine()
|
||||||
{
|
{
|
||||||
@@ -599,3 +645,130 @@ void AsmFile::RaiseWarning(const char* format, ...)
|
|||||||
{
|
{
|
||||||
DO_REPORT("warning");
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,13 +31,14 @@ enum class Directive
|
|||||||
Include,
|
Include,
|
||||||
String,
|
String,
|
||||||
Braille,
|
Braille,
|
||||||
|
Enum,
|
||||||
Unknown
|
Unknown
|
||||||
};
|
};
|
||||||
|
|
||||||
class AsmFile
|
class AsmFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AsmFile(std::string filename);
|
AsmFile(std::string filename, bool isStdin, bool doEnum);
|
||||||
AsmFile(AsmFile&& other);
|
AsmFile(AsmFile&& other);
|
||||||
AsmFile(const AsmFile&) = delete;
|
AsmFile(const AsmFile&) = delete;
|
||||||
~AsmFile();
|
~AsmFile();
|
||||||
@@ -49,9 +50,11 @@ public:
|
|||||||
bool IsAtEnd();
|
bool IsAtEnd();
|
||||||
void OutputLine();
|
void OutputLine();
|
||||||
void OutputLocation();
|
void OutputLocation();
|
||||||
|
bool ParseEnum();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char* m_buffer;
|
char* m_buffer;
|
||||||
|
bool m_doEnum;
|
||||||
long m_pos;
|
long m_pos;
|
||||||
long m_size;
|
long m_size;
|
||||||
long m_lineNum;
|
long m_lineNum;
|
||||||
@@ -68,6 +71,10 @@ private:
|
|||||||
void RaiseError(const char* format, ...);
|
void RaiseError(const char* format, ...);
|
||||||
void RaiseWarning(const char* format, ...);
|
void RaiseWarning(const char* format, ...);
|
||||||
void VerifyStringLength(int length);
|
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
|
#endif // ASM_FILE_H
|
||||||
|
|||||||
@@ -30,56 +30,16 @@
|
|||||||
#include "char_util.h"
|
#include "char_util.h"
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
#include "string_parser.h"
|
#include "string_parser.h"
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
CFile::CFile(const char * filenameCStr, bool isStdin)
|
CFile::CFile(const char * filenameCStr, bool isStdin)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
if (isStdin)
|
||||||
|
|
||||||
if (isStdin) {
|
|
||||||
fp = stdin;
|
|
||||||
m_filename = std::string{"<stdin>/"}.append(filenameCStr);
|
m_filename = std::string{"<stdin>/"}.append(filenameCStr);
|
||||||
} else {
|
else
|
||||||
fp = std::fopen(filenameCStr, "rb");
|
|
||||||
m_filename = std::string(filenameCStr);
|
m_filename = std::string(filenameCStr);
|
||||||
}
|
|
||||||
|
|
||||||
std::string& filename = m_filename;
|
m_buffer = ReadFileToBuffer(filenameCStr, isStdin, &m_size);
|
||||||
|
|
||||||
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_pos = 0;
|
m_pos = 0;
|
||||||
m_lineNum = 1;
|
m_lineNum = 1;
|
||||||
|
|||||||
@@ -56,6 +56,4 @@ private:
|
|||||||
void RaiseWarning(const char* format, ...);
|
void RaiseWarning(const char* format, ...);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CHUNK_SIZE 4096
|
|
||||||
|
|
||||||
#endif // C_FILE_H
|
#endif // C_FILE_H
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#include "preproc.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include <string>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -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_
|
||||||
+59
-20
@@ -20,11 +20,14 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
#include <unistd.h>
|
||||||
#include "preproc.h"
|
#include "preproc.h"
|
||||||
#include "asm_file.h"
|
#include "asm_file.h"
|
||||||
#include "c_file.h"
|
#include "c_file.h"
|
||||||
#include "charmap.h"
|
#include "charmap.h"
|
||||||
|
|
||||||
|
static void UsageAndExit(const char *program);
|
||||||
|
|
||||||
Charmap* g_charmap;
|
Charmap* g_charmap;
|
||||||
|
|
||||||
void PrintAsmBytes(unsigned char *s, int length)
|
void PrintAsmBytes(unsigned char *s, int length)
|
||||||
@@ -43,11 +46,12 @@ void PrintAsmBytes(unsigned char *s, int length)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreprocAsmFile(std::string filename)
|
void PreprocAsmFile(std::string filename, bool isStdin, bool doEnum)
|
||||||
{
|
{
|
||||||
std::stack<AsmFile> stack;
|
std::stack<AsmFile> stack;
|
||||||
|
|
||||||
stack.push(AsmFile(filename));
|
stack.push(AsmFile(filename, isStdin, doEnum));
|
||||||
|
std::printf("# 1 \"%s\"\n", filename.c_str());
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@@ -66,7 +70,7 @@ void PreprocAsmFile(std::string filename)
|
|||||||
switch (directive)
|
switch (directive)
|
||||||
{
|
{
|
||||||
case Directive::Include:
|
case Directive::Include:
|
||||||
stack.push(AsmFile(stack.top().ReadPath()));
|
stack.push(AsmFile(stack.top().ReadPath(), false, doEnum));
|
||||||
stack.top().OutputLocation();
|
stack.top().OutputLocation();
|
||||||
break;
|
break;
|
||||||
case Directive::String:
|
case Directive::String:
|
||||||
@@ -83,6 +87,12 @@ void PreprocAsmFile(std::string filename)
|
|||||||
PrintAsmBytes(s, length);
|
PrintAsmBytes(s, length);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Directive::Enum:
|
||||||
|
{
|
||||||
|
if (!stack.top().ParseEnum())
|
||||||
|
stack.top().OutputLine();
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Directive::Unknown:
|
case Directive::Unknown:
|
||||||
{
|
{
|
||||||
std::string globalLabel = stack.top().GetGlobalLabel();
|
std::string globalLabel = stack.top().GetGlobalLabel();
|
||||||
@@ -109,9 +119,9 @@ void PreprocCFile(const char * filename, bool isStdin)
|
|||||||
cFile.Preproc();
|
cFile.Preproc();
|
||||||
}
|
}
|
||||||
|
|
||||||
char* GetFileExtension(char* filename)
|
const char* GetFileExtension(const char* filename)
|
||||||
{
|
{
|
||||||
char* extension = filename;
|
const char* extension = filename;
|
||||||
|
|
||||||
while (*extension != 0)
|
while (*extension != 0)
|
||||||
extension++;
|
extension++;
|
||||||
@@ -130,35 +140,64 @@ char* GetFileExtension(char* filename)
|
|||||||
return extension;
|
return extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void UsageAndExit(const char *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);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
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 [-i] [-e] SRC_FILE CHARMAP_FILE */
|
||||||
|
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]);
|
switch (opt)
|
||||||
return 1;
|
{
|
||||||
|
case 'i':
|
||||||
|
isStdin = true;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
doEnum = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UsageAndExit(argv[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_charmap = new Charmap(argv[2]);
|
if (optind + 2 != argc)
|
||||||
|
UsageAndExit(argv[0]);
|
||||||
|
|
||||||
char* extension = GetFileExtension(argv[1]);
|
source = argv[optind + 0];
|
||||||
|
charmap = argv[optind + 1];
|
||||||
|
|
||||||
|
g_charmap = new Charmap(charmap);
|
||||||
|
|
||||||
|
const char* extension = GetFileExtension(source);
|
||||||
|
|
||||||
if (!extension)
|
if (!extension)
|
||||||
FATAL_ERROR("\"%s\" has no file extension.\n", argv[1]);
|
FATAL_ERROR("\"%s\" has no file extension.\n", argv[1]);
|
||||||
|
|
||||||
if ((extension[0] == 's') && extension[1] == 0)
|
if ((extension[0] == 's') && extension[1] == 0)
|
||||||
PreprocAsmFile(argv[1]);
|
{
|
||||||
else if ((extension[0] == 'c' || extension[0] == 'i') && extension[1] == 0) {
|
PreprocAsmFile(source, isStdin, doEnum);
|
||||||
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 {
|
else if ((extension[0] == 'c' || extension[0] == 'i') && extension[1] == 0)
|
||||||
PreprocCFile(argv[1], false);
|
{
|
||||||
|
if (doEnum)
|
||||||
|
FATAL_ERROR("-e is invalid for C sources\n");
|
||||||
|
PreprocCFile(source, isStdin);
|
||||||
}
|
}
|
||||||
} else
|
else
|
||||||
|
{
|
||||||
FATAL_ERROR("\"%s\" has an unknown file extension of \"%s\".\n", argv[1], extension);
|
FATAL_ERROR("\"%s\" has an unknown file extension of \"%s\".\n", argv[1], extension);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user