Skip to content

Commit 550e668

Browse files
SBird1337sbirdmrgriffin
authored
Support C-Style enum in preproc (pret#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 <[email protected]> Co-authored-by: Martin Griffin <[email protected]>
1 parent a0a02f9 commit 550e668

File tree

9 files changed

+339
-103
lines changed

9 files changed

+339
-103
lines changed

Makefile

+7-7
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ ifeq ($(NODEP),1)
311311
$(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.c
312312
ifeq (,$(KEEP_TEMPS))
313313
@echo "$(CC1) <flags> -o $@ $<"
314-
@$(CPP) $(CPPFLAGS) $< | $(PREPROC) $< charmap.txt -i | $(CC1) $(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $(AS) $(ASFLAGS) -o $@ -
314+
@$(CPP) $(CPPFLAGS) $< | $(PREPROC) -i $< charmap.txt | $(CC1) $(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $(AS) $(ASFLAGS) -o $@ -
315315
else
316316
@$(CPP) $(CPPFLAGS) $< -o $(C_BUILDDIR)/$*.i
317317
@$(PREPROC) $(C_BUILDDIR)/$*.i charmap.txt | $(CC1) $(CFLAGS) -o $(C_BUILDDIR)/$*.s
@@ -323,7 +323,7 @@ define C_DEP
323323
$1: $2 $$(shell $(SCANINC) -I include -I tools/agbcc/include -I gflib $2)
324324
ifeq (,$$(KEEP_TEMPS))
325325
@echo "$$(CC1) <flags> -o $$@ $$<"
326-
@$$(CPP) $$(CPPFLAGS) $$< | $$(PREPROC) $$< charmap.txt -i | $$(CC1) $$(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $$(AS) $$(ASFLAGS) -o $$@ -
326+
@$$(CPP) $$(CPPFLAGS) $$< | $$(PREPROC) -i $$< charmap.txt | $$(CC1) $$(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $$(AS) $$(ASFLAGS) -o $$@ -
327327
else
328328
@$$(CPP) $$(CPPFLAGS) $$< -o $$(C_BUILDDIR)/$3.i
329329
@$$(PREPROC) $$(C_BUILDDIR)/$3.i charmap.txt | $$(CC1) $$(CFLAGS) -o $$(C_BUILDDIR)/$3.s
@@ -338,7 +338,7 @@ ifeq ($(NODEP),1)
338338
$(GFLIB_BUILDDIR)/%.o: $(GFLIB_SUBDIR)/%.c $$(c_dep)
339339
ifeq (,$(KEEP_TEMPS))
340340
@echo "$(CC1) <flags> -o $@ $<"
341-
@$(CPP) $(CPPFLAGS) $< | $(PREPROC) $< charmap.txt -i | $(CC1) $(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $(AS) $(ASFLAGS) -o $@ -
341+
@$(CPP) $(CPPFLAGS) $< | $(PREPROC) -i $< charmap.txt | $(CC1) $(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $(AS) $(ASFLAGS) -o $@ -
342342
else
343343
@$(CPP) $(CPPFLAGS) $< -o $(GFLIB_BUILDDIR)/$*.i
344344
@$(PREPROC) $(GFLIB_BUILDDIR)/$*.i charmap.txt | $(CC1) $(CFLAGS) -o $(GFLIB_BUILDDIR)/$*.s
@@ -350,7 +350,7 @@ define GFLIB_DEP
350350
$1: $2 $$(shell $(SCANINC) -I include -I tools/agbcc/include -I gflib $2)
351351
ifeq (,$$(KEEP_TEMPS))
352352
@echo "$$(CC1) <flags> -o $$@ $$<"
353-
@$$(CPP) $$(CPPFLAGS) $$< | $$(PREPROC) $$< charmap.txt -i | $$(CC1) $$(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $$(AS) $$(ASFLAGS) -o $$@ -
353+
@$$(CPP) $$(CPPFLAGS) $$< | $$(PREPROC) -i $$< charmap.txt | $$(CC1) $$(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $$(AS) $$(ASFLAGS) -o $$@ -
354354
else
355355
@$$(CPP) $$(CPPFLAGS) $$< -o $$(GFLIB_BUILDDIR)/$3.i
356356
@$$(PREPROC) $$(GFLIB_BUILDDIR)/$3.i charmap.txt | $$(CC1) $$(CFLAGS) -o $$(GFLIB_BUILDDIR)/$3.s
@@ -363,11 +363,11 @@ endif
363363

364364
ifeq ($(NODEP),1)
365365
$(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s
366-
$(PREPROC) $< charmap.txt | $(CPP) -I include - | $(AS) $(ASFLAGS) -o $@
366+
$(PREPROC) $< charmap.txt | $(CPP) -I include - | $(PREPROC) -i $$< charmap.txt | $(AS) $(ASFLAGS) -o $@
367367
else
368368
define SRC_ASM_DATA_DEP
369369
$1: $2 $$(shell $(SCANINC) -I include -I "" $2)
370-
$$(PREPROC) $$< charmap.txt | $$(CPP) -I include - | $$(AS) $$(ASFLAGS) -o $$@
370+
$$(PREPROC) $$< charmap.txt | $$(CPP) -I include - | $$(PREPROC) -ie $$< charmap.txt | $$(AS) $$(ASFLAGS) -o $$@
371371
endef
372372
$(foreach src, $(C_ASM_SRCS), $(eval $(call SRC_ASM_DATA_DEP,$(patsubst $(C_SUBDIR)/%.s,$(C_BUILDDIR)/%.o, $(src)),$(src))))
373373
endif
@@ -385,7 +385,7 @@ endif
385385

386386
ifeq ($(NODEP),1)
387387
$(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s
388-
$(PREPROC) $< charmap.txt | $(CPP) -I include - | $(AS) $(ASFLAGS) -o $@
388+
$(PREPROC) $< charmap.txt | $(CPP) -I include - | $(PREPROC) -ie $$< charmap.txt | $(AS) $(ASFLAGS) -o $@
389389
else
390390
$(foreach src, $(REGULAR_DATA_ASM_SRCS), $(eval $(call SRC_ASM_DATA_DEP,$(patsubst $(DATA_ASM_SUBDIR)/%.s,$(DATA_ASM_BUILDDIR)/%.o, $(src)),$(src))))
391391
endif

tools/preproc/Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ CXX ?= g++
33
CXXFLAGS := -std=c++11 -O2 -Wall -Wno-switch -Werror
44

55
SRCS := asm_file.cpp c_file.cpp charmap.cpp preproc.cpp string_parser.cpp \
6-
utf8.cpp
6+
utf8.cpp io.cpp
77

88
HEADERS := asm_file.h c_file.h char_util.h charmap.h preproc.h string_parser.h \
9-
utf8.h
9+
utf8.h io.h
1010

1111
ifeq ($(OS),Windows_NT)
1212
EXE := .exe

tools/preproc/asm_file.cpp

+198-25
Original file line numberDiff line numberDiff line change
@@ -27,33 +27,12 @@
2727
#include "utf8.h"
2828
#include "string_parser.h"
2929
#include "../../gflib/characters.h"
30+
#include "io.h"
3031

31-
AsmFile::AsmFile(std::string filename) : m_filename(filename)
32+
AsmFile::AsmFile(std::string filename, bool isStdin, bool doEnum) : m_filename(filename)
3233
{
33-
FILE *fp = std::fopen(filename.c_str(), "rb");
34-
35-
if (fp == NULL)
36-
FATAL_ERROR("Failed to open \"%s\" for reading.\n", filename.c_str());
37-
38-
std::fseek(fp, 0, SEEK_END);
39-
40-
m_size = std::ftell(fp);
41-
42-
if (m_size < 0)
43-
FATAL_ERROR("File size of \"%s\" is less than zero.\n", filename.c_str());
44-
else if (m_size == 0)
45-
return; // Empty file
46-
47-
m_buffer = new char[m_size + 1];
48-
49-
std::rewind(fp);
50-
51-
if (std::fread(m_buffer, m_size, 1, fp) != 1)
52-
FATAL_ERROR("Failed to read \"%s\".\n", filename.c_str());
53-
54-
m_buffer[m_size] = 0;
55-
56-
std::fclose(fp);
34+
m_buffer = ReadFileToBuffer(filename.c_str(), isStdin, &m_size);
35+
m_doEnum = doEnum;
5736

5837
m_pos = 0;
5938
m_lineNum = 1;
@@ -65,6 +44,7 @@ AsmFile::AsmFile(std::string filename) : m_filename(filename)
6544
AsmFile::AsmFile(AsmFile&& other) : m_filename(std::move(other.m_filename))
6645
{
6746
m_buffer = other.m_buffer;
47+
m_doEnum = other.m_doEnum;
6848
m_pos = other.m_pos;
6949
m_size = other.m_size;
7050
m_lineNum = other.m_lineNum;
@@ -174,6 +154,8 @@ Directive AsmFile::GetDirective()
174154
return Directive::String;
175155
else if (CheckForDirective(".braille"))
176156
return Directive::Braille;
157+
else if (CheckForDirective("enum"))
158+
return Directive::Enum;
177159
else
178160
return Directive::Unknown;
179161
}
@@ -527,6 +509,70 @@ void AsmFile::OutputLine()
527509
}
528510
}
529511

512+
// parses an assumed C `enum`. Returns false if `enum { ...` is not matched
513+
bool AsmFile::ParseEnum()
514+
{
515+
if (!m_doEnum)
516+
return false;
517+
518+
long fallbackPosition = m_pos;
519+
std::string headerFilename = "";
520+
long currentHeaderLine = SkipWhitespaceAndEol();
521+
std::string enumName = ReadIdentifier();
522+
currentHeaderLine += SkipWhitespaceAndEol();
523+
long enumCounter = 0;
524+
long symbolCount = 0;
525+
526+
if (m_buffer[m_pos] != '{') // assume assembly macro, otherwise assume enum and report errors accordingly
527+
{
528+
m_pos = fallbackPosition - 4;
529+
return false;
530+
}
531+
532+
currentHeaderLine += FindLastLineNumber(headerFilename);
533+
m_pos++;
534+
for (;;)
535+
{
536+
currentHeaderLine += SkipWhitespaceAndEol();
537+
std::string currentIdentName = ReadIdentifier();
538+
if (!currentIdentName.empty())
539+
{
540+
std::printf("# %ld \"%s\"\n", currentHeaderLine, headerFilename.c_str());
541+
currentHeaderLine += SkipWhitespaceAndEol();
542+
if (m_buffer[m_pos] == '=')
543+
{
544+
m_pos++;
545+
currentHeaderLine += SkipWhitespaceAndEol();
546+
enumCounter = ReadInteger(headerFilename, currentHeaderLine);
547+
currentHeaderLine += SkipWhitespaceAndEol();
548+
}
549+
std::printf(".equiv %s, %ld\n", currentIdentName.c_str(), enumCounter);
550+
enumCounter++;
551+
symbolCount++;
552+
}
553+
else if (symbolCount == 0)
554+
{
555+
RaiseError("%s:%ld: empty enum is invalid", headerFilename.c_str(), currentHeaderLine);
556+
}
557+
558+
if (m_buffer[m_pos] != ',')
559+
{
560+
currentHeaderLine += SkipWhitespaceAndEol();
561+
if (m_buffer[m_pos++] == '}' && m_buffer[m_pos++] == ';')
562+
{
563+
ExpectEmptyRestOfLine();
564+
break;
565+
}
566+
else
567+
{
568+
RaiseError("unterminated enum from included file %s:%ld", headerFilename.c_str(), currentHeaderLine);
569+
}
570+
}
571+
m_pos++;
572+
}
573+
return true;
574+
}
575+
530576
// Asserts that the rest of the line is empty and moves to the next one.
531577
void AsmFile::ExpectEmptyRestOfLine()
532578
{
@@ -599,3 +645,130 @@ void AsmFile::RaiseWarning(const char* format, ...)
599645
{
600646
DO_REPORT("warning");
601647
}
648+
649+
// Skips Whitespace including newlines and returns the amount of newlines skipped
650+
int AsmFile::SkipWhitespaceAndEol()
651+
{
652+
int newlines = 0;
653+
while (m_buffer[m_pos] == '\t' || m_buffer[m_pos] == ' ' || m_buffer[m_pos] == '\n')
654+
{
655+
if (m_buffer[m_pos] == '\n')
656+
newlines++;
657+
m_pos++;
658+
}
659+
return newlines;
660+
}
661+
662+
// returns the last line indicator and its corresponding file name without modifying the token index
663+
int AsmFile::FindLastLineNumber(std::string& filename)
664+
{
665+
long pos = m_pos;
666+
long linebreaks = 0;
667+
while (m_buffer[pos] != '#' && pos >= 0)
668+
{
669+
if (m_buffer[pos] == '\n')
670+
linebreaks++;
671+
pos--;
672+
}
673+
674+
if (pos < 0)
675+
RaiseError("line indicator for header file not found before `enum`");
676+
677+
pos++;
678+
while (m_buffer[pos] == ' ' || m_buffer[pos] == '\t')
679+
pos++;
680+
681+
if (!IsAsciiDigit(m_buffer[pos]))
682+
RaiseError("malformatted line indicator found before `enum`, expected line number");
683+
684+
unsigned n = 0;
685+
int digit = 0;
686+
while ((digit = ConvertDigit(m_buffer[pos++], 10)) != -1)
687+
n = 10 * n + digit;
688+
689+
while (m_buffer[pos] == ' ' || m_buffer[pos] == '\t')
690+
pos++;
691+
692+
if (m_buffer[pos++] != '"')
693+
RaiseError("malformatted line indicator found before `enum`, expected filename");
694+
695+
while (m_buffer[pos] != '"')
696+
{
697+
unsigned char c = m_buffer[pos++];
698+
699+
if (c == 0)
700+
{
701+
if (pos >= m_size)
702+
RaiseError("unexpected EOF in line indicator");
703+
else
704+
RaiseError("unexpected null character in line indicator");
705+
}
706+
707+
if (!IsAsciiPrintable(c))
708+
RaiseError("unexpected character '\\x%02X' in line indicator", c);
709+
710+
if (c == '\\')
711+
{
712+
c = m_buffer[pos];
713+
RaiseError("unexpected escape '\\%c' in line indicator", c);
714+
}
715+
716+
filename += c;
717+
}
718+
719+
return n + linebreaks - 1;
720+
}
721+
722+
std::string AsmFile::ReadIdentifier()
723+
{
724+
long start = m_pos;
725+
if (!IsIdentifierStartingChar(m_buffer[m_pos]))
726+
return std::string();
727+
728+
m_pos++;
729+
730+
while (IsIdentifierChar(m_buffer[m_pos]))
731+
m_pos++;
732+
733+
return std::string(&m_buffer[start], m_pos - start);
734+
}
735+
736+
long AsmFile::ReadInteger(std::string filename, long line)
737+
{
738+
bool negate = false;
739+
int radix = 10;
740+
if (!IsAsciiDigit(m_buffer[m_pos]))
741+
{
742+
if (m_buffer[m_pos++] == '-')
743+
negate = true;
744+
else
745+
RaiseError("expected number in included file %s:%ld", filename.c_str(), line);
746+
}
747+
748+
if (m_buffer[m_pos] == '0' && m_buffer[m_pos + 1] == 'x')
749+
{
750+
radix = 16;
751+
m_pos += 2;
752+
}
753+
else if (m_buffer[m_pos] == '0' && m_buffer[m_pos + 1] == 'b')
754+
{
755+
radix = 2;
756+
m_pos += 2;
757+
}
758+
else if (m_buffer[m_pos] == '0' && IsAsciiDigit(m_buffer[m_pos+1]))
759+
{
760+
radix = 8;
761+
m_pos++;
762+
}
763+
764+
long n = 0;
765+
int digit;
766+
767+
while ((digit = ConvertDigit(m_buffer[m_pos], radix)) != -1)
768+
{
769+
n = n * radix + digit;
770+
m_pos++;
771+
}
772+
773+
return negate ? -n : n;
774+
}

tools/preproc/asm_file.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,14 @@ enum class Directive
3131
Include,
3232
String,
3333
Braille,
34+
Enum,
3435
Unknown
3536
};
3637

3738
class AsmFile
3839
{
3940
public:
40-
AsmFile(std::string filename);
41+
AsmFile(std::string filename, bool isStdin, bool doEnum);
4142
AsmFile(AsmFile&& other);
4243
AsmFile(const AsmFile&) = delete;
4344
~AsmFile();
@@ -49,9 +50,11 @@ class AsmFile
4950
bool IsAtEnd();
5051
void OutputLine();
5152
void OutputLocation();
53+
bool ParseEnum();
5254

5355
private:
5456
char* m_buffer;
57+
bool m_doEnum;
5558
long m_pos;
5659
long m_size;
5760
long m_lineNum;
@@ -68,6 +71,10 @@ class AsmFile
6871
void RaiseError(const char* format, ...);
6972
void RaiseWarning(const char* format, ...);
7073
void VerifyStringLength(int length);
74+
int SkipWhitespaceAndEol();
75+
int FindLastLineNumber(std::string& filename);
76+
std::string ReadIdentifier();
77+
long ReadInteger(std::string filename, long line);
7178
};
7279

7380
#endif // ASM_FILE_H

0 commit comments

Comments
 (0)