diff --git a/include/Defs.h b/include/Defs.h index 27de1e9..7b68485 100644 --- a/include/Defs.h +++ b/include/Defs.h @@ -295,6 +295,7 @@ int TypeIsInt(int Type); int TypeIsPtr(int Type); char* TypeNames(int Type); +int TypeSize(int Type, struct SymbolTableEntry* Composite); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * @@ -318,14 +319,10 @@ struct ASTNode* ConstructASTBranch(int Operation, int Type, struct ASTNode* Left * * * * * * * * * P A R S I N G * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -//struct ASTNode* ParseNewASTNode(void); -//struct ASTNode* ParseAdditiveASTNode(void); struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence); -//int ParseAST(struct ASTNode* Node); struct ASTNode* ParsePrimary(void); -//void ParseStatements(void); struct ASTNode* ParseStatement(void); struct ASTNode* PrefixStatement(); struct ASTNode* PostfixStatement(); @@ -335,6 +332,7 @@ void ParseGlobals(); struct ASTNode* ParseFunction(int Type); struct ASTNode* ParseCompound(); +struct SymbolTableEntry* BeginStructDeclaration(); struct ASTNode* GetExpressionList(); struct ASTNode* CallFunction(); struct ASTNode* ReturnStatement(); @@ -394,6 +392,7 @@ int RetrieveRegister(); void DeallocateRegister(int Register); int PrimitiveSize(int Type); +int AsAlignMemory(int Type, int Offset, int Direction); int AsLoad(int Value); int AsAdd(int Left, int Right); diff --git a/src/Assembler.c b/src/Assembler.c index 9f526ff..4b16ce3 100644 --- a/src/Assembler.c +++ b/src/Assembler.c @@ -316,6 +316,29 @@ int NewLabel(void) { static int id = 1; return id++; } + +/* + * Align non-char types to a 4 byte alignment. + * Chars need no alignment on x86_64. + * + * @param Type: The DataTypes representation of the data to align + * @param Offset: The offset to align + * @param Direction: The desired direction to move the address for alignment. 1 = up, -1 = down. + * @return the new alignment + * + */ +int AsAlignMemory(int Type, int Offset, int Direction) { + switch(Type) { + case RET_CHAR: return Offset; + case RET_INT: case RET_LONG: break; + default: + DieDecimal("Unable to align type", Type); + } + + int Alignment = 4; + Offset = (Offset + Direction * (Alignment-1)) & ~(Alignment-1); + return (Offset); +} // Assemble an If statement int AsIf(struct ASTNode* Node) { @@ -775,9 +798,12 @@ int AsStrDeref(int Register1, int Register2, int Type) { // Assemble a global symbol (variable, struct, enum, function, string) void AsGlobalSymbol(struct SymbolTableEntry* Entry) { - int TypeSize; - TypeSize = PrimitiveSize(Entry->Type); + if(Entry == NULL) return; + if(Entry->Structure == ST_FUNC) return; + + + int Size = TypeSize(Entry->Type, Entry->CompositeType); fprintf(OutputFile, "\t.data\n" "\t.globl\t%s\n", @@ -785,14 +811,15 @@ void AsGlobalSymbol(struct SymbolTableEntry* Entry) { fprintf(OutputFile, "%s:\n", Entry->Name); - for(int i = 0; i < Entry->Length; i++) { - switch(TypeSize) { - case 1: fprintf(OutputFile, "\t.byte\t0\r\n", Entry->Name); break; - case 4: fprintf(OutputFile, "\t.long\t0\r\n", Entry->Name); break; - case 8: fprintf(OutputFile, "\t.quad\t0\r\n", Entry->Name); break; - default: DieDecimal("Unknown type in AsNewSymbol", TypeSize); break; - } + switch(Size) { + case 1: fprintf(OutputFile, "\t.byte\t0\r\n", Entry->Name); break; + case 4: fprintf(OutputFile, "\t.long\t0\r\n", Entry->Name); break; + case 8: fprintf(OutputFile, "\t.quad\t0\r\n", Entry->Name); break; + default: + for(int i = 0; i < Size; i++) + fprintf(OutputFile, "\t.byte\t0\n"); } + } // Assemble a function call, with all associated parameter bumping and stack movement. diff --git a/src/Lexer.c b/src/Lexer.c index eef5f28..155e3a4 100644 --- a/src/Lexer.c +++ b/src/Lexer.c @@ -367,7 +367,7 @@ void Tokenise() { if(RejectedToken != NULL) { Token = RejectedToken; RejectedToken = NULL; - return 1; + return; } Char = FindChar(); @@ -375,7 +375,7 @@ void Tokenise() { switch(Char) { case EOF: Token->type = LI_EOF; - return 0; + return; case '+': // + can be either "+" or "++". diff --git a/src/Parser.c b/src/Parser.c index 52691f1..3a24512 100644 --- a/src/Parser.c +++ b/src/Parser.c @@ -424,7 +424,7 @@ struct ASTNode* ParseStatement(void) { case TY_LONG: case TY_INT: printf("\t\tNew Variable: %s\n", CurrentIdentifier); - Type = ParseOptionalPointer(); + Type = ParseOptionalPointer(NULL); VerifyToken(TY_IDENTIFIER, "ident"); BeginVariableDeclaration(Type, NULL, SC_LOCAL); VerifyToken(LI_SEMIC, ";"); // TODO: single line assignment? @@ -517,7 +517,7 @@ void ParseGlobals() { while(1) { printf("New definition incoming..\r\n\n"); - Type = ParseOptionalPointer(); + Type = ParseOptionalPointer(NULL); //TODO: converge pathways on this block? if(CurrentToken.type == KW_FUNC) { diff --git a/src/Statements.c b/src/Statements.c index 9cf9161..08af38a 100644 --- a/src/Statements.c +++ b/src/Statements.c @@ -34,12 +34,14 @@ static int ReadDeclarationList(struct SymbolTableEntry* FunctionSymbol, int Stor PrototypePointer = FunctionSymbol->Start; while(CurrentToken.type != LI_RPARE) { - TokenType = ParseOptionalPointer(); + TokenType = ParseOptionalPointer(FunctionSymbol); VerifyToken(TY_IDENTIFIER, "identifier"); + printf("\tReading a new element: %s of type %d\n", CurrentIdentifier, TokenType); + if(PrototypePointer != NULL) { if(TokenType != PrototypePointer->Type) - DieDecimal("Function paramater of invalid type at index", ParamCount + 1); + DieDecimal("Function parameter of invalid type at index", ParamCount + 1); PrototypePointer=PrototypePointer->NextSymbol; } else { BeginVariableDeclaration(TokenType, Composite, Storage); @@ -93,9 +95,9 @@ struct SymbolTableEntry* BeginStructDeclaration() { Composite = AddSymbol(CurrentIdentifier, DAT_STRUCT, 0, SC_STRUCT, 0, 0, NULL); Tokenise(); - - ReadDeclarationList(NULL, SC_MEMBER, LI_RBRAS); - VerifyToken(LI_RBRAS, "]"); + printf("Reading a struct declaration..\n"); + ReadDeclarationList(NULL, SC_MEMBER, LI_RBRAC); + VerifyToken(LI_RBRAC, "}"); Composite->Start = StructMembers; StructMembers = StructMembersEnd = NULL; @@ -195,7 +197,7 @@ struct ASTNode* ParseFunction(int Type) { } VerifyToken(LI_LPARE, "("); - ParamCount = ReadParameters(OldFunction); + ParamCount = ReadDeclarationList(OldFunction, SC_GLOBAL, LI_RPARE); VerifyToken(LI_RPARE, ")"); if(NewFunction) { diff --git a/src/Types.c b/src/Types.c index e165ac5..616fe9b 100644 --- a/src/Types.c +++ b/src/Types.c @@ -7,11 +7,29 @@ #include #include +/* + * Returns whether the input Type represents a raw integer type. + * It works on the principles outlined in Pointers.c; the lowest + * 4 bits indicate indirection. + * + * @param Type: The DataTypes representation to check + * @return a boolean representing whether the input Type is a raw integer + */ int TypeIsInt(int Type) { return ((Type & 0xf) == 0); } +/* + * Returns whether the input Type has at least one level of indirection. + * It works on the principles outlined in Pointers.c; the lowest 4 bits + * indicate indirection. + * + * @param Type: The DataTypes representation to check + * @return a boolean representing whether the input Type is a pointer + * + */ + int TypeIsPtr(int Type) { return ((Type & 0xf) != 0); } @@ -20,12 +38,6 @@ int TypeIsPtr(int Type) { * Turn a token type into its appropriate * primitive type. * - * This is where we do redirections like: - * short -> s16 - * long -> s64 - * int -> s32 - * char -> u8 - * */ int PrimitiveSize(int Type) { @@ -41,8 +53,28 @@ int PrimitiveSize(int Type) { return 0; } +/* + * Dynamically calculate the size of an object. + * This was performed with an array previously, but the addition of + * structs and enums makes that irrelevant. + * + */ + +int TypeSize(int Type, struct SymbolTableEntry* Composite) { + if(Type == DAT_STRUCT) return Composite->Length; + return PrimitiveSize(Type); +} + +/* + * A char buffer we can abuse for printing type names. + * It needs to be 7 because that's 4 (long) + 3 (ptr), the longest + * possible name right now. + */ static char TypeBuffer[7]; +/* + * Get the name of the input Type as a string. + */ char* TypeNames(int Type) { switch(Type) { case RET_CHAR: memcpy(TypeBuffer, "Char", 4); break; @@ -58,21 +90,12 @@ char* TypeNames(int Type) { } /* - * Given two types, determine if they are compatible. - * - * Depending on the value of STRICT, it will try to - * fit the right value into the left value. - * - * This is valid, for ie. a char into an int, as int is larger than char. - * This is called widening the char. - * - * If STRICT is set, it will only allow widening the left to the right. - * This means you cannot `char a; int b; b = 15000; a = b;` - * As this would shrink the int and lose resolution. - * - * NOTE: THIS IS NOT THE DEFAULT BEHAVIOUR - * By default, you CAN shrink an int into a char, a la shifting down. + * Determine if two types are compatible. + * A left char and a right int are compatible, as the char will fit into the int. + * The left char will need to be widened for assignment, however. * + * If strict is set, you can only widen the Left to the Right. + * If strict is false, any widening is valid. * */