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; }
void CodeGenerator::ReadConstant(dynamic *num, VarType &type, _TokenType terminator, _TokenType extra) { infunc(CodeGenerator::ReadConstant); ParseTree *tree; ParseTreeNode *top; // Allocate the parse tree if ((tree = new ParseTree) == NULL) throw CError("Couldn't allocate parse tree"); // Build the tree tree->Build(tokeniser, terminator, extra); // Reduce to a single constant tree->Optimise(); // Grab the top of the tree if ((top = tree->GetTop()) == NULL) throw CompileError("(Line %d) No constant defined", CUR_TOKEN.line); // Get to see if the reduction produces a constant if (top->GetNodeType() != PTNODE_TYPE_CONSTANT || top->children[0] || top->children[1]) throw CompileError("(Line %d) Definition not a constant", CUR_TOKEN.line); // Check for a floating point definition in the place of an integer if (type.id != VARIABLE_TYPEID_FLOAT && top->out_type.id == VARIABLE_TYPEID_FLOAT) throw CompileError("(Line %d) Type mismatch", CUR_TOKEN.line); // Scan for the constant with the intended type switch (type.id) { // char case (VARIABLE_TYPEID_CHAR): num->i = ((Constant *)top)->value.i; if (num->i > 127 || num->i < -128) throw CompileError("(Line %d) Constant out of range for variable type 'char'", CUR_TOKEN.line); break; // short case (VARIABLE_TYPEID_SHORT): num->i = ((Constant *)top)->value.i; if (num->i > 32767 || num->i < -32768) throw CompileError("(Line %d) Constant out of range for variable type 'short'", CUR_TOKEN.line); break; // int case (VARIABLE_TYPEID_INT): num->i = ((Constant *)top)->value.i; break; // unsigned char case (VARIABLE_TYPEID_UCHAR): num->i = ((Constant *)top)->value.i; if (num->i > 255 || num->i < 0) throw CompileError("(Line %d) Constant out of range for variable type 'unsigned char'", CUR_TOKEN.line); break; // unsigned short case (VARIABLE_TYPEID_USHORT): num->i = ((Constant *)top)->value.i; if (num->i > 65535 || num->i < 0) throw CompileError("(Line %d) Constant out of range for variable type 'unsigned short'", CUR_TOKEN.line); break; // unsigned int case (VARIABLE_TYPEID_UINT): num->ui = ((Constant *)top)->value.ui; break; // float case (VARIABLE_TYPEID_FLOAT): num->f = ((Constant *)top)->value.f; break; case (VARIABLE_TYPEID_STRING): num->i = ((StringLiteral *)top)->string->GetAddress(); break; } outfunc; }
void CodeGenerator::GetArrayInfo(VarType &type) { infunc(CodeGenerator::GetArrayInfo); ParseTree *tree; ParseTreeNode *top; // Should be at the array 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 array close tree->Build(tokeniser, TOKEN_ARRAY_CLOSE, TOKEN_NULL); INC_TOKEN; // Reduce the tree to a single constant tree->Optimise(); // Grab the top tree node if ((top = tree->GetTop()) == NULL) throw CompileError("(Line %d) No dimension for array", CUR_TOKEN.line); // Is it a constant? if (top->GetNodeType() != PTNODE_TYPE_CONSTANT || top->children[0] || top->children[1]) throw CompileError("(Line %d) Array size is not a constant", CUR_TOKEN.line); // Check for floating point dimensions if (top->out_type.id == VARIABLE_TYPEID_FLOAT) throw CompileError("(Line %d) Cannot specify array dimension using floats", CUR_TOKEN.line); // Retrieve the correct value switch (top->out_type.id) { case (VARIABLE_TYPEID_CHAR): type.elements = (int)((Constant *)top)->value.c; break; case (VARIABLE_TYPEID_SHORT): type.elements = (int)((Constant *)top)->value.s; break; case (VARIABLE_TYPEID_INT): type.elements = (int)((Constant *)top)->value.i; break; case (VARIABLE_TYPEID_UCHAR): type.elements = (int)((Constant *)top)->value.uc; break; case (VARIABLE_TYPEID_USHORT): type.elements = (int)((Constant *)top)->value.us; break; case (VARIABLE_TYPEID_UINT): type.elements = (int)((Constant *)top)->value.ui; break; } // Set it as an array type.array = 1; // The tree is no longer needed delete tree; outfunc; }