/*************/ /*GEMWIRE */ /* ERYTHRO*/ /*************/ #include #include #include static int ReadParameters(struct SymbolTableEntry* FunctionSymbol) { int TokenType, ParamCount = 0; struct SymbolTableEntry* PrototypePointer = NULL; if(FunctionSymbol != NULL) PrototypePointer = FunctionSymbol->Start; while(CurrentToken.type != LI_RPARE) { TokenType = ParseOptionalPointer(); VerifyToken(TY_IDENTIFIER, "identifier"); if(PrototypePointer != NULL) { if(TokenType != PrototypePointer->Type) DieDecimal("Function paramater of invalid type at index", ParamCount + 1); PrototypePointer=PrototypePointer->NextSymbol; } else { BeginVariableDeclaration(TokenType, SC_PARAM); } ParamCount++; switch(CurrentToken.type) { case LI_COM: Tokenise(&CurrentToken); break; case LI_RPARE: break; default: DieDecimal("Unexpected token in parameter", CurrentToken.type); } } if((FunctionSymbol != NULL) && (ParamCount != FunctionSymbol->Length)) DieMessage("Invalid number of parameters in prototyped function", FunctionSymbol->Name); return ParamCount; } /* * Handles the declaration of a type of a variable. * int newVar; * * It verifies that we have a type keyword followed by a * unique, non-keyword identifier. * * It then stores this variable into the symbol table, * and returns the new item. * */ struct SymbolTableEntry* BeginVariableDeclaration(int Type, int Scope) { struct SymbolTableEntry* Symbol = NULL; switch(Scope) { case SC_GLOBAL: if(FindGlobal(CurrentIdentifier) != NULL) DieMessage("Invalid redeclaration of global variable", CurrentIdentifier); case SC_LOCAL: case SC_PARAM: if(FindLocal(CurrentIdentifier) != NULL) DieMessage("Invalid redelcaration of local variable", CurrentIdentifier); } if(CurrentToken.type == LI_LBRAS) { Tokenise(&CurrentToken); if(CurrentToken.type == LI_INT) { switch(Scope) { case SC_GLOBAL: Symbol = AddSymbol(CurrentIdentifier, PointerTo(Type), ST_ARR, Scope, 1, 0); break; case SC_LOCAL: case SC_PARAM: Die("Local arrays are unimplemented"); } } Tokenise(&CurrentToken); VerifyToken(LI_RBRAS, "]"); } else { Symbol = AddSymbol(CurrentIdentifier, Type, ST_VAR, Scope, 1, 0); } return Symbol; } struct ASTNode* ParseFunction(int Type) { struct ASTNode* Tree; struct ASTNode* FinalStatement; struct SymbolTableEntry* OldFunction, *NewFunction = NULL; int SymbolSlot, BreakLabel, ParamCount, ID; if((OldFunction = FindSymbol(CurrentIdentifier)) != NULL) if(OldFunction->Storage != ST_FUNC) OldFunction = NULL; if(OldFunction == NULL) { BreakLabel = NewLabel(); NewFunction = AddSymbol(CurrentIdentifier, Type, ST_FUNC, SC_GLOBAL, BreakLabel, 0); } VerifyToken(LI_LPARE, "("); ParamCount = ReadParameters(OldFunction); VerifyToken(LI_RPARE, ")"); if(NewFunction) { NewFunction->Elements = ParamCount; NewFunction->Start = Params; OldFunction = NewFunction; } Params = ParamsEnd = NULL; if(CurrentToken.type == LI_SEMIC) { Tokenise(&CurrentToken); return NULL; } printf("\nIdentified%sfunction %s of return type %s, end label %d\n", (OldFunction == NULL) ? " new " : " overloaded ", OldFunction->Name, TypeNames(Type), BreakLabel); FunctionEntry = OldFunction; 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, OldFunction, BreakLabel); } /* * Handles the logic for return. * //TODO: No brackets * //TODO: Type inference * * */ struct ASTNode* ReturnStatement() { struct ASTNode* Tree; int ReturnType; if(FunctionEntry->Type == RET_VOID) Die("Attempt to return from void function"); VerifyToken(KW_RETURN, "return"); VerifyToken(LI_LPARE, "("); // TODO: Make optional! Reject? Tree = ParsePrecedenceASTNode(0); /* ReturnType = Tree->ExprType; FunctionType = Symbols[CurrentFunction].Type; */ Tree = MutateType(Tree, FunctionEntry->Type, 0); if(Tree == NULL) Die("Returning a value of incorrect type for function"); /* if(ReturnType) Tree = ConstructASTBranch(ReturnType, FunctionType, Tree, 0); */ Tree = ConstructASTBranch(OP_RET, RET_NONE, Tree, FunctionEntry, 0); printf("\t\tReturning from function %s\n", FunctionEntry->Name); VerifyToken(LI_RPARE, ")"); // TODO: OPTIONALISE! return Tree; } /* * Handles Identifiers. * * 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 * * For the case where you're assigning an l-value; * You can assign with another assignment, * a statement, a function or a literal. * */ /* struct ASTNode* ParseIdentifier() { struct ASTNode* Left, *Right, *Tree; int LeftType, RightType; int ID; VerifyToken(TY_IDENTIFIER, "ident"); 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(); 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; Left = MutateType(Left, RightType, 0); if(!Left) Die("Incompatible types in assignment"); if(LeftType) Left = ConstructASTBranch(LeftType, Right->ExprType, Left, 0); Tree = ConstructASTNode(OP_ASSIGN, RET_INT, Left, NULL, Right, 0); return Tree; }*/ 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) Condition = ConstructASTBranch(OP_BOOLCONV, Condition->ExprType, Condition, NULL, 0); VerifyToken(LI_RPARE, ")"); True = ParseCompound(); if(CurrentToken.type == KW_ELSE) { Tokenise(&CurrentToken); False = ParseCompound(); } return ConstructASTNode(OP_IF, RET_NONE, Condition, True, False, NULL, 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) Condition = ConstructASTBranch(OP_BOOLCONV, Condition->ExprType, Condition, NULL, 0); VerifyToken(LI_RPARE, ")"); Body = ParseCompound(); return ConstructASTNode(OP_LOOP, RET_NONE, Condition, NULL, Body, NULL, 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) Condition = ConstructASTBranch(OP_BOOLCONV, Condition->ExprType, Condition, NULL, 0); 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, NULL, 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, NULL, 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, NULL, 0); } struct ASTNode* PrintStatement(void) { struct ASTNode* Tree; int LeftType, RightType; VerifyToken(KW_PRINT, "print"); Tree = ParsePrecedenceASTNode(0); LeftType = RET_INT; RightType = Tree->ExprType; Tree = MutateType(Tree, RightType, 0); if(!Tree) DieDecimal("Attempting to print an invalid type:", RightType); if(RightType) Tree = ConstructASTBranch(RightType, RET_INT, Tree, NULL, 0); Tree = ConstructASTBranch(OP_PRINT, RET_NONE, Tree, NULL, 0); //ParseAST(Tree); return Tree; } struct ASTNode* PostfixStatement() { struct ASTNode* Tree; struct SymbolTableEntry* Entry; 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. if((Entry = FindSymbol(CurrentIdentifier)) == NULL || Entry->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, Entry->Type, Entry, 0); break; case PPMM_MINUS: Tokenise(&CurrentToken); Tree = ConstructASTLeaf(OP_POSTDEC, Entry->Type, Entry, 0); break; default: Tree = ConstructASTLeaf(REF_IDENT, Entry->Type, Entry, 0); } return Tree; } struct ASTNode* PrefixStatement() { struct ASTNode* Tree; switch (CurrentToken.type) { case BOOL_INVERT: Tokenise(&CurrentToken); Tree = PrefixStatement(); Tree->RVal = 1; Tree = ConstructASTBranch(OP_BOOLNOT, Tree->ExprType, Tree, NULL, 0); break; case BIT_NOT: Tokenise(&CurrentToken); Tree = PrefixStatement(); Tree->RVal = 1; Tree = ConstructASTBranch(OP_BITNOT, Tree->ExprType, Tree, NULL, 0); break; case AR_MINUS: Tokenise(&CurrentToken); Tree = PrefixStatement(); Tree = ConstructASTBranch(OP_NEGATE, Tree->ExprType, Tree, NULL, 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, NULL, 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, NULL, 0); break; case BIT_AND: 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, NULL, 0); break; default: Tree = ParsePrimary(); } return Tree; }