Skip to content

Commit

Permalink
[preproc] add parser for c-style enum
Browse files Browse the repository at this point in the history
  • Loading branch information
sbird committed Apr 1, 2024
1 parent d5acfb4 commit e8291f3
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 1 deletion.
186 changes: 186 additions & 0 deletions tools/preproc/asm_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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()
{
Expand Down Expand Up @@ -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;
}
6 changes: 6 additions & 0 deletions tools/preproc/asm_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ enum class Directive
Include,
String,
Braille,
Enum,
Unknown
};

Expand All @@ -49,6 +50,7 @@ class AsmFile
bool IsAtEnd();
void OutputLine();
void OutputLocation();
bool ParseEnum();

private:
char* m_buffer;
Expand All @@ -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
2 changes: 1 addition & 1 deletion tools/preproc/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@

char *ReadFileToBuffer(const char *filename, bool isStdin, long *size);

#endif // IO_H_
#endif // IO_H_
7 changes: 7 additions & 0 deletions tools/preproc/preproc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ void PreprocAsmFile(std::string filename, bool isStdin)
std::stack<AsmFile> stack;

stack.push(AsmFile(filename, isStdin));
std::printf("# 1 \"%s\"\n", filename.c_str());

for (;;)
{
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit e8291f3

Please sign in to comment.