2020-09-10 00:56:16 +00:00
|
|
|
|
|
|
|
/*************/
|
|
|
|
/*GEMWIRE */
|
|
|
|
/* ERYTHRO*/
|
|
|
|
/*************/
|
|
|
|
|
|
|
|
#include <Defs.h>
|
|
|
|
#include <Data.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handles the declaration of a type of a variable.
|
|
|
|
* int newVar;
|
|
|
|
*
|
|
|
|
* It verifies that we have the `int` keyword followed by a
|
|
|
|
* unique, non-keyword identifier.
|
|
|
|
*
|
|
|
|
* It then stores this variable into the symbol table.
|
|
|
|
*
|
|
|
|
* //TODO: Assemble this into the symbol table.
|
|
|
|
* //TODO: int i = 5;
|
|
|
|
*
|
|
|
|
*/
|
2020-09-13 22:41:46 +00:00
|
|
|
void BeginVariableDeclaration(int Type) {
|
2020-09-10 00:56:16 +00:00
|
|
|
int ID;
|
2020-11-21 02:07:44 +00:00
|
|
|
printf("type: %s\n", TypeNames[Type]);
|
2020-09-10 00:56:16 +00:00
|
|
|
|
2020-11-18 20:49:08 +00:00
|
|
|
if(CurrentToken.type == LI_LBRAS) {
|
|
|
|
Tokenise(&CurrentToken);
|
2020-11-21 02:07:44 +00:00
|
|
|
//Type = Type - 2;
|
2020-11-18 20:49:08 +00:00
|
|
|
if(CurrentToken.type == LI_INT) {
|
|
|
|
printf("Adding array %s that is %d x %s.\r\n", CurrentIdentifier, CurrentToken.value, TypeNames[Type]);
|
|
|
|
ID = AddArraySymbol(CurrentIdentifier, PointerTo(Type), ST_ARR, 0, CurrentToken.value);
|
|
|
|
AsNewSymb(ID);
|
2020-09-13 22:41:46 +00:00
|
|
|
}
|
2020-09-10 00:56:16 +00:00
|
|
|
|
2020-11-18 20:49:08 +00:00
|
|
|
Tokenise(&CurrentToken);
|
|
|
|
VerifyToken(LI_RBRAS, "]");
|
|
|
|
} else {
|
|
|
|
|
|
|
|
while(1) {
|
|
|
|
//printf("Identifier: %s\n", CurrentIdentifier);
|
|
|
|
printf("Adding symbol %s of type %s.\n", CurrentIdentifier, TypeNames[Type]);
|
2020-11-23 19:23:41 +00:00
|
|
|
ID = AddSymbol(CurrentIdentifier, Type, ST_VAR, 1);
|
2020-11-18 20:49:08 +00:00
|
|
|
AsNewSymb(ID);
|
|
|
|
|
|
|
|
if(CurrentToken.type == LI_SEMIC) {
|
|
|
|
printf("\tEnd of variables to declare in this statement\n");
|
|
|
|
Tokenise(&CurrentToken);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(CurrentToken.type == LI_COM) {
|
|
|
|
printf("\t\tStatement appears to continue. Integrating new variable.\n");
|
|
|
|
Tokenise(&CurrentToken);
|
|
|
|
VerifyToken(TY_IDENTIFIER, "ident");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
DieDecimal("\nExpected ; after identifier, found", CurrentToken.type);
|
|
|
|
}
|
2020-09-13 22:41:46 +00:00
|
|
|
}
|
2020-11-18 20:49:08 +00:00
|
|
|
|
|
|
|
VerifyToken(LI_SEMIC, ";");
|
2020-09-10 00:56:16 +00:00
|
|
|
}
|
|
|
|
|
2020-09-13 22:41:46 +00:00
|
|
|
struct ASTNode* ParseFunction(int Type) {
|
2020-09-10 00:56:16 +00:00
|
|
|
struct ASTNode* Tree;
|
|
|
|
struct ASTNode* FinalStatement;
|
2020-09-13 22:41:46 +00:00
|
|
|
int SymbolSlot, BreakLabel;
|
2020-09-10 00:56:16 +00:00
|
|
|
|
2020-11-21 02:07:44 +00:00
|
|
|
printf("\nIdentified function %s of return type %s\n", CurrentIdentifier, TypeNames[Type]);
|
2020-09-10 00:56:16 +00:00
|
|
|
|
|
|
|
BreakLabel = NewLabel();
|
|
|
|
|
2020-11-23 19:12:13 +00:00
|
|
|
SymbolSlot = AddFunctionSymbol(CurrentIdentifier, Type, ST_FUNC, BreakLabel, 1);
|
2020-09-10 00:56:16 +00:00
|
|
|
CurrentFunction = SymbolSlot;
|
|
|
|
|
|
|
|
VerifyToken(LI_LPARE, "(");
|
|
|
|
VerifyToken(LI_RPARE, ")");
|
|
|
|
|
|
|
|
Tree = ParseCompound();
|
|
|
|
|
|
|
|
if(Type != RET_VOID) {
|
|
|
|
// Functions with one statement have no composite node, so we have to check
|
|
|
|
FinalStatement = (Tree->Operation == OP_COMP) ? Tree->Right : Tree;
|
|
|
|
|
|
|
|
if(FinalStatement == NULL || FinalStatement->Operation != OP_RET) {
|
|
|
|
Die("Function with non-void type does not return");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return ConstructASTBranch(OP_FUNC, Tree->ExprType, Tree, SymbolSlot);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handles the logic for return.
|
|
|
|
* //TODO: No brackets
|
|
|
|
* //TODO: Type inference
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct ASTNode* ReturnStatement() {
|
|
|
|
struct ASTNode* Tree;
|
|
|
|
int ReturnType, FunctionType;
|
|
|
|
|
|
|
|
|
|
|
|
if(Symbols[CurrentFunction].Type == RET_VOID)
|
|
|
|
Die("Attempt to return from void function");
|
|
|
|
|
|
|
|
VerifyToken(KW_RETURN, "return");
|
|
|
|
|
|
|
|
VerifyToken(LI_LPARE, "("); // TODO: Make optional! Reject?
|
|
|
|
|
|
|
|
Tree = ParsePrecedenceASTNode(0);
|
|
|
|
|
2020-11-15 06:40:05 +00:00
|
|
|
/*
|
2020-09-10 00:56:16 +00:00
|
|
|
ReturnType = Tree->ExprType;
|
|
|
|
FunctionType = Symbols[CurrentFunction].Type;
|
2020-11-15 06:40:05 +00:00
|
|
|
*/
|
2020-09-10 00:56:16 +00:00
|
|
|
|
2020-11-15 06:40:05 +00:00
|
|
|
Tree = MutateType(Tree, Symbols[CurrentFunction].Type, 0);
|
|
|
|
if(Tree == NULL)
|
2020-09-10 00:56:16 +00:00
|
|
|
Die("Returning a value of incorrect type for function");
|
|
|
|
|
2020-11-15 06:40:05 +00:00
|
|
|
/*
|
2020-09-10 00:56:16 +00:00
|
|
|
if(ReturnType)
|
|
|
|
Tree = ConstructASTBranch(ReturnType, FunctionType, Tree, 0);
|
2020-11-15 06:40:05 +00:00
|
|
|
*/
|
|
|
|
|
2020-09-10 00:56:16 +00:00
|
|
|
Tree = ConstructASTBranch(OP_RET, RET_NONE, Tree, 0);
|
|
|
|
|
|
|
|
printf("\t\tReturning from function %s\n", Symbols[CurrentFunction].Name);
|
|
|
|
|
|
|
|
VerifyToken(LI_RPARE, ")"); // TODO: OPTIONALISE!
|
|
|
|
|
|
|
|
return Tree;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2020-09-14 01:05:24 +00:00
|
|
|
* Handles Identifiers.
|
2020-09-10 00:56:16 +00:00
|
|
|
*
|
2020-09-14 01:05:24 +00:00
|
|
|
* This is called for any of:
|
|
|
|
* - Calling a function
|
|
|
|
* - Assigning an lvalue variable
|
|
|
|
* - Performing arithmetic on a variable
|
|
|
|
* - Performing arithmetic with the return values of function calls
|
2020-09-10 00:56:16 +00:00
|
|
|
*
|
2020-09-14 01:05:24 +00:00
|
|
|
* For the case where you're assigning an l-value;
|
|
|
|
* You can assign with another assignment,
|
|
|
|
* a statement, a function or a literal.
|
2020-09-10 00:56:16 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2020-11-15 06:40:05 +00:00
|
|
|
/*
|
2020-09-10 00:56:16 +00:00
|
|
|
struct ASTNode* ParseIdentifier() {
|
|
|
|
struct ASTNode* Left, *Right, *Tree;
|
|
|
|
int LeftType, RightType;
|
|
|
|
int ID;
|
|
|
|
|
|
|
|
VerifyToken(TY_IDENTIFIER, "ident");
|
|
|
|
|
2020-09-13 01:26:49 +00:00
|
|
|
printf("\t\tAfter parsing, the identifier name is %s, id %d in the symbol table.\n", CurrentIdentifier, FindSymbol(CurrentIdentifier));
|
2020-09-12 01:52:51 +00:00
|
|
|
|
2020-09-10 00:56:16 +00:00
|
|
|
if(CurrentToken.type == LI_LPARE)
|
|
|
|
return CallFunction();
|
|
|
|
|
|
|
|
if((ID = FindSymbol(CurrentIdentifier)) == -1) {
|
|
|
|
printf("Symbol %s not in table. Table contents: %s, %s\n", CurrentIdentifier, Symbols[0].Name, Symbols[1].Name);
|
|
|
|
DieMessage("Undeclared Variable ", CurrentIdentifier);
|
|
|
|
}
|
|
|
|
Right = ConstructASTLeaf(LV_IDENT, Symbols[ID].Type, ID);
|
|
|
|
|
|
|
|
VerifyToken(LI_EQUAL, "=");
|
|
|
|
|
|
|
|
Left = ParsePrecedenceASTNode(0);
|
|
|
|
|
|
|
|
LeftType = Left->ExprType;
|
|
|
|
RightType = Right->ExprType;
|
|
|
|
|
2020-09-14 01:05:24 +00:00
|
|
|
Left = MutateType(Left, RightType, 0);
|
|
|
|
if(!Left)
|
|
|
|
Die("Incompatible types in assignment");
|
2020-09-10 00:56:16 +00:00
|
|
|
|
|
|
|
if(LeftType)
|
|
|
|
Left = ConstructASTBranch(LeftType, Right->ExprType, Left, 0);
|
|
|
|
|
|
|
|
Tree = ConstructASTNode(OP_ASSIGN, RET_INT, Left, NULL, Right, 0);
|
|
|
|
|
|
|
|
return Tree;
|
2020-11-15 06:40:05 +00:00
|
|
|
}*/
|
2020-09-10 00:56:16 +00:00
|
|
|
|
|
|
|
struct ASTNode* IfStatement() {
|
|
|
|
struct ASTNode* Condition, *True, *False = NULL;
|
|
|
|
|
|
|
|
VerifyToken(KW_IF, "if");
|
|
|
|
VerifyToken(LI_LPARE, "(");
|
|
|
|
|
|
|
|
Condition = ParsePrecedenceASTNode(0);
|
|
|
|
|
|
|
|
// Limit if(x) to =? != < > <= =>
|
|
|
|
// No null checking, no arithmetic, no functions.
|
|
|
|
// TODO: this
|
|
|
|
if(Condition->Operation < OP_EQUAL || Condition->Operation > OP_GREATE)
|
|
|
|
Die("Invalid Comparison in if statement");
|
|
|
|
|
|
|
|
VerifyToken(LI_RPARE, ")");
|
|
|
|
|
|
|
|
True = ParseCompound();
|
|
|
|
|
|
|
|
if(CurrentToken.type == KW_ELSE) {
|
|
|
|
Tokenise(&CurrentToken);
|
|
|
|
False = ParseCompound();
|
|
|
|
}
|
|
|
|
|
|
|
|
return ConstructASTNode(OP_IF, RET_NONE, Condition, True, False, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ASTNode* WhileStatement() {
|
|
|
|
struct ASTNode* Condition, *Body;
|
|
|
|
|
|
|
|
VerifyToken(KW_WHILE, "while");
|
|
|
|
VerifyToken(LI_LPARE, "(");
|
|
|
|
|
|
|
|
Condition = ParsePrecedenceASTNode(0);
|
|
|
|
|
|
|
|
if(Condition->Operation < OP_EQUAL || Condition->Operation > OP_GREATE)
|
|
|
|
Die("Bad Comparison inside while()");
|
|
|
|
|
|
|
|
VerifyToken(LI_RPARE, ")");
|
|
|
|
|
|
|
|
Body = ParseCompound();
|
|
|
|
|
|
|
|
return ConstructASTNode(OP_LOOP, RET_NONE, Condition, NULL, Body, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ASTNode* ForStatement() {
|
|
|
|
|
|
|
|
// for (preop; condition; postop) {
|
|
|
|
// body
|
|
|
|
//}
|
|
|
|
|
|
|
|
struct ASTNode* Condition, *Body;
|
|
|
|
struct ASTNode* Preop, *Postop;
|
|
|
|
|
|
|
|
struct ASTNode* Tree;
|
|
|
|
|
|
|
|
VerifyToken(KW_FOR, "for");
|
|
|
|
VerifyToken(LI_LPARE, "(");
|
|
|
|
|
|
|
|
Preop = ParseStatement();
|
|
|
|
VerifyToken(LI_SEMIC, ";");
|
|
|
|
|
|
|
|
Condition = ParsePrecedenceASTNode(0);
|
|
|
|
|
|
|
|
if(Condition->Operation < OP_EQUAL || Condition->Operation > OP_GREATE)
|
|
|
|
Die("Bad comparison in for");
|
|
|
|
VerifyToken(LI_SEMIC, ";");
|
|
|
|
|
|
|
|
Postop = ParseStatement();
|
|
|
|
VerifyToken(LI_RPARE, ")");
|
|
|
|
|
|
|
|
Body = ParseCompound();
|
|
|
|
|
|
|
|
// We need to be able to skip over the body and the postop, so we group them together.
|
|
|
|
Tree = ConstructASTNode(OP_COMP, RET_NONE, Body, NULL, Postop, 0);
|
|
|
|
// We need to be able to jump to the top of the condition and fall through to the body,
|
|
|
|
// so we group it with the last block
|
|
|
|
Tree = ConstructASTNode(OP_LOOP, RET_NONE, Condition, NULL, Tree, 0);
|
|
|
|
|
|
|
|
// We need to append the postop to the loop, to form the final for loop
|
|
|
|
return ConstructASTNode(OP_COMP, RET_NONE, Preop, NULL, Tree, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ASTNode* PrintStatement(void) {
|
|
|
|
struct ASTNode* Tree;
|
|
|
|
int LeftType, RightType;
|
|
|
|
|
|
|
|
VerifyToken(KW_PRINT, "print");
|
|
|
|
|
|
|
|
Tree = ParsePrecedenceASTNode(0);
|
|
|
|
|
|
|
|
LeftType = RET_INT;
|
|
|
|
RightType = Tree->ExprType;
|
|
|
|
|
2020-09-14 01:05:24 +00:00
|
|
|
Tree = MutateType(Tree, RightType, 0);
|
|
|
|
if(!Tree)
|
2020-09-10 00:56:16 +00:00
|
|
|
DieDecimal("Attempting to print an invalid type:", RightType);
|
|
|
|
|
|
|
|
if(RightType)
|
|
|
|
Tree = ConstructASTBranch(RightType, RET_INT, Tree, 0);
|
|
|
|
|
|
|
|
Tree = ConstructASTBranch(OP_PRINT, RET_NONE, Tree, 0);
|
|
|
|
|
|
|
|
//ParseAST(Tree);
|
|
|
|
|
|
|
|
return Tree;
|
|
|
|
|
2020-09-13 01:26:49 +00:00
|
|
|
}
|
|
|
|
|
2020-11-23 21:42:32 +00:00
|
|
|
struct ASTNode* PostfixStatement() {
|
|
|
|
struct ASTNode* Tree;
|
|
|
|
int ID;
|
|
|
|
|
|
|
|
Tokenise(&CurrentToken);
|
|
|
|
|
|
|
|
// If we get here, we're one of three things:
|
|
|
|
// - Function
|
|
|
|
// - Array
|
|
|
|
// - Variable
|
|
|
|
|
|
|
|
if(CurrentToken.type == LI_LPARE)
|
|
|
|
return CallFunction();
|
|
|
|
|
|
|
|
if(CurrentToken.type == LI_LBRAS)
|
|
|
|
return AccessArray();
|
|
|
|
|
|
|
|
// If we get here, we must be a variable.
|
|
|
|
// There's no guarantees that the variable is in
|
|
|
|
// the symbol table, though.
|
|
|
|
|
|
|
|
ID = FindSymbol(CurrentIdentifier);
|
|
|
|
if(ID == -1 || Symbols[ID].Structure != ST_VAR)
|
|
|
|
DieMessage("Unknown Variable", CurrentIdentifier);
|
|
|
|
|
|
|
|
// Here we check for postincrement and postdecrement.
|
|
|
|
|
|
|
|
switch(CurrentToken.type) {
|
|
|
|
case PPMM_PLUS:
|
|
|
|
Tokenise(&CurrentToken);
|
|
|
|
Tree = ConstructASTLeaf(OP_POSTINC, Symbols[ID].Type, ID);
|
|
|
|
break;
|
|
|
|
case PPMM_MINUS:
|
|
|
|
Tokenise(&CurrentToken);
|
|
|
|
Tree = ConstructASTLeaf(OP_POSTDEC, Symbols[ID].Type, ID);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Tree = ConstructASTLeaf(REF_IDENT, Symbols[ID].Type, ID);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Tree;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-09-13 01:26:49 +00:00
|
|
|
struct ASTNode* PrefixStatement() {
|
|
|
|
struct ASTNode* Tree;
|
|
|
|
|
|
|
|
switch (CurrentToken.type) {
|
2020-11-23 21:42:32 +00:00
|
|
|
case BOOL_INVERT:
|
|
|
|
Tokenise(&CurrentToken);
|
|
|
|
Tree = PrefixStatement();
|
|
|
|
Tree->RVal = 1;
|
|
|
|
Tree = ConstructASTBranch(OP_BOOLNOT, Tree->ExprType, Tree, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BIT_NOT:
|
|
|
|
Tokenise(&CurrentToken);
|
|
|
|
Tree = PrefixStatement();
|
|
|
|
Tree->RVal = 1;
|
|
|
|
Tree = ConstructASTBranch(OP_BITNOT, Tree->ExprType, Tree, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PPMM_PLUS:
|
|
|
|
Tokenise(&CurrentToken);
|
|
|
|
Tree = PrefixStatement();
|
|
|
|
|
|
|
|
if(Tree->Operation != REF_IDENT)
|
|
|
|
Die("++ not followed by identifier");
|
|
|
|
Tree = ConstructASTBranch(OP_PREINC, Tree->ExprType, Tree, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PPMM_MINUS:
|
|
|
|
Tokenise(&CurrentToken);
|
|
|
|
Tree = PrefixStatement();
|
|
|
|
|
|
|
|
if(Tree->Operation != REF_IDENT)
|
|
|
|
Die("-- not followed by identifier");
|
|
|
|
|
|
|
|
Tree = ConstructASTBranch(OP_PREDEC, Tree->ExprType, Tree, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BIT_AND:
|
2020-09-13 01:26:49 +00:00
|
|
|
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.");
|
2020-11-15 06:40:05 +00:00
|
|
|
|
2020-09-13 01:26:49 +00:00
|
|
|
Tree = ConstructASTBranch(OP_DEREF, ValueAt(Tree->ExprType), Tree, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Tree = ParsePrimary();
|
2020-11-15 06:40:05 +00:00
|
|
|
|
2020-09-13 01:26:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return Tree;
|
2020-09-10 00:56:16 +00:00
|
|
|
}
|