Small fixes, complete refactor
This commit is contained in:
parent
e19a945934
commit
72358aed9f
|
@ -295,6 +295,7 @@ int TypeIsInt(int Type);
|
||||||
int TypeIsPtr(int Type);
|
int TypeIsPtr(int Type);
|
||||||
|
|
||||||
char* TypeNames(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 * * * * * * * * *
|
* * * * * * * * * P A R S I N G * * * * * * * * *
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
//struct ASTNode* ParseNewASTNode(void);
|
|
||||||
//struct ASTNode* ParseAdditiveASTNode(void);
|
|
||||||
struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence);
|
struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence);
|
||||||
|
|
||||||
//int ParseAST(struct ASTNode* Node);
|
|
||||||
|
|
||||||
struct ASTNode* ParsePrimary(void);
|
struct ASTNode* ParsePrimary(void);
|
||||||
//void ParseStatements(void);
|
|
||||||
struct ASTNode* ParseStatement(void);
|
struct ASTNode* ParseStatement(void);
|
||||||
struct ASTNode* PrefixStatement();
|
struct ASTNode* PrefixStatement();
|
||||||
struct ASTNode* PostfixStatement();
|
struct ASTNode* PostfixStatement();
|
||||||
|
@ -335,6 +332,7 @@ void ParseGlobals();
|
||||||
struct ASTNode* ParseFunction(int Type);
|
struct ASTNode* ParseFunction(int Type);
|
||||||
struct ASTNode* ParseCompound();
|
struct ASTNode* ParseCompound();
|
||||||
|
|
||||||
|
struct SymbolTableEntry* BeginStructDeclaration();
|
||||||
struct ASTNode* GetExpressionList();
|
struct ASTNode* GetExpressionList();
|
||||||
struct ASTNode* CallFunction();
|
struct ASTNode* CallFunction();
|
||||||
struct ASTNode* ReturnStatement();
|
struct ASTNode* ReturnStatement();
|
||||||
|
@ -394,6 +392,7 @@ int RetrieveRegister();
|
||||||
void DeallocateRegister(int Register);
|
void DeallocateRegister(int Register);
|
||||||
|
|
||||||
int PrimitiveSize(int Type);
|
int PrimitiveSize(int Type);
|
||||||
|
int AsAlignMemory(int Type, int Offset, int Direction);
|
||||||
|
|
||||||
int AsLoad(int Value);
|
int AsLoad(int Value);
|
||||||
int AsAdd(int Left, int Right);
|
int AsAdd(int Left, int Right);
|
||||||
|
|
|
@ -317,6 +317,29 @@ int NewLabel(void) {
|
||||||
return id++;
|
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
|
// Assemble an If statement
|
||||||
int AsIf(struct ASTNode* Node) {
|
int AsIf(struct ASTNode* Node) {
|
||||||
int FalseLabel, EndLabel;
|
int FalseLabel, EndLabel;
|
||||||
|
@ -775,9 +798,12 @@ int AsStrDeref(int Register1, int Register2, int Type) {
|
||||||
|
|
||||||
// Assemble a global symbol (variable, struct, enum, function, string)
|
// Assemble a global symbol (variable, struct, enum, function, string)
|
||||||
void AsGlobalSymbol(struct SymbolTableEntry* Entry) {
|
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"
|
fprintf(OutputFile, "\t.data\n"
|
||||||
"\t.globl\t%s\n",
|
"\t.globl\t%s\n",
|
||||||
|
@ -785,14 +811,15 @@ void AsGlobalSymbol(struct SymbolTableEntry* Entry) {
|
||||||
|
|
||||||
fprintf(OutputFile, "%s:\n", Entry->Name);
|
fprintf(OutputFile, "%s:\n", Entry->Name);
|
||||||
|
|
||||||
for(int i = 0; i < Entry->Length; i++) {
|
switch(Size) {
|
||||||
switch(TypeSize) {
|
|
||||||
case 1: fprintf(OutputFile, "\t.byte\t0\r\n", Entry->Name); break;
|
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 4: fprintf(OutputFile, "\t.long\t0\r\n", Entry->Name); break;
|
||||||
case 8: fprintf(OutputFile, "\t.quad\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;
|
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.
|
// Assemble a function call, with all associated parameter bumping and stack movement.
|
||||||
|
|
|
@ -367,7 +367,7 @@ void Tokenise() {
|
||||||
if(RejectedToken != NULL) {
|
if(RejectedToken != NULL) {
|
||||||
Token = RejectedToken;
|
Token = RejectedToken;
|
||||||
RejectedToken = NULL;
|
RejectedToken = NULL;
|
||||||
return 1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Char = FindChar();
|
Char = FindChar();
|
||||||
|
@ -375,7 +375,7 @@ void Tokenise() {
|
||||||
switch(Char) {
|
switch(Char) {
|
||||||
case EOF:
|
case EOF:
|
||||||
Token->type = LI_EOF;
|
Token->type = LI_EOF;
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
case '+':
|
case '+':
|
||||||
// + can be either "+" or "++".
|
// + can be either "+" or "++".
|
||||||
|
|
|
@ -424,7 +424,7 @@ struct ASTNode* ParseStatement(void) {
|
||||||
case TY_LONG:
|
case TY_LONG:
|
||||||
case TY_INT:
|
case TY_INT:
|
||||||
printf("\t\tNew Variable: %s\n", CurrentIdentifier);
|
printf("\t\tNew Variable: %s\n", CurrentIdentifier);
|
||||||
Type = ParseOptionalPointer();
|
Type = ParseOptionalPointer(NULL);
|
||||||
VerifyToken(TY_IDENTIFIER, "ident");
|
VerifyToken(TY_IDENTIFIER, "ident");
|
||||||
BeginVariableDeclaration(Type, NULL, SC_LOCAL);
|
BeginVariableDeclaration(Type, NULL, SC_LOCAL);
|
||||||
VerifyToken(LI_SEMIC, ";"); // TODO: single line assignment?
|
VerifyToken(LI_SEMIC, ";"); // TODO: single line assignment?
|
||||||
|
@ -517,7 +517,7 @@ void ParseGlobals() {
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
printf("New definition incoming..\r\n\n");
|
printf("New definition incoming..\r\n\n");
|
||||||
Type = ParseOptionalPointer();
|
Type = ParseOptionalPointer(NULL);
|
||||||
|
|
||||||
//TODO: converge pathways on this block?
|
//TODO: converge pathways on this block?
|
||||||
if(CurrentToken.type == KW_FUNC) {
|
if(CurrentToken.type == KW_FUNC) {
|
||||||
|
|
|
@ -34,12 +34,14 @@ static int ReadDeclarationList(struct SymbolTableEntry* FunctionSymbol, int Stor
|
||||||
PrototypePointer = FunctionSymbol->Start;
|
PrototypePointer = FunctionSymbol->Start;
|
||||||
|
|
||||||
while(CurrentToken.type != LI_RPARE) {
|
while(CurrentToken.type != LI_RPARE) {
|
||||||
TokenType = ParseOptionalPointer();
|
TokenType = ParseOptionalPointer(FunctionSymbol);
|
||||||
VerifyToken(TY_IDENTIFIER, "identifier");
|
VerifyToken(TY_IDENTIFIER, "identifier");
|
||||||
|
|
||||||
|
printf("\tReading a new element: %s of type %d\n", CurrentIdentifier, TokenType);
|
||||||
|
|
||||||
if(PrototypePointer != NULL) {
|
if(PrototypePointer != NULL) {
|
||||||
if(TokenType != PrototypePointer->Type)
|
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;
|
PrototypePointer=PrototypePointer->NextSymbol;
|
||||||
} else {
|
} else {
|
||||||
BeginVariableDeclaration(TokenType, Composite, Storage);
|
BeginVariableDeclaration(TokenType, Composite, Storage);
|
||||||
|
@ -93,9 +95,9 @@ struct SymbolTableEntry* BeginStructDeclaration() {
|
||||||
|
|
||||||
Composite = AddSymbol(CurrentIdentifier, DAT_STRUCT, 0, SC_STRUCT, 0, 0, NULL);
|
Composite = AddSymbol(CurrentIdentifier, DAT_STRUCT, 0, SC_STRUCT, 0, 0, NULL);
|
||||||
Tokenise();
|
Tokenise();
|
||||||
|
printf("Reading a struct declaration..\n");
|
||||||
ReadDeclarationList(NULL, SC_MEMBER, LI_RBRAS);
|
ReadDeclarationList(NULL, SC_MEMBER, LI_RBRAC);
|
||||||
VerifyToken(LI_RBRAS, "]");
|
VerifyToken(LI_RBRAC, "}");
|
||||||
|
|
||||||
Composite->Start = StructMembers;
|
Composite->Start = StructMembers;
|
||||||
StructMembers = StructMembersEnd = NULL;
|
StructMembers = StructMembersEnd = NULL;
|
||||||
|
@ -195,7 +197,7 @@ struct ASTNode* ParseFunction(int Type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
VerifyToken(LI_LPARE, "(");
|
VerifyToken(LI_LPARE, "(");
|
||||||
ParamCount = ReadParameters(OldFunction);
|
ParamCount = ReadDeclarationList(OldFunction, SC_GLOBAL, LI_RPARE);
|
||||||
VerifyToken(LI_RPARE, ")");
|
VerifyToken(LI_RPARE, ")");
|
||||||
|
|
||||||
if(NewFunction) {
|
if(NewFunction) {
|
||||||
|
|
63
src/Types.c
63
src/Types.c
|
@ -7,11 +7,29 @@
|
||||||
#include <Defs.h>
|
#include <Defs.h>
|
||||||
#include <Data.h>
|
#include <Data.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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) {
|
int TypeIsInt(int Type) {
|
||||||
return ((Type & 0xf) == 0);
|
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) {
|
int TypeIsPtr(int Type) {
|
||||||
return ((Type & 0xf) != 0);
|
return ((Type & 0xf) != 0);
|
||||||
}
|
}
|
||||||
|
@ -20,12 +38,6 @@ int TypeIsPtr(int Type) {
|
||||||
* Turn a token type into its appropriate
|
* Turn a token type into its appropriate
|
||||||
* primitive type.
|
* primitive type.
|
||||||
*
|
*
|
||||||
* This is where we do redirections like:
|
|
||||||
* short -> s16
|
|
||||||
* long -> s64
|
|
||||||
* int -> s32
|
|
||||||
* char -> u8
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int PrimitiveSize(int Type) {
|
int PrimitiveSize(int Type) {
|
||||||
|
@ -41,8 +53,28 @@ int PrimitiveSize(int Type) {
|
||||||
return 0;
|
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];
|
static char TypeBuffer[7];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the name of the input Type as a string.
|
||||||
|
*/
|
||||||
char* TypeNames(int Type) {
|
char* TypeNames(int Type) {
|
||||||
switch(Type) {
|
switch(Type) {
|
||||||
case RET_CHAR: memcpy(TypeBuffer, "Char", 4); break;
|
case RET_CHAR: memcpy(TypeBuffer, "Char", 4); break;
|
||||||
|
@ -58,21 +90,12 @@ char* TypeNames(int Type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given two types, determine if they are compatible.
|
* Determine if two types are compatible.
|
||||||
*
|
* A left char and a right int are compatible, as the char will fit into the int.
|
||||||
* Depending on the value of STRICT, it will try to
|
* The left char will need to be widened for assignment, however.
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
|
* If strict is set, you can only widen the Left to the Right.
|
||||||
|
* If strict is false, any widening is valid.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user