Refactor to allow inline initialization of arrays.

This commit is contained in:
Curle 2023-04-24 22:26:54 +01:00
parent e42a2cfd8d
commit 0f77480d5b
5 changed files with 154 additions and 41 deletions

View File

@ -239,15 +239,16 @@ struct SymbolTableEntry {
struct SymbolTableEntry* CompositeType; // A pointer to the start of a Symbol Table list that represents a certain Composite type
int Structure; // An entry in StructureType - metadata on how to process the data
int Storage; // The scope of this symbol - decides when it is discarded.
union {
int EndLabel; // For a function - The number of the label to jump to, in order to exit this function (if applicable)
int Length; // For an array - The length of the symbol in units of 1 element -- the size of an array, for example.
int Length; // Size of an array, or the number of parameters in a function
int Size; // Total size in bytes.
int* InitialValues;
int IntValue; // For an enum - The value of an Enum entry
};
union {
int EndLabel; // For a function - The number of the label to jump to, in order to exit this function (if applicable)
int SinkOffset; // For a variable - How many times must we sink the rbp to get to this symbol in the stack?
int Elements; // For a function - How many parameters?
};
struct SymbolTableEntry* NextSymbol; // The next symbol in a list

View File

@ -61,6 +61,33 @@ struct ASTNode* ParseCompound() {
}
}
/*
* Read a literal of the given type.
* @param Type integer or char*
* @return the integer literal, or label value of the string.
*/
int ParseLiteral(int Type) {
if ((Type == PointerTo(RET_CHAR)) && (CurrentFile->CurrentSymbol.type == LI_STR))
return Assembler->vtable->AsNewString(CurrentIdentifier);
if (CurrentFile->CurrentSymbol.type == LI_INT) {
switch (Type) {
case RET_CHAR:
if (CurrentFile->CurrentSymbol.value < 0 || CurrentFile->CurrentSymbol.value > 255)
ErrorReport("Integer literal value too big for char\n");
case RET_INT:
case RET_LONG:
break;
default: ErrorReport("Type Mismatch. Integer Literal vs Variable.\n");
}
} else {
ErrorReport("Expecting an integer literal or char array.\n");
}
return CurrentFile->CurrentSymbol.value;
}
/*
* Resolve a typename to a type struct.
* Short circuit on the case where a definition is present, as definitions are typeless.
@ -158,31 +185,94 @@ static int ParsePointerType(int Type) {
*/
static struct SymbolTableEntry* ParseArrayDeclaration(char* name, int Type, struct SymbolTableEntry* CompositeType, int Storage) {
struct SymbolTableEntry* Symbol = NULL;
int Elems = -1, MaxElems, *InitialList, i, j;
Tokenise();
Safe();
if (CurrentFile->CurrentSymbol.type == LI_INT) {
switch (Storage) {
case SC_GLOBAL:
Symbol = AddSymbol(name, PointerTo(Type), ST_ARR, Storage, CurrentFile->CurrentSymbol.value, 0, CompositeType);
break;
case SC_LOCAL:
case SC_PARAM:
case SC_MEMBER:
default:
ErrorReport("Local array definitions not permitted.\n");
}
if (CurrentFile->CurrentSymbol.value <= 0)
ErrorReport("Array size in definition cannot be negative.\n");
Elems = CurrentFile->CurrentSymbol.value;
Tokenise();
}
Tokenise();
VerifyToken(LI_RBRAC, "]");
Safe();
if (CurrentFile->CurrentSymbol.type == LI_EQUAL) {
if (Storage != SC_GLOBAL)
ErrorReport("Non-global array cannot be initialized.\n");
Tokenise();
Safe();
VerifyToken(LI_LBRAC, "{");
if (Elems != -1)
MaxElems = Elems;
else
MaxElems = 10;
InitialList = (int*)malloc(MaxElems * sizeof(int));
while (1) {
if (Elems != -1 && i == MaxElems)
ErrorReport("Too many items in initializer list\n");
InitialList[i++] = ParseLiteral(Type);
Tokenise();
Safe();
if (Elems == -1 && i == MaxElems) {
MaxElems += 10;
InitialList = (int*)realloc(InitialList, MaxElems * sizeof(int));
}
if (CurrentFile->CurrentSymbol.type == LI_RBRAC) {
Tokenise();
break;
}
VerifyToken(LI_COM, ",");
Safe();
}
for (j = i; j < Symbol->Length; j++)
InitialList[j] = 0;
if (i > Elems)
Elems = i;
Symbol->InitialValues = InitialList;
}
Symbol->Length = Elems;
Symbol->Size = Symbol->Length * TypeSize(Type, CompositeType);
if (Storage == SC_GLOBAL)
Assembler->vtable->AsGlobalSymbol(Symbol);
return Symbol;
}
// A short redirect to add a Scalar definition to the variable tables.
static struct SymbolTableEntry* ParseScalarDeclaration(char* name, int Type, struct SymbolTableEntry* CompositeType, int Storage) {
return AddSymbol(name, Type, ST_VAR, Storage, 1, 0, CompositeType);
struct SymbolTableEntry* sym = AddSymbol(name, Type, ST_VAR, Storage, 1, 0, CompositeType);
// Being assigned.
if (CurrentFile->CurrentSymbol.type == LI_EQUAL) {
if (Storage != SC_GLOBAL && Storage != SC_LOCAL)
ErrorReport("Non-static, non-local variable cannot be initialized.\n");
Tokenise();
Safe();
if (Storage == SC_GLOBAL) {
sym->InitialValues = (int*) malloc(sizeof(int));
sym->InitialValues[0] = ParseLiteral(Type);
Tokenise();
}
}
if (Storage == SC_GLOBAL)
Assembler->vtable->AsGlobalSymbol(sym);
return sym;
}
/*
@ -323,7 +413,7 @@ static struct SymbolTableEntry* ParseFunctionDeclaration(char* name, int Type, s
TypeNames(Type), BreakLabel);
if (NewFunction) {
NewFunction->Elements = ParamCount;
NewFunction->Length = ParamCount;
NewFunction->Start = Params;
NewFunction->Type = RET_LONG;
OldFunction = NewFunction;
@ -584,6 +674,7 @@ struct SymbolTableEntry* BeginCompositeDeclaration(int Type) {
}
Composite->Length = Type == DAT_STRUCT ? Offset : Largest;
Composite->Size = Offset;
return Composite;
}
@ -904,8 +995,8 @@ struct ASTNode* SwitchStatement() {
VerifyToken(LI_LBRAC, "{");
// Verify the switch expression (must be integer-compatible)
if (!TypeIsInt(!left->ExprType))
Die("Switch expression is not of integer type");
if (!TypeIsInt(left->ExprType))
ErrorReport("Switch expression is not of integer type, instead %s.\n", TypeNames(left->ExprType));
Safe();

View File

@ -251,6 +251,9 @@ struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Stor
Node->SinkOffset = SinkOffset;
Node->CompositeType = CompositeType;
if (TypeIsPtr(Type) || TypeIsInt(Type))
Node->Size = Length * TypeSize(Type, CompositeType);
printf("Adding a %s symbol of name %s, type %s to the tables.\n", ScopeNames[Node->Storage], Node->Name,
TypeNames(Node->Type));
switch (Storage) {

View File

@ -17,7 +17,8 @@
*/
int TypeIsInt(int Type) {
return ((Type & 0xf) == 0);
printf("\tComparing type %d.\n", Type);
return ( ((Type & 0xf) == 0) && (Type >= RET_CHAR && Type <= RET_LONG));
}
/*

View File

@ -712,22 +712,35 @@ static int AsStrDeref(int Register1, int Register2, int Type) {
return Register1;
}
static void AsDataSegment() {
fprintf(stdout, ".data:\n");
}
// Assemble a global symbol (variable, struct, enum, function, string)
static void AsGlobalSymbol(struct SymbolTableEntry* Entry) {
int size, type, init, i;
if (Entry == NULL) return;
if (Entry->Structure == ST_FUNC) return;
if (Entry->Structure = ST_ARR) {
type = ValueAt(Entry->Type);
size = TypeSize(type, Entry->CompositeType);
} else {
size = Entry->Size;
type = Entry->Type;
}
int Size = TypeSize(Entry->Type, Entry->CompositeType);
fprintf(OutputFile, "\t.data\n"
"\t.globl\t%s\n",
Entry->Name);
AsDataSegment();
fprintf(OutputFile,"\t.globl\t%s\n", Entry->Name);
fprintf(OutputFile, "%s:\n", Entry->Name);
switch (Size) {
for (i = 0; i < Entry->Length; i++) {
init = 0;
if (Entry->InitialValues)
init = Entry->InitialValues[i];
switch (size) {
case 1:
fprintf(OutputFile, "\t.byte\t0\r\n");
break;
@ -735,12 +748,16 @@ static void AsGlobalSymbol(struct SymbolTableEntry* Entry) {
fprintf(OutputFile, "\t.long\t0\r\n");
break;
case 8:
fprintf(OutputFile, "\t.quad\t0\r\n");
if (Entry->InitialValues && type == PointerTo(RET_CHAR))
fprintf(OutputFile, "\t.quad\tL%d\r\n", init);
else
fprintf(OutputFile, "\t.quad\t%d\r\n", init);
break;
default:
for (int i = 0; i < Size; i++)
for (i = 0; i < size; i++)
fprintf(OutputFile, "\t.byte\t0\n");
}
}
}