Compare commits

...

2 Commits

Author SHA1 Message Date
a27d3dd782
Add support for pointers of char, int and long types 2020-09-13 02:26:49 +01:00
822376d142
Add new tests to help debugging 2020-09-13 02:26:18 +01:00
14 changed files with 257 additions and 57 deletions

View File

@ -16,6 +16,8 @@
extern_ struct SymbolTable Symbols[SYMBOLS];
extern_ char* TypeNames[9];
extern_ char* TokenStrings[];
extern_ char* TokenNames[];

View File

@ -16,6 +16,7 @@
* TYpes are prefixed TY.
* CoMParisons are prefixed CMP.
*
*
* NOTE: Tokens are different from Syntax Operations!
*
* Tokens should represent the characters that invoke them,
@ -49,6 +50,8 @@ enum TokenTypes {
LI_LPARE, // (
LI_RPARE, // )
LI_AMP, // &
TY_IDENTIFIER, // Identifier name. Variable, function, etc.
TY_NONE, // No return type. Literal void.
TY_CHAR, // "char" type keyword
@ -94,6 +97,9 @@ enum SyntaxOps {
OP_ASSIGN, // Assign an l-value
OP_ADDRESS, // Fetch the address of a var
OP_DEREF, // Get the value of the address in a pointer
TERM_INTLITERAL, // Integer Literal. This is a virtual operation, so it's a terminal.
REF_IDENT, // Reference (read) an identifier (variable).
@ -155,6 +161,12 @@ enum DataTypes {
RET_LONG, // "long" type keyword
RET_VOID, // "void" type keyword
// Pointer types
PTR_CHAR,
PTR_INT,
PTR_LONG,
PTR_VOID,
};
/*
@ -212,8 +224,10 @@ 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* ParseFunction();
struct ASTNode* ParseCompound();
@ -222,7 +236,9 @@ struct ASTNode* ParseCompound();
struct ASTNode* CallFunction();
struct ASTNode* ReturnStatement();
int ParseType(int Token);
int ParsePointer();
int ValueAt(int Type);
int PointerTo(int Type);
int ParseTokenToOperation(int Token);
@ -279,6 +295,9 @@ int AsDiv(int Left, int Right);
int AsLdVar(int ID);
int AsStrVar(int Register, int ID);
int AsDeref(int Reg, int Type);
int AsAddr(int ID);
void AsNewSymb(int ID);
int AsEqual(int Left, int Right);

View File

@ -26,8 +26,6 @@ static char* ByteRegisters[4] = { "%r8b", "%r9b", "%r10b", "%r11b" };
static char* Comparisons[6] = { "sete", "setne", "setl", "setg", "setle", "setge" };
static char* InvComparisons[6] = { "jne", "je", "jge", "jle", "jg", "jl"};
static char* Types[5] = { "none", "char", "int", "long", "void" };
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * R O O T O F A S S E M B L E R * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
@ -85,6 +83,12 @@ int AssembleTree(struct ASTNode* Node, int Register, int ParentOp) {
case OP_DIVIDE:
return AsDiv(LeftVal, RightVal);
case OP_ADDRESS:
return AsAddr(Node->Value.ID);
case OP_DEREF:
return AsDeref(LeftVal, Node->Left->ExprType);
case OP_ASSIGN:
return RightVal;
@ -356,18 +360,22 @@ int AsLdVar(int ID) {
break;
case RET_LONG:
case PTR_CHAR:
case PTR_INT:
case PTR_LONG:
case PTR_VOID:
fprintf(OutputFile, "\tmovq\t%s(%%rip), %s\n", Symbols[ID].Name, Registers[Reg]);
break;
default:
DieMessage("Bad type for loading", Types[Symbols[ID].Type]);
DieMessage("Bad type for loading", TypeNames[Symbols[ID].Type]);
}
return Reg;
}
int AsStrVar(int Register, int ID) {
printf("\tStoring contents of %s into %s\n", Registers[Register], Symbols[ID].Name);
printf("\tStoring contents of %s into %s, type %d\n", Registers[Register], Symbols[ID].Name, Symbols[ID].Type);
switch(Symbols[ID].Type) {
case RET_CHAR:
@ -380,16 +388,44 @@ int AsStrVar(int Register, int ID) {
break;
case RET_LONG:
case PTR_CHAR:
case PTR_INT:
case PTR_LONG:
case PTR_VOID:
fprintf(OutputFile, "\tmovq\t%s, %s(%%rip)\n", Registers[Register], Symbols[ID].Name);
break;
default:
DieMessage("Bad type for saving", Types[Symbols[ID].Type]);
DieMessage("Bad type for saving", TypeNames[Symbols[ID].Type]);
}
return Register;
}
int AsAddr(int ID) {
int Register = RetrieveRegister();
printf("\tSaving pointer of %s into %s\n", Symbols[ID].Name, Registers[Register]);
fprintf(OutputFile, "\tleaq\t%s(%%rip), %s\n", Symbols[ID].Name, Registers[Register]);
return Register;
}
int AsDeref(int Reg, int Type) {
printf("\tDereferencing %s\n", Registers[Reg]);
switch(Type) {
case PTR_CHAR:
fprintf(OutputFile, "\tmovzbq\t(%s), %s\n", Registers[Reg], Registers[Reg]);
break;
case PTR_INT:
case PTR_LONG:
fprintf(OutputFile, "\tmovq\t(%s), %s\n", Registers[Reg], Registers[Reg]);
break;
}
return Reg;
}
void AsNewSymb(int ID) {
int TypeSize;
@ -432,7 +468,7 @@ int AsReturn(int Register, int FuncID) {
break;
default:
DieMessage("Bad function type in generating return", Types[Symbols[FuncID].Type]);
DieMessage("Bad function type in generating return", TypeNames[Symbols[FuncID].Type]);
}

View File

@ -219,6 +219,10 @@ int Tokenise(struct Token* Token) {
Token->type = AR_SLASH;
break;
case '&':
Token->type = LI_AMP;
break;
case '=':
Char = NextChar();
// If the next char is =, we have ==, the compare equality token.

View File

@ -35,6 +35,8 @@ char* TokenNames[] = {
"Logical Block Start",
"Logical Block End",
"Dereference operator",
"Identifier",
"None Type",
"Char Type",
@ -52,21 +54,8 @@ char* TokenNames[] = {
"Return keyword"
};
static void TokeniseFile() {
char* TypeNames[9] = { "none", "char", "int", "long", "void", "charptr", "intptr", "longptr", "voidptr"};
struct Token Token;
while(Tokenise(&Token)) {
printf("Token %s", TokenStrings[Token.type]);
if(Token.type == LI_INT) {
printf(", value %d", Token.value);
}
printf("\n");
}
}
int main(int argc, char* argv[]) {
Line = 1;

View File

@ -99,7 +99,7 @@ int ParseTokenToOperation(int Token) {
*
*/
static struct ASTNode* ParsePrimary(void) {
struct ASTNode* ParsePrimary(void) {
struct ASTNode* Node;
int ID;
@ -174,7 +174,7 @@ struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
int LeftType, RightType;
int NodeType;
LeftNode = ParsePrimary();
LeftNode = PrefixStatement();
NodeType = CurrentToken.type;
if(NodeType == LI_SEMIC || NodeType == LI_RPARE)

66
src/Pointers.c Normal file
View File

@ -0,0 +1,66 @@
/*************/
/*GEMWIRE */
/* ERYTHRO*/
/*************/
#include <Defs.h>
#include <Data.h>
int PointerTo(int Type) {
printf("\t\tPointerising a %s\n", TypeNames[Type]);
// As it stands, the conversion between
// RET and PTR is +4.
// TODO: if we add types, increase this number
// TODO: Make this a proper translation table
// TODO: More checks! This can go wrong easily!
if(Type >= RET_CHAR && Type <= RET_VOID) {
return Type + 4;
} else {
DieDecimal("Unable to create a pointer to the desired type", Type);
}
return -1;
}
int ValueAt(int Type) {
printf("\t\tDereferencing a %s\n", TypeNames[Type]);
//TODO: this is still bullshittery!
if(Type >= PTR_CHAR && Type <= PTR_VOID) {
return Type - 4;
} else {
DieDecimal("Unable to dereference type", Type);
}
return -1;
}
int ParsePointer() {
int Type;
// TODO: THIS IS WRONG AND SHOULD NOT EXIST
// TY_CHAR is 21, RET_CHAR is 1.
// Offset is 20. Rest are in order
if(CurrentToken.type >= TY_CHAR && CurrentToken.type <= TY_VOID) {
Type = CurrentToken.type - 20;
} else {
DieDecimal("Illegal type for pointerisation", CurrentToken.type);
}
// Recursively scan more *s
// This makes things like:
// x = **y;
// possible.
while(1) {
Tokenise(&CurrentToken);
printf("\t\t\tType on parsing is %d\n", CurrentToken.type);
if(CurrentToken.type != AR_STAR)
break;
Type = PointerTo(Type);
}
return Type;
}

View File

@ -20,28 +20,11 @@
*
*/
static char* Types[5] = { "none", "char", "int", "long", "void" };
static int TypeSize[5] = { 0, 1, 4, 8, 0}; // in BYTES
int ParseType(int Token) {
switch(Token) {
case TY_CHAR:
return RET_CHAR;
case TY_VOID:
return RET_VOID;
case TY_INT:
return RET_INT;
default:
DieDecimal("Illegal variable type", Token);
}
}
static int TypeSize[9] = { 0, 1, 4, 8, 0, 8, 8, 8, 8}; // in BYTES
int PrimitiveSize(int Type) {
if(Type < RET_NONE || Type > RET_VOID)
DieMessage("Checking size of bad data type", Types[Type]);
if(Type < RET_NONE || Type > PTR_VOID)
DieDecimal("Checking size of bad data type", Type);
return TypeSize[Type];
}
@ -145,10 +128,9 @@ int TypesCompatible(int* Left, int* Right, int STRICT) {
*/
void BeginVariableDeclaration(void) {
int ID;
int Type = ParseType(CurrentToken.type);
int Type = ParsePointer(CurrentToken.type);
//printf("type: %s\n", Types[Type]);
Tokenise(&CurrentToken);
VerifyToken(TY_IDENTIFIER, "ident");
//printf("Identifier: %s\n", CurrentIdentifier);
@ -163,8 +145,8 @@ struct ASTNode* ParseFunction() {
struct ASTNode* FinalStatement;
int SymbolSlot, BreakLabel, Type;
Type = ParseType(CurrentToken.type);
Tokenise(&CurrentToken);
Type = ParsePointer(CurrentToken.type);
VerifyToken(KW_FUNC, "::");
VerifyToken(TY_IDENTIFIER, "ident");
@ -251,7 +233,7 @@ struct ASTNode* ParseIdentifier() {
VerifyToken(TY_IDENTIFIER, "ident");
printf("After parsing, the identifier name is %s, id %d in the symbol table.\n", CurrentIdentifier, FindSymbol(CurrentIdentifier));
printf("\t\tAfter parsing, the identifier name is %s, id %d in the symbol table.\n", CurrentIdentifier, FindSymbol(CurrentIdentifier));
if(CurrentToken.type == LI_LPARE)
return CallFunction();
@ -386,3 +368,40 @@ struct ASTNode* PrintStatement(void) {
return Tree;
}
struct ASTNode* PrefixStatement() {
struct ASTNode* Tree;
switch (CurrentToken.type) {
case LI_AMP:
Tokenise(&CurrentToken);
// To allow things like:
// x = &&y;
// We need to recursively parse prefixes;
Tree = PrefixStatement();
if(Tree->Operation != REF_IDENT)
Die("& must be followed by another & or an identifier.");
Tree->Operation = OP_ADDRESS;
Tree->ExprType = PointerTo(Tree->ExprType);
break;
case AR_STAR:
Tokenise(&CurrentToken);
Tree = PrefixStatement();
if(Tree->Operation != REF_IDENT && Tree->Operation != OP_DEREF)
Die("* must be followed by another * or an identifier.");
Tree = ConstructASTBranch(OP_DEREF, ValueAt(Tree->ExprType), Tree, 0);
break;
default:
Tree = ParsePrimary();
}
return Tree;
}

View File

@ -1,4 +1,4 @@
{
void :: main() {
int x;
x = 0;

View File

@ -11,5 +11,6 @@ void :: main() {
PrintInteger(Result);
PrintInteger(Testings(10) + 10);
PrintInteger(Testings(10) + i);
}

19
tests/funcs3 Normal file
View File

@ -0,0 +1,19 @@
int :: Testings() {
return (40);
}
void :: main() {
int Result;
PrintInteger(10);
Result = Testings(10);
PrintInteger(Result);
int i;
for(i = 0; i < 5; i = i + 1) {
PrintInteger(Testings(10) + i);
}
}

10
tests/funcs4 Normal file
View File

@ -0,0 +1,10 @@
void :: main() {
int i;
for(i = 0; i < 5; i = i + 1) {
PrintInteger(i);
}
}

22
tests/pointers Normal file
View File

@ -0,0 +1,22 @@
int :: main() {
char a;
char *b;
char c;
int d;
int *e;
int f;
a= 18;
PrintInteger(a);
b= &a;
c= *b;
PrintInteger(c);
d= 12;
PrintInteger(d);
e= &d;
f= *e;
PrintInteger(f);
return(0);
}

13
tests/print Normal file
View File

@ -0,0 +1,13 @@
void :: main() {
int x;
int y;
int m;
x = 5;
y = 50;
m = 300;
print m;
print y;
print x;
}