diff --git a/include/Defs.h b/include/Defs.h index f3f5712..e835bfb 100644 --- a/include/Defs.h +++ b/include/Defs.h @@ -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 IntValue; // For an enum - The value of an Enum entry - }; + 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 diff --git a/src/Statements.c b/src/Statements.c index b7a1744..235c270 100644 --- a/src/Statements.c +++ b/src/Statements.c @@ -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(); diff --git a/src/Symbols.c b/src/Symbols.c index c5d3f78..58120d7 100644 --- a/src/Symbols.c +++ b/src/Symbols.c @@ -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) { diff --git a/src/Types.c b/src/Types.c index 5e868f6..634cdfb 100644 --- a/src/Types.c +++ b/src/Types.c @@ -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)); } /* diff --git a/src/assemble/ASMAssembler.c b/src/assemble/ASMAssembler.c index bb66a3f..b2d8f78 100644 --- a/src/assemble/ASMAssembler.c +++ b/src/assemble/ASMAssembler.c @@ -712,34 +712,51 @@ 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) { - case 1: - fprintf(OutputFile, "\t.byte\t0\r\n"); - break; - case 4: - fprintf(OutputFile, "\t.long\t0\r\n"); - break; - case 8: - fprintf(OutputFile, "\t.quad\t0\r\n"); - break; - default: - for (int i = 0; i < Size; i++) - fprintf(OutputFile, "\t.byte\t0\n"); + 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; + case 4: + fprintf(OutputFile, "\t.long\t0\r\n"); + break; + case 8: + 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 (i = 0; i < size; i++) + fprintf(OutputFile, "\t.byte\t0\n"); + } } }