コード例 #1
0
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;
}
コード例 #2
0
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;
}
コード例 #3
0
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;
}
コード例 #4
0
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;
}
コード例 #5
0
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;
}
コード例 #6
0
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;
}