Esempio n. 1
0
Error GDCompiler::_parse_block(CodeGen& codegen,const GDParser::BlockNode *p_block,int p_stack_level,int p_break_addr,int p_continue_addr) {

	codegen.push_stack_identifiers();
	int new_identifiers=0;
	codegen.current_line=p_block->line;

	for(int i=0;i<p_block->statements.size();i++) {

		const GDParser::Node *s = p_block->statements[i];


		switch(s->type) {
			case GDParser::Node::TYPE_NEWLINE: {

				const GDParser::NewLineNode *nl = static_cast<const GDParser::NewLineNode*>(s);
				codegen.opcodes.push_back(GDFunction::OPCODE_LINE);
				codegen.opcodes.push_back(nl->line);
				codegen.current_line=nl->line;

			} break;
			case GDParser::Node::TYPE_CONTROL_FLOW: {
				// try subblocks

				const GDParser::ControlFlowNode *cf = static_cast<const GDParser::ControlFlowNode*>(s);

				switch(cf->cf_type) {


					case GDParser::ControlFlowNode::CF_IF: {

#ifdef DEBUG_ENABLED
						codegen.opcodes.push_back(GDFunction::OPCODE_LINE);
						codegen.opcodes.push_back(cf->line);
						codegen.current_line=cf->line;
#endif
						int ret = _parse_expression(codegen,cf->arguments[0],p_stack_level,false);
						if (ret<0)
							return ERR_PARSE_ERROR;

						codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF_NOT);
						codegen.opcodes.push_back(ret);
						int else_addr=codegen.opcodes.size();
						codegen.opcodes.push_back(0); //temporary

						Error err = _parse_block(codegen,cf->body,p_stack_level,p_break_addr,p_continue_addr);
						if (err)
							return err;

						if (cf->body_else) {

							codegen.opcodes.push_back(GDFunction::OPCODE_JUMP);
							int end_addr=codegen.opcodes.size();
							codegen.opcodes.push_back(0);
							codegen.opcodes[else_addr]=codegen.opcodes.size();

							Error err = _parse_block(codegen,cf->body_else,p_stack_level,p_break_addr,p_continue_addr);
							if (err)
								return err;

							codegen.opcodes[end_addr]=codegen.opcodes.size();
						} else {
							//end without else
							codegen.opcodes[else_addr]=codegen.opcodes.size();

						}

					} break;
					case GDParser::ControlFlowNode::CF_FOR: {



						int slevel=p_stack_level;
						int iter_stack_pos=slevel;
						int iterator_pos = (slevel++)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS);
						int counter_pos = (slevel++)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS);
						int container_pos = (slevel++)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS);
						codegen.alloc_stack(slevel);

						    codegen.push_stack_identifiers();
						      codegen.add_stack_identifier(static_cast<const GDParser::IdentifierNode*>(cf->arguments[0])->name,iter_stack_pos);

						int ret = _parse_expression(codegen,cf->arguments[1],slevel,false);
						if (ret<0)
							return ERR_COMPILATION_FAILED;

						//assign container
						codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN);
						codegen.opcodes.push_back(container_pos);
						codegen.opcodes.push_back(ret);

						//begin loop
						codegen.opcodes.push_back(GDFunction::OPCODE_ITERATE_BEGIN);
						codegen.opcodes.push_back(counter_pos);
						codegen.opcodes.push_back(container_pos);
						codegen.opcodes.push_back(codegen.opcodes.size()+4);
						codegen.opcodes.push_back(iterator_pos);
						codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); //skip code for next
						codegen.opcodes.push_back(codegen.opcodes.size()+8);
						//break loop
						int break_pos=codegen.opcodes.size();
						codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); //skip code for next
						codegen.opcodes.push_back(0); //skip code for next
						//next loop
						int continue_pos=codegen.opcodes.size();
						codegen.opcodes.push_back(GDFunction::OPCODE_ITERATE);
						codegen.opcodes.push_back(counter_pos);
						codegen.opcodes.push_back(container_pos);
						codegen.opcodes.push_back(break_pos);
						codegen.opcodes.push_back(iterator_pos);


						Error err = _parse_block(codegen,cf->body,slevel,break_pos,continue_pos);
						if (err)
							return err;


						codegen.opcodes.push_back(GDFunction::OPCODE_JUMP);
						codegen.opcodes.push_back(continue_pos);
						codegen.opcodes[break_pos+1]=codegen.opcodes.size();


						codegen.pop_stack_identifiers();

					} break;
					case GDParser::ControlFlowNode::CF_WHILE: {

						codegen.opcodes.push_back(GDFunction::OPCODE_JUMP);
						codegen.opcodes.push_back(codegen.opcodes.size()+3);
						int break_addr=codegen.opcodes.size();
						codegen.opcodes.push_back(GDFunction::OPCODE_JUMP);
						codegen.opcodes.push_back(0);
						int continue_addr=codegen.opcodes.size();

						int ret = _parse_expression(codegen,cf->arguments[0],p_stack_level,false);
						if (ret<0)
							return ERR_PARSE_ERROR;
						codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF_NOT);
						codegen.opcodes.push_back(ret);
						codegen.opcodes.push_back(break_addr);
						Error err = _parse_block(codegen,cf->body,p_stack_level,break_addr,continue_addr);
						if (err)
							return err;
						codegen.opcodes.push_back(GDFunction::OPCODE_JUMP);
						codegen.opcodes.push_back(continue_addr);

						codegen.opcodes[break_addr+1]=codegen.opcodes.size();

					} break;
					case GDParser::ControlFlowNode::CF_SWITCH: {

					} break;
					case GDParser::ControlFlowNode::CF_BREAK: {

						if (p_break_addr<0) {

							_set_error("'break'' not within loop",cf);
							return ERR_COMPILATION_FAILED;
						}
						codegen.opcodes.push_back(GDFunction::OPCODE_JUMP);
						codegen.opcodes.push_back(p_break_addr);

					} break;
					case GDParser::ControlFlowNode::CF_CONTINUE: {

						if (p_continue_addr<0) {

							_set_error("'continue' not within loop",cf);
							return ERR_COMPILATION_FAILED;
						}

						codegen.opcodes.push_back(GDFunction::OPCODE_JUMP);
						codegen.opcodes.push_back(p_continue_addr);

					} break;
					case GDParser::ControlFlowNode::CF_RETURN: {

						int ret;

						if (cf->arguments.size()) {

							ret = _parse_expression(codegen,cf->arguments[0],p_stack_level,false);
							if (ret<0)
								return ERR_PARSE_ERROR;

						} else {

							ret=GDFunction::ADDR_TYPE_NIL << GDFunction::ADDR_BITS;
						}

						codegen.opcodes.push_back(GDFunction::OPCODE_RETURN);
						codegen.opcodes.push_back(ret);

					} break;

				}
			} break;
			case GDParser::Node::TYPE_ASSERT: {
				// try subblocks

				const GDParser::AssertNode *as = static_cast<const GDParser::AssertNode*>(s);

				int ret = _parse_expression(codegen,as->condition,p_stack_level,false);
				if (ret<0)
					return ERR_PARSE_ERROR;

				codegen.opcodes.push_back(GDFunction::OPCODE_ASSERT);
				codegen.opcodes.push_back(ret);
			} break;
			case GDParser::Node::TYPE_LOCAL_VAR: {


				const GDParser::LocalVarNode *lv = static_cast<const GDParser::LocalVarNode*>(s);

				codegen.add_stack_identifier(lv->name,p_stack_level++);
				codegen.alloc_stack(p_stack_level);
				new_identifiers++;

			} break;
			default: {
				//expression
				int ret = _parse_expression(codegen,s,p_stack_level,true);
				if (ret<0)
					return ERR_PARSE_ERROR;
			} break;

		}

	}
	codegen.pop_stack_identifiers();
	return OK;
}