502 lines
14 KiB
C
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;
|
|
|
|
}
|
|
}
|
|
|
|
|