From 3717b310beff5de9d6d3beaeb8dfb2d3e94297bb Mon Sep 17 00:00:00 2001 From: Curle Date: Thu, 3 Mar 2022 02:44:07 +0000 Subject: [PATCH] Implement unions and largest-element allocation --- include/Data.h | 3 ++- include/Defs.h | 8 ++++++-- src/Assembler.c | 2 +- src/Lexer.c | 5 +++++ src/Main.c | 1 + src/Parser.c | 2 +- src/Pointers.c | 16 ++++++++++------ src/Statements.c | 36 +++++++++++++++++++++--------------- src/Symbols.c | 20 +++++++++++++++++--- src/Types.c | 2 +- tests/union.er | 21 +++++++++++++++++++++ 11 files changed, 86 insertions(+), 30 deletions(-) create mode 100644 tests/union.er diff --git a/include/Data.h b/include/Data.h index c368a7c..2c83a5f 100644 --- a/include/Data.h +++ b/include/Data.h @@ -20,7 +20,8 @@ extern_ struct SymbolTableEntry* Globals, * GlobalsEnd; extern_ struct SymbolTableEntry* Locals, * LocalsEnd; extern_ struct SymbolTableEntry* Params, * ParamsEnd; extern_ struct SymbolTableEntry* Structs, * StructsEnd; -extern_ struct SymbolTableEntry* StructMembers, * StructMembersEnd; + +extern_ struct SymbolTableEntry* CompositeMembers, * CompositeMembersEnd; extern_ struct SymbolTableEntry* Unions, * UnionsEnd; extern_ struct SymbolTableEntry* Enums, * EnumsEnd; diff --git a/include/Defs.h b/include/Defs.h index 6dc7bd5..65baf0e 100644 --- a/include/Defs.h +++ b/include/Defs.h @@ -96,7 +96,8 @@ enum TokenTypes { KW_WHILE, KW_FOR, KW_RETURN, - KW_STRUCT + KW_STRUCT, + KW_UNION }; /* @@ -219,6 +220,7 @@ struct SymbolTableEntry { enum StorageScope { SC_GLOBAL = 1, // Global Scope SC_STRUCT, // Struct Definitions + SC_UNION, // Union Definitions SC_ENUM, // Enum Definitions SC_MEMBER, // The members of Structs or Enums //SC_CLASS, // Class-local definitions @@ -348,7 +350,7 @@ struct ASTNode* ParseFunction(int Type); struct ASTNode* ParseCompound(); -struct SymbolTableEntry* BeginStructDeclaration(); +struct SymbolTableEntry* BeginCompositeDeclaration(int Type); struct ASTNode* GetExpressionList(); @@ -387,6 +389,8 @@ struct SymbolTableEntry* FindGlobal(char* Symbol); struct SymbolTableEntry* FindStruct(char* Symbol); +struct SymbolTableEntry* FindUnion(char* Symbol); + struct SymbolTableEntry* FindMember(char* Symbol); void AppendSymbol(struct SymbolTableEntry** Head, struct SymbolTableEntry** Tail, struct SymbolTableEntry* Node); diff --git a/src/Assembler.c b/src/Assembler.c index 2457e38..fdea8ea 100644 --- a/src/Assembler.c +++ b/src/Assembler.c @@ -799,7 +799,7 @@ int AsDeref(int Reg, int Type) { printf("\tDereferencing %s\n", Registers[Reg]); switch (DestSize) { case 1: - fprintf(OutputFile, "\tmovzbq\t(%s), %s\n", Registers[Reg], ByteRegisters[Reg]); + fprintf(OutputFile, "\tmovzbq\t(%s), %s\n", Registers[Reg], Registers[Reg]); break; case 2: fprintf(OutputFile, "\tmovslq\t(%s), %s\n", Registers[Reg], DoubleRegisters[Reg]); diff --git a/src/Lexer.c b/src/Lexer.c index 73b5aeb..8c98620 100644 --- a/src/Lexer.c +++ b/src/Lexer.c @@ -338,6 +338,11 @@ static int ReadKeyword(char* Str) { return KW_STRUCT; break; + case 'u': + if(!strcmp(Str, "union")) + return KW_UNION; + break; + case 'v': if (!strcmp(Str, "void")) return TY_VOID; diff --git a/src/Main.c b/src/Main.c index d810716..5476df9 100644 --- a/src/Main.c +++ b/src/Main.c @@ -87,6 +87,7 @@ char* ScopeNames[] = { "INVALID", "GLOBAL", "STRUCT", + "UNION", "ENUM", "MEMBER", "PARAMETER", diff --git a/src/Parser.c b/src/Parser.c index b055c27..0a35880 100644 --- a/src/Parser.c +++ b/src/Parser.c @@ -534,7 +534,7 @@ void ParseGlobals() { // Structs are parsed fully in ParseOptionalPointer // TODO: FIX THAT!! - if (Type == DAT_STRUCT && CurrentToken.type == LI_SEMIC) { + if ((Type == DAT_STRUCT || Type == DAT_UNION) && CurrentToken.type == LI_SEMIC) { Tokenise(); continue; } diff --git a/src/Pointers.c b/src/Pointers.c index 72539b9..06a0ca9 100644 --- a/src/Pointers.c +++ b/src/Pointers.c @@ -94,7 +94,11 @@ int ParseOptionalPointer(struct SymbolTableEntry** Composite) { break; case KW_STRUCT: Type = DAT_STRUCT; - *Composite = BeginStructDeclaration(); + *Composite = BeginCompositeDeclaration(Type); + break; + case KW_UNION: + Type = DAT_UNION; + *Composite = BeginCompositeDeclaration(Type); break; default: DieDecimal("Illegal type for pointerisation", CurrentToken.type); @@ -175,13 +179,13 @@ struct ASTNode* AccessMember(bool Deref) { if ((CompositeVar = FindSymbol(CurrentIdentifier)) == NULL) DieMessage("Undeclared variable", CurrentIdentifier); - if (Deref && CompositeVar->Type != PointerTo(DAT_STRUCT)) + if (Deref && (CompositeVar->Type != PointerTo(DAT_STRUCT) && CompositeVar->Type != PointerTo(DAT_UNION))) DieMessage("Undeclared struct", CurrentIdentifier); - if (!Deref && CompositeVar->Type != DAT_STRUCT) + if (!Deref && (CompositeVar->Type != DAT_STRUCT && CompositeVar->Type != DAT_UNION)) DieMessage("Undeclared struct", CurrentIdentifier); if (Deref) - LeftNode = ConstructASTLeaf(REF_IDENT, PointerTo(DAT_STRUCT), CompositeVar, 0); + LeftNode = ConstructASTLeaf(REF_IDENT, PointerTo(CompositeVar->Type), CompositeVar, 0); else LeftNode = ConstructASTLeaf(OP_ADDRESS, CompositeVar->Type, CompositeVar, 0); @@ -193,14 +197,14 @@ struct ASTNode* AccessMember(bool Deref) { VerifyToken(TY_IDENTIFIER, "identifier"); for (Member = TypePtr->Start; Member != NULL; Member = Member->NextSymbol) { - printf("\tComparing struct entry %s with the wanted %s. Index %d.\r\n", Member->Name, CurrentIdentifier, + printf("\tComparing composite entry %s with the wanted %s. Index %d.\r\n", Member->Name, CurrentIdentifier, Member->SinkOffset); if (!strcmp(Member->Name, CurrentIdentifier)) break; } if (Member == NULL) - DieMessage("Invalid struct member", CurrentIdentifier); + DieMessage("Invalid composite member", CurrentIdentifier); RightNode = ConstructASTLeaf(TERM_INTLITERAL, RET_INT, NULL, Member->SinkOffset); diff --git a/src/Statements.c b/src/Statements.c index 71e6bcf..71ac8c0 100644 --- a/src/Statements.c +++ b/src/Statements.c @@ -62,25 +62,26 @@ static int ReadDeclarationList(struct SymbolTableEntry* FunctionSymbol, int Stor } /* - * Handles the declaration of a new struct. + * Handles the declaration of a new composite type. + * For example, a struct is a composite of multiple different named positions: * struct thisStct { int x, int y, int z }; * * Verifies that the current identifier is not used, * verifies that this is not a redefinition (excluding * the case where there is a declaration but no definition) - * and then saves it into the Structs symbol table. + * and then saves it into the appropriate symbol table. * - * @return the Symbol Table entry of this new struct. + * @return the Symbol Table entry of this new composite. */ -struct SymbolTableEntry* BeginStructDeclaration() { +struct SymbolTableEntry* BeginCompositeDeclaration(int Type) { struct SymbolTableEntry* Composite = NULL, * Member; - int Offset; + int Offset = 0, Largest = 0; Tokenise(); if (CurrentToken.type == TY_IDENTIFIER) { - Composite = FindStruct(CurrentIdentifier); + Composite = Type == DAT_STRUCT ? FindStruct(CurrentIdentifier) : FindUnion(CurrentIdentifier); Tokenise(); } @@ -91,29 +92,34 @@ struct SymbolTableEntry* BeginStructDeclaration() { } if (Composite) - DieMessage("Redefinition of struct", CurrentIdentifier); + DieMessage("Redefinition of composite", CurrentIdentifier); - Composite = AddSymbol(CurrentIdentifier, DAT_STRUCT, 0, SC_STRUCT, 0, 0, NULL); + Composite = AddSymbol(CurrentIdentifier, Type, 0, Type == DAT_STRUCT ? SC_STRUCT : SC_UNION, 0, 0, NULL); Tokenise(); - printf("Reading a struct declaration..\n"); + printf("Reading a composite declaration.. Type is %s\n", Type == DAT_STRUCT ? "struct" : "union"); ReadDeclarationList(NULL, SC_MEMBER, LI_RBRAC); VerifyToken(LI_RBRAC, "}"); - Composite->Start = StructMembers; - StructMembers = StructMembersEnd = NULL; + Composite->Start = CompositeMembers; + CompositeMembers = CompositeMembersEnd = NULL; Member = Composite->Start; - printf("\tSetting first entry in struct to %s\r\n", Member->Name); + printf("\tSetting first entry in composite to %s\r\n", Member->Name); Member->SinkOffset = 0; Offset = TypeSize(Member->Type, Member->CompositeType); for (Member = Member->NextSymbol; Member != NULL; Member = Member->NextSymbol) { - Member->SinkOffset = AsAlignMemory(Member->Type, Offset, 1); + if (Type == DAT_STRUCT) + Member->SinkOffset = AsAlignMemory(Member->Type, Offset, 1); + else + Member->SinkOffset = 0; - Offset += TypeSize(Member->Type, Member->CompositeType); + int CurrentSize = TypeSize(Member->Type, Member->CompositeType); + Offset += CurrentSize; + Largest = CurrentSize > Largest ? CurrentSize : Largest; } - Composite->Length = Offset; + Composite->Length = Type == DAT_STRUCT ? Offset : Largest; return Composite; } diff --git a/src/Symbols.c b/src/Symbols.c index 0023348..a7cacfd 100644 --- a/src/Symbols.c +++ b/src/Symbols.c @@ -120,6 +120,16 @@ struct SymbolTableEntry* FindGlobal(char* Symbol) { struct SymbolTableEntry* FindStruct(char* Symbol) { return SearchList(Symbol, Structs); } +/* + * An override for FindSymbol. + * Searches only the defined Unions. + * @param Symbol: The string name of the symbol to search for. + * @return a pointer to the node if found, else NULL + * + */ +struct SymbolTableEntry* FindUnion(char* Symbol) { + return SearchList(Symbol, Unions); +} /* * An override for FindSymbol. @@ -129,7 +139,7 @@ struct SymbolTableEntry* FindStruct(char* Symbol) { * */ struct SymbolTableEntry* FindMember(char* Symbol) { - return SearchList(Symbol, StructMembers); + return SearchList(Symbol, CompositeMembers); } /* @@ -177,7 +187,7 @@ void ClearTables() { Globals = GlobalsEnd = NULL; Locals = LocalsEnd = NULL; Params = ParamsEnd = NULL; - StructMembers = StructMembersEnd = NULL; + CompositeMembers = CompositeMembersEnd = NULL; Structs = StructsEnd = NULL; } @@ -218,8 +228,12 @@ struct SymbolTableEntry* AddSymbol(char* Name, int Type, int Structure, int Stor case SC_STRUCT: AppendSymbol(&Structs, &StructsEnd, Node); break; + case SC_UNION: + AppendSymbol(&Unions, &UnionsEnd, Node); + break; case SC_MEMBER: - AppendSymbol(&StructMembers, &StructMembersEnd, Node); + AppendSymbol(&CompositeMembers, &CompositeMembersEnd, Node); + break; case SC_LOCAL: AppendSymbol(&Locals, &LocalsEnd, Node); break; diff --git a/src/Types.c b/src/Types.c index f22acf4..e5dcbe2 100644 --- a/src/Types.c +++ b/src/Types.c @@ -64,7 +64,7 @@ int PrimitiveSize(int Type) { */ int TypeSize(int Type, struct SymbolTableEntry* Composite) { - if (Type == DAT_STRUCT) return Composite->Length; + if (Type == DAT_STRUCT || Type == DAT_UNION) return Composite->Length; return PrimitiveSize(Type); } diff --git a/tests/union.er b/tests/union.er new file mode 100644 index 0000000..0d80279 --- /dev/null +++ b/tests/union.er @@ -0,0 +1,21 @@ +int :: printf(char* format); + +union fruit { + char cherry, + int apple, + int orange, + long banana +}; + +union fruit basket; + +int :: main() { + basket.apple = 55; + printf("1 %d b\n", basket.cherry); + printf("2 %d a\n", basket.orange); + basket.orange = 100; + printf("3 %d c\n", basket.banana); + printf("4 %d d\n", basket.apple); + + return (0); +} \ No newline at end of file