Erythro/src/Parser.c
Curle 83959b4793
More work on arrays. Fixed some bugs.
Still need to figure out why AsStrDeref isn't working.
2020-11-21 02:07:44 +00:00

502 lines
14 KiB
C

/*************/
/*GEMWIRE */
/* ERYTHRO*/
/*************/
#include <stdio.h>
#include <stdlib.h>
#include "Defs.h"
#include "Data.h"
/*
* Precedence is directly related to Token Type.
*
* enum TokenTypes {
* LI_EOF, AR_PLUS, AR_MINUS, AR_STAR, AR_SLASH, LI_INT
* };
*
*/
static int Precedence[] =
{ 0, 10, // EOF, ASSIGN
20, 20, // + -
30, 30, // * /
40, 40, // =? !=
50, 50, // < >
50, 50}; // <= =>
static int OperatorPrecedence(int Token) {
int Prec = Precedence[Token];
if(Prec == 0 || Token >= RET_VOID) {
DieMessage("Attempting to determine operator precedence of an EOF or INT literal", TokenNames[Token]);
}
return Prec;
}
static int IsRightExpr(int Token) {
return (Token == LI_EQUAL);
}
/* * * * * * * * * * * * * * * * * * * * * * * *
* * * N O D E C O N S T R U C T I O N * * *
* * * * * * * * * * * * * * * * * * * * * * * */
struct ASTNode* ConstructASTNode(int Operation, int Type,
struct ASTNode* Left,
struct ASTNode* Middle,
struct ASTNode* Right,
int IntValue) {
struct ASTNode* Node;
Node = (struct ASTNode*) malloc(sizeof(struct ASTNode));
if(!Node) {
fprintf(stderr, "Unable to allocate node!");
exit(1);
}
Node->Operation = Operation;
Node->ExprType = Type;
Node->Left = Left;
Node->Middle = Middle;
Node->Right = Right;
Node->Value.IntValue = IntValue;
return Node;
}
struct ASTNode* ConstructASTLeaf(int Operation, int Type, int IntValue) {
return ConstructASTNode(Operation, Type, NULL, NULL, NULL, IntValue);
}
struct ASTNode* ConstructASTBranch(int Operation, int Type, struct ASTNode* Left, int IntValue) {
return ConstructASTNode(Operation, Type, Left, NULL, NULL, IntValue);
}
/* * * * * * * * * * * * * * * * * * * * * * * *
* * * * T O K E N P A R S I N G * * * *
* * * * * * * * * * * * * * * * * * * * * * * */
/*
* Take a Token Type, and convert it to an AST-Node Operation.
*
* TokenTypes and SyntaxOps are synchronized to make this easy.
*
*/
int ParseTokenToOperation(int Token) {
if(Token > LI_EOF && Token < LI_INT)
return Token;
DieDecimal("ParseToken: Unknown token", Token);
}
/*
* Parse a primary (terminal) expression.
* This currently handles literal expressions, constructing a leaf node
* and handing control back up the chain.
*
*
*/
struct ASTNode* ParsePrimary(void) {
struct ASTNode* Node;
int ID;
switch(CurrentToken.type) {
case LI_INT:
if((CurrentToken.value >= 0) && (CurrentToken.value < 256))
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_CHAR, CurrentToken.value);
else
Node = ConstructASTLeaf(TERM_INTLITERAL, RET_INT, CurrentToken.value);
break;
case TY_IDENTIFIER:
// A variable or a function?
// Read the next token
Tokenise(&CurrentToken);
// If the token after the identifier is a (, then it's a function.
if(CurrentToken.type == LI_LPARE)
return CallFunction();
if(CurrentToken.type == LI_LBRAS)
return AccessArray();
// Otherwise, we've read too far and need to go back.
RejectToken(&CurrentToken);
// It's a variable, so find the symbol and construct a leaf for it
ID = FindSymbol(CurrentIdentifier);
if(ID == -1)
DieMessage("Unknown Variable", CurrentIdentifier);
Node = ConstructASTLeaf(REF_IDENT, Symbols[ID].Type, ID);
break;
case LI_RPARE:
// Starting a ( expr ) block
Tokenise(&CurrentToken);
Node = ParsePrecedenceASTNode(0);
// Make sure we close
VerifyToken(LI_RPARE, ")");
return Node;
}
Tokenise(&CurrentToken);
return Node;
}
struct ASTNode* ParsePrecedenceASTNode(int PreviousTokenPrecedence) {
struct ASTNode* LeftNode, *RightNode;
struct ASTNode* LeftTemp, *RightTemp;
// int LeftType, RightType;
int NodeType, OpType;
LeftNode = PrefixStatement();
NodeType = CurrentToken.type;
//printf("%d\r\n", CurrentToken.type);
if(NodeType == LI_SEMIC || NodeType == LI_RPARE || NodeType == LI_RBRAS) {
//printf("Current token matches ; ) ]\r\n");
LeftNode->RVal = 1; return LeftNode;
}
//printf("Current token has value %d, type %s\n", CurrentToken.value, TokenNames[CurrentToken.type]);
while((OperatorPrecedence(NodeType) > PreviousTokenPrecedence) || (IsRightExpr(OpType) && OperatorPrecedence(OpType) == PreviousTokenPrecedence)) {
//printf("inside while\n");
Tokenise(&CurrentToken);
RightNode = ParsePrecedenceASTNode(Precedence[NodeType]);
/*
LeftType = LeftNode->ExprType;
RightType = RightNode->ExprType;
*/
/**
* While parsing this node, we may need to widen some types.
* This requires a few functions and checks.
*/
OpType = ParseTokenToOperation(NodeType);
if(OpType == OP_ASSIGN) {
printf("\tParsePrecedenceASTNode: Assignment statement\r\n");
RightNode->RVal = 1;
RightNode = MutateType(RightNode, LeftNode->ExprType, 0);
if(LeftNode == NULL)
Die("Incompatible Expression encountered in assignment");
//printf("\tAssigning variable: %s value %d\n", Symbols[FindSymbol(CurrentIdentifier)].Name, RightNode->Value.IntValue);
int currSymbolID = FindSymbol(CurrentIdentifier);
printf("\t\tAssigning variable: %s\n", Symbols[currSymbolID].Name);
printf("\t\tAfter parsing, the identifier name is %s, id %d in the symbol table.\n", CurrentIdentifier, FindSymbol(CurrentIdentifier));
LeftTemp = LeftNode;
LeftNode = RightNode;
RightNode = LeftTemp;
// Clear temps as ensurance
RightTemp = NULL;
LeftTemp = NULL;
} else {
LeftNode->RVal = 1;
RightNode->RVal = 1;
//printf("mutate left\r\n");
LeftTemp = MutateType(LeftNode, RightNode->ExprType, OpType);
//printf("mutate right\r\n");
RightTemp = MutateType(RightNode, LeftNode->ExprType, OpType);
//printf("mutate right over\r\n");
/**
* If both are null, the types are incompatible.
*/
if(LeftTemp == NULL && RightTemp == NULL)
Die("Incompatible types in parsing nodes");
/**
* If the left was valid, or valid for
* expansion, then it will be non-null.
*
* If it was valid, then this will be
* equivalent to LeftNode = LeftNode
*/
if(LeftTemp)
LeftNode = LeftTemp;
/**
* Same here, but there is a higher chance
* for the right node to be incompatible due
* to the nature of widening types.
*/
if(RightTemp)
RightNode = RightTemp;
}
/**
* Checks over, back to normal parsing.
*/
if(LeftTemp != NULL)
LeftNode = LeftTemp; //ConstructASTBranch(LeftType, RightNode->ExprType, LeftNode, 0);
if(RightTemp != NULL)
RightNode = RightTemp; // ConstructASTBranch(RightType, LeftNode->ExprType, RightNode, 0);
LeftNode = ConstructASTNode(ParseTokenToOperation(NodeType), LeftNode->ExprType, LeftNode, NULL, RightNode, 0);
NodeType = CurrentToken.type;
if(NodeType == LI_SEMIC || NodeType == LI_RPARE || NodeType == LI_RBRAS) {
LeftNode->RVal = 1;
return LeftNode;
}
}
LeftNode->RVal = 1;
return LeftNode;
}
/* struct ASTNode* ParseMultiplicativeASTNode(void) {
struct ASTNode* LeftNode, * RightNode;
int NodeType;
LeftNode = ParsePrimary();
NodeType = CurrentToken.type;
if(NodeType == LI_EOF)
return LeftNode;
while((NodeType == AR_STAR) || (NodeType == AR_SLASH)) {
Tokenise(&CurrentToken);
RightNode = ParsePrimary();
LeftNode = ConstructASTNode(ParseTokenToOperation(NodeType), LeftNode, NULL, RightNode, 0);
NodeType = CurrentToken.type;
if(NodeType == LI_EOF)
break;
}
return LeftNode;
}
*/
/* struct ASTNode* ParseAdditiveASTNode(void) {
struct ASTNode* LeftNode, * RightNode;
int NodeType;
LeftNode = ParseMultiplicativeASTNode();
NodeType = CurrentToken.type;
if(NodeType == LI_EOF)
return LeftNode;
while(1) {
Tokenise(&CurrentToken);
RightNode = ParseMultiplicativeASTNode();
LeftNode = ConstructASTNode(ParseTokenToOperation(NodeType), LeftNode, NULL, RightNode, 0);
NodeType = CurrentToken.type;
if(NodeType == LI_EOF)
break;
}
return LeftNode;
}
*/
/* * * * * * * * * * * * * * * * * * * * * * * *
* * * * I N T E R P R E T A T I O N * * * *
* * * * * * * * * * * * * * * * * * * * * * * */
int ParseAST(struct ASTNode* Node) {
int LeftVal, RightVal;
if(Node->Left)
LeftVal = ParseAST(Node->Left);
if(Node->Right)
RightVal = ParseAST(Node->Right);
/*
if(Node->Operation == TERM_INTLITERAL)
printf("int %d\n", Node->IntValue);
else
printf("%d %s %d\n", LeftVal, TokenStrings[Node->Operation], RightVal);
*/
switch(Node->Operation) {
case OP_ADD:
return (LeftVal + RightVal);
case OP_SUBTRACT:
return (LeftVal - RightVal);
case OP_MULTIPLY:
return (LeftVal * RightVal);
case OP_DIVIDE:
return (LeftVal / RightVal);
case REF_IDENT:
case TERM_INTLITERAL:
return Node->Value.IntValue;
default:
fprintf(stderr, "Unknown syntax token: %d\n", Node->Operation);
exit(1);
}
}
/* * * * * * * * * * * * * * * * * * * * *
* * * * F U N C T I O N S * * * *
* * * * * * * * * * * * * * * * * * * * */
struct ASTNode* CallFunction() {
struct ASTNode* Tree;
int FuncID;
//TODO: Test structural type!
if((FuncID = FindSymbol(CurrentIdentifier)) == -1 && (Symbols[FuncID].Structure == ST_FUNC))
DieMessage("Undeclared function", CurrentIdentifier);
VerifyToken(LI_LPARE, "(");
Tree = ParsePrecedenceASTNode(0);
Tree = ConstructASTBranch(OP_CALL, Symbols[FuncID].Type, Tree, FuncID);
VerifyToken(LI_RPARE, ")");
return Tree;
}
/* * * * * * * * * * * * * * * * * * * * * *
* * * * S T A T E M E N T S * * * *
* * * * * * * * * * * * * * * * * * * * * */
struct ASTNode* ParseStatement(void) {
int Type;
switch(CurrentToken.type) {
case TY_CHAR:
case TY_LONG:
case TY_INT:
printf("\t\tNew Variable: %s\n", CurrentIdentifier);
Type = ParseOptionalPointer();
VerifyToken(TY_IDENTIFIER, "ident");
BeginVariableDeclaration(Type);
return NULL;
/*case TY_IDENTIFIER:
if(Symbols[FindSymbol(CurrentIdentifier)].Structure == ST_FUNC)
printf("\t\tCalling Function: %s\n", Symbols[FindSymbol(CurrentIdentifier)].Name);
else
printf("\t\tAssigning variable: %s\n", Symbols[FindSymbol(CurrentIdentifier)].Name);
return ParseIdentifier();
*/
case KW_IF:
return IfStatement();
case KW_WHILE:
return WhileStatement();
case KW_FOR:
return ForStatement();
case KW_RETURN:
return ReturnStatement();
default:
ParsePrecedenceASTNode(0);
//DieDecimal("Syntax Error in single-statement parsing. Token:", CurrentToken.type);
}
}
struct ASTNode* ParseCompound() {
struct ASTNode* Left = NULL, *Tree;
// Compound statements are defined by comprising
// multiple statements inside { a bracket block }
VerifyToken(LI_LBRAC, "{");
while(1) {
printf("\tNew branch in compound\n");
Tree = ParseStatement();
if(Tree && (Tree->Operation == OP_PRINT || Tree->Operation == OP_ASSIGN
|| Tree->Operation == OP_RET || Tree->Operation == OP_CALL))
VerifyToken(LI_SEMIC, ";");
if(Tree) {
if(Left == NULL)
Left = Tree;
else
Left = ConstructASTNode(OP_COMP, RET_NONE, Left, NULL, Tree, 0);
}
if(CurrentToken.type == LI_RBRAC) {
VerifyToken(LI_RBRAC, "}");
return Left;
}
}
}
void ParseGlobals() {
struct ASTNode* Tree;
int Type, FunctionComing;
printf("Parsing global definitions\n");
while(1) {
printf("New definition incoming..\r\n\n");
Type = ParseOptionalPointer();
//TODO: converge pathways on this block?
if(CurrentToken.type == KW_FUNC) {
VerifyToken(KW_FUNC, "::");
FunctionComing = 1;
}
VerifyToken(TY_IDENTIFIER, "ident");
if(FunctionComing && CurrentToken.type == LI_LPARE) {
printf("\tParsing function");
Tree = ParseFunction(Type);
printf("\nBeginning assembler creation of new function %s\n", Symbols[Tree->Value.ID].Name);
AssembleTree(Tree, -1, 0);
} else {
printf("\tParsing global variable declaration\n");
BeginVariableDeclaration(Type);
}
if(CurrentToken.type == LI_EOF)
break;
}
}