void CodeGenerator::ProcessParseTree(int flags) { infunc(CodeGenerator::ProcessParseTree); ParseTree *tree; // Allocate some space for the parse tree if ((tree = new ParseTree) == NULL) throw CError("Couldn't allocate parse tree"); // Build the parse tree (steps passed all the tokens) tree->Build(tokeniser, TOKEN_END_OF_LINE, TOKEN_NULL); // Reduce the tree if possible tree->Optimise(); if (g_Object) { tree->CompleteTypes(flags); tree->GenerateCode(flags); // Yacka // tree->Debug(); } // The tree is no longer needed delete tree; outfunc; }
void CodeGenerator::ProcessReturnTerm(int flags) { infunc(CodeGenerator::ProcessKeywordTerm); ParseTree *tree; if (!(flags & FLAGS_IN_FUNCTION)) throw CompileError("(Line %d) Cannot specify return keyword outside of a function", CUR_TOKEN.line); INC_TOKEN; // Does this function return any values? if (cur_class->cur_function->GetReturnType().id == VARIABLE_TYPEID_VOID) { // Can only end here if (CUR_TOKEN.type != TOKEN_END_OF_LINE) throw CompileError("(Line %d) Cannot specify return value for void function", CUR_TOKEN.line); return; } // Allocate the parse tree if ((tree = new ParseTree) == NULL) throw CError("Couldn't allocate parse tree"); // Build the parse tree tree->Build(tokeniser, TOKEN_END_OF_LINE, TOKEN_NULL); // Reduce it tree->Optimise(); if (g_Object) { tree->CompleteTypes(flags | FLAGS_IMPLICIT_ASSIGNMENT); tree->GenerateCode(flags | FLAGS_IMPLICIT_ASSIGNMENT); } // Don't need the tree delete tree; // Mark the return cur_class->cur_function->had_return = 1; if (g_Object) { // Pop the return value to a safe place if (cur_class->cur_function->GetReturnType().id != VARIABLE_TYPEID_VOID) g_Object->WriteOp(OPCODE_POP_RETURN); // Write the return code cur_class->cur_function->WriteReturn(g_Object); } outfunc; }
void CodeGenerator::ProcessWhileTerm(int flags) { infunc(CodeGenerator::ProcessWhileTerm); ParseTree *tree; int code_position; if (!(flags & FLAGS_IN_CLASS)) throw CompileError("(Line %d) Can't have a while loop statement outside of a class", CUR_TOKEN.line); // Go passed the declare INC_TOKEN; if (CUR_TOKEN.type != TOKEN_LEFT_BRACKET) throw CompileError("(Line %d) Expecting an opening bracket", CUR_TOKEN.line); // Should be at the expression opening here INC_TOKEN; // Allocate the parse tree for the test expression if ((tree = new ParseTree) == NULL) throw CError("Couldn't allocate parse tree"); // Build the tree, ending at the closing bracket tree->Build(tokeniser, TOKEN_RIGHT_BRACKET, TOKEN_NULL); INC_TOKEN; // Reduce the tree tree->Optimise(); if (g_Object) { // Mark before the loop test code_position = g_Object->GetPosition(); // Generate the test statement tree->CompleteTypes(flags | FLAGS_IMPLICIT_ASSIGNMENT); tree->GenerateCode(flags | FLAGS_IMPLICIT_ASSIGNMENT); } // Valid? if (tree->GetTop() == NULL) throw CompileError("(Line %d) Expecting an expression for the if statement", CUR_TOKEN.line); if (g_Object) { g_Object->AddBackpatchItem(14); // Generate the jump out of the loop if (tree->GetTop()->out_type.id == VARIABLE_TYPEID_FLOAT) g_Object->WriteOp(OPCODE_FJZ, 0); else g_Object->WriteOp(OPCODE_JZ, 0); } // Don't need this anymore delete tree; ProcessBlock(flags | FLAGS_ALLOW_LINE_BLOCKS | FLAGS_ALLOW_BREAK_CONTINUE); if (g_Object) { // Jump back to the beginning of the loop g_Object->WriteOp(OPCODE_JMP, code_position); // Update the loop jump out g_Object->UpdateItems(14); // Update all breaks g_Object->UpdateItems(12); // Update all continues g_Object->UpdateItems(13, code_position); } outfunc; }
void CodeGenerator::ProcessIfTerm(int flags) { infunc(CodeGenerator::ProcessIfTerm); ParseTree *tree; ParseTreeNode *top; int a, b; a = b = 100 + rand(); while (a == b) b = 100 + rand(); if (!(flags & FLAGS_IN_CLASS)) throw CompileError("(Line %d) Can't have an if statement outside of a class", CUR_TOKEN.line); // Go passed the declare INC_TOKEN; if (CUR_TOKEN.type != TOKEN_LEFT_BRACKET) throw CompileError("(Line %d) Expecting an opening bracket", CUR_TOKEN.line); // Should be at the expression opening here INC_TOKEN; // Allocate the parse tree for the expression if ((tree = new ParseTree) == NULL) throw CError("Couldn't allocate parse tree"); // Build the tree, ending at the if close tree->Build(tokeniser, TOKEN_RIGHT_BRACKET, TOKEN_NULL); INC_TOKEN; // Reduce the tree tree->Optimise(); if (g_Object) { tree->CompleteTypes(flags | FLAGS_IMPLICIT_ASSIGNMENT); // Implicit assignment (no need for asg at the end of the expression) tree->GenerateCode(flags | FLAGS_IMPLICIT_ASSIGNMENT); } if (tree->GetTop() == NULL) throw CompileError("(Line %d) Expecting an expression for the if statement", CUR_TOKEN.line); if (g_Object) { // Mark this jump g_Object->AddBackpatchItem(a); // Grab the top tree node if ((top = tree->GetTop()) == NULL) throw CompileError("(Line %d) Expecting an expression for the if statement", CUR_TOKEN.line); // Jump over the following block if the expression is false if (top->out_type.id == VARIABLE_TYPEID_FLOAT) g_Object->WriteOp(OPCODE_FJZ, 0); else g_Object->WriteOp(OPCODE_JZ, 0); } // The tree is no longer needed delete tree; BlockType bt = ProcessBlock(flags | FLAGS_ALLOW_LINE_BLOCKS); if (NEXT_TOKEN.type == TOKEN_ELSE) { // Step over the close scope INC_TOKEN; if (g_Object) { // Mark this jump, at the end of the if's true block g_Object->AddBackpatchItem(b); // Jump over the else false block g_Object->WriteOp(OPCODE_JMP, 0); } } if (g_Object) g_Object->UpdateItems(a); if (CUR_TOKEN.type == TOKEN_ELSE) { // Step over the keyword INC_TOKEN; ProcessBlock(flags | FLAGS_ALLOW_LINE_BLOCKS); // Back patch the jump over the else block if (g_Object) g_Object->UpdateItems(b); } outfunc; }