⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gencode.c

📁 C编译器,在VC6.0环境下开发
💻 C
字号:
#include	"GenCode.h"
#include	"Common.h"
#include	"Error.h"
#include	"SymTab.h"
#include	<stdio.h>
#include	<string.h>
#include	<assert.h>

// for test
//static	char	_OUTPUT_FILE_NAME[] = "MMOutput.asm";

static	char	_TMP_DECL_FILE_NAME[] = "~$_decl.tmp";
static	char	_TMP_DATA_FILE_NAME[] = "~$_data.tmp";
static	char	_TMP_CODE_FILE_NAME[] = "~$_code.tmp";
static	char	_TMP_CODE2_FILE_NAME[]= "~$_code2.tmp";
static	char	_DATA_SEG_NAME[] = "_data\t%s";
static	char	_CODE_SEG_NAME[] = "_text\t%s";
static	char	_START_LABEL_NAME[] = "start";
static	char	_GB_LABEL_NAME[] = "bb_label_%d";

static	char	sg_buf[MAX_CHAR_IN_LINE];
static	char	sg_buf1[MAX_CHAR_IN_LINE];

static	FILE	*sg_decl_fp = NULL;
static	FILE	*sg_data_fp = NULL;
static	FILE	*sg_code_fp = NULL;
static	FILE	*sg_code2_fp = NULL;
static	unsigned	sg_is_main_func_exist = 0;

static void	append_file_by_file(FILE *fpd, FILE *fps)
{
	fseek( fps, 0L, SEEK_SET);
	fgets(sg_buf, MAX_CHAR_IN_LINE, fps);
	while ( !feof(fps) )
	{
		fputs(sg_buf, fpd);
		fgets(sg_buf, MAX_CHAR_IN_LINE, fps);
	}
}

void	open_code2()
{
	assert( !sg_code2_fp );

	sg_code2_fp = fopen(_TMP_CODE2_FILE_NAME,"w+");
	if ( !sg_code2_fp )
	{
		parse_error("can't open tmp file", _TMP_CODE2_FILE_NAME);
		user_exit(1);
	}
}

void	close_code2()
{
	assert( sg_code2_fp );

	fclose( sg_code2_fp );
	sg_code2_fp  = NULL;
}

void	write_to_code2(char *p_code)
{
	assert( sg_code2_fp );

	fputs(p_code, sg_code2_fp);
	fputs("\n", sg_code2_fp);
}

void	write_to_code(char *p_code)
{
	assert( sg_code_fp );

	fputs(p_code, sg_code_fp);
	fputs("\n", sg_code_fp);
}

void	write_to_data(char *p_code)
{
	assert( sg_data_fp );

	fputs(p_code, sg_data_fp);
	fputs("\n", sg_data_fp);
}

void	write_to_decl(char *p_code)
{
	assert( sg_decl_fp );

	fputs(p_code, sg_decl_fp);
	fputs("\n", sg_decl_fp);
}

void	copy_code2_code()
{
	assert( sg_code2_fp );

	append_file_by_file(sg_code_fp, sg_code2_fp);
}

void	gen_func_head(symbol *func)
{
	assert( func);

	if ( !IS_FUNCTION(func) )
	{
		yyerror("not function in gen_func_head()");
		user_exit(1);
	}
	// gen code in code file
	if ( IS_MAIN_FUNC(func) )
	{
		// is main function
		// func	proc	near
		sprintf(sg_buf, "%s\tproc\tfar", func->rname);
		write_to_code(sg_buf);
		// start:
		sprintf(sg_buf, "%s:", _START_LABEL_NAME);
		write_to_code(sg_buf);
		// push ds
		// xor ax,ax
		// push ax
		// mov	ax, _data
		// mov	ds, ax
		write_to_code("\tpush\tds");
		write_to_code("\txor\tax,\tax");
		write_to_code("\tpush\tax");
		sprintf(sg_buf1,"\tmov\tax,\t%s", _DATA_SEG_NAME);
		// to del %s at tail of _DATA_SEG_NAME
		sprintf(sg_buf,sg_buf1, "");                   
		write_to_code(sg_buf);
		write_to_code("\tmov\tds,\tax");
		// set main function exist flag
		sg_is_main_func_exist = 1;
	}
	else
	{
		// func	proc	near
		sprintf(sg_buf, "%s\tproc\tnear", func->rname);
		write_to_code(sg_buf);
	}

	// push	bp;
	write_to_code("\tpush\tbp");
	// mov	bp, sp
	write_to_code("\tmov\tbp,\tsp");
	// sub sp, offset
	if ( func->offset )
	{
		sprintf(sg_buf, "\tsub\tsp,\t%d", func->offset);
		write_to_code(sg_buf);
	}
}

void	gen_func_end(symbol *func)
{
	assert( func);

	if ( !IS_FUNCTION(func) )
	{
		yyerror("not function in gen_func_end()");
		user_exit(1);
	}
	// gen code in code file
	// mov	sp, bp
	write_to_code("\tmov\tsp,\tbp");
	// pop	bp
	write_to_code("\tpop\tbp");
	// ret
	write_to_code("\tret");
	// func	endp
	sprintf(sg_buf, "%s\tendp", func->rname);
	write_to_code(sg_buf);
}

// not gen the code in code2 , so donot use these function to gen code in code temp files
// like function head and end
void	gen_cmp(char *p1, char *p2)
{
	assert(p1);
	assert(p2);

	sprintf(sg_buf, "\tcmp\t%s,\t%s", p1, p2);
	write_to_code2(sg_buf);
}

void	gen_cmp_cl(char *p1, int num)
{
	assert(p1);

	sprintf(sg_buf, "\tcmp\t%s,\t%d", p1, num);
	write_to_code2(sg_buf);
}

void	gen_mov(char *p1, char *p2)
{
	assert(p1);
	assert(p2);

	sprintf(sg_buf, "\tmov\t%s,\t%s", p1, p2);
	write_to_code2(sg_buf);
}

void	gen_mov_cl(char *p1, int num)
{
	assert(p1);

	sprintf(sg_buf, "\tmov\t%s,\t%d", p1, num);
	write_to_code2(sg_buf);
}

void	gen_lea(char *p1, char *p2)
{
	assert(p1);
	assert(p2);

	sprintf(sg_buf, "\tlea\t%s,\t%s", p1, p2);
	write_to_code2(sg_buf);
}

void	gen_add(char *p1, char *p2)
{
	assert(p1);
	assert(p2);

	sprintf(sg_buf, "\tadd\t%s,\t%s", p1, p2);
	write_to_code2(sg_buf);
}

void	gen_add_cl(char *p1, int num)
{
	assert(p1);

	sprintf(sg_buf, "\tadd\t%s,\t%d", p1, num);
	write_to_code2(sg_buf);
}

void	gen_sub(char *p1, char *p2)
{
	assert(p1);
	assert(p2);

	sprintf(sg_buf, "\tsub\t%s,\t%s", p1, p2);
	write_to_code2(sg_buf);
}

void	gen_sub_cl(char *p1, int num)
{
	assert(p1);

	sprintf(sg_buf, "\tsub\t%s,\t%d", p1, num);
	write_to_code2(sg_buf);
}

void	gen_xor(char *p1, char *p2)
{
	assert(p1);
	assert(p2);

	sprintf(sg_buf, "\txor\t%s,\t%s", p1, p2);
	write_to_code2(sg_buf);
}

void	gen_or(char *p1, char *p2)
{
	assert(p1);
	assert(p2);

	sprintf(sg_buf, "\tor\t%s,\t%s", p1, p2);
	write_to_code2(sg_buf);
}

void	gen_and(char *p1, char *p2)
{
	assert(p1);
	assert(p2);

	sprintf(sg_buf, "\tand\t%s,\t%s", p1, p2);
	write_to_code2(sg_buf);
}

void	gen_shl(char *p1, char *p2)
{
	assert(p1);
	assert(p2);

	sprintf(sg_buf, "\tshl\t%s,\t%s", p1, p2);
	write_to_code2(sg_buf);
}

void	gen_shr(char *p1, char *p2)
{
	assert(p1);
	assert(p2);

	sprintf(sg_buf, "\tshr\t%s,\t%s", p1, p2);
	write_to_code2(sg_buf);
}

void	gen_neg(char *p)
{
	assert(p);

	sprintf(sg_buf, "\tneg\t%s", p);
	write_to_code2(sg_buf);
}

void	gen_inc(char *p)
{
	assert(p);

	sprintf(sg_buf, "\tinc\t%s", p);
	write_to_code2(sg_buf);
}

void	gen_dec(char *p)
{
	assert(p);

	sprintf(sg_buf, "\tdec\t%s", p);
	write_to_code2(sg_buf);
}

void	gen_call(char *name)
{
	assert(name);

	sprintf(sg_buf, "\tcall\t%s", name);
	write_to_code2(sg_buf);
}

void	gen_not(char *p)
{
	assert(p);

	sprintf(sg_buf, "\tnot\t%s", p);
	write_to_code2(sg_buf);
}

void	gen_mul(char *p)
{
	assert(p);

	sprintf(sg_buf, "\timul\t%s", p);
	write_to_code2(sg_buf);
}

void	gen_div(char *p)
{
	assert(p);

	sprintf(sg_buf, "\tidiv\t%s", p);
	write_to_code2(sg_buf);
}

void	gen_label(char *lb)
{
	assert(lb);

	sprintf(sg_buf, "%s:", lb);
	write_to_code2(sg_buf);
}

void	gen_jump(char *jp, char *lb)
{
	assert(jp);
	assert(lb);

	sprintf(sg_buf, "\t%s\t%s", jp, lb);
	write_to_code2(sg_buf);
}

void	gen_push_reg(char *reg)
{
	assert(reg);

	sprintf(sg_buf, "\tpush\t%s", reg);
	write_to_code2(sg_buf);
}

void	gen_pop_reg(char *reg)
{
	assert(reg);

	sprintf(sg_buf, "\tpop\t%s", reg);
	write_to_code2(sg_buf);
}

// gen globe value
void	gen_globe_var_list(symbol *p)
{
	while (p)
	{
		if ( !IS_VAR(p) )
		// not var
			goto	lab_next;

		// gen var define
		// ? db ?
		switch(p->NOUN)
		{
		case	SPEC_CHAR:
			strcpy(sg_buf1, "\t%s\tdb\t");
			break;
		case	SPEC_FLOAT:	// just as int
		case	SPEC_DOUBLE:// just as int
		case	SPEC_INT:
			strcpy(sg_buf1, "\t%s\tdw\t");
			break;
		default:
			yyerror("can't gen globe var in gen_gb_var()");
			user_exit(1);
		}
		if ( IS_ARRAY(p) )
		{
			// var db 100 dup(?)
			strcat(sg_buf1, "%d dup(?)");
			sprintf(sg_buf, sg_buf1, p->rname, p->num_ele);
		}
		else if ( IS_ASSIGN(p) )
		{
			// var db value
			// initalizer in the ->args
			assert(p->args);
			strcat(sg_buf1, "%d");
			sprintf(sg_buf, sg_buf1, p->rname, get_sym_value(p->args));
			// delete the initalizer symbol
			// and clear the ->assign flag
			del_symbol(p->args);
			p->args = NULL;
			p->is_assign = 0;
		}
		else
		{
			// var db ?
			strcat(sg_buf1, "?");
			sprintf(sg_buf, sg_buf1, p->rname);
		}
		write_to_data(sg_buf);
lab_next:
		p = p->next;
	}
}

// gen string code
void	gen_string_tab(const_string *head)
{
	while (head)
	{
		sprintf(sg_buf, "\t%s\tdb\t%s, 0", head->rname, head->str);
		write_to_data(sg_buf);

		head = head->next;
	}
}

// gen data segment head
void	gen_data_segment_head()
{
	// _data	segment
	sprintf(sg_buf, _DATA_SEG_NAME, "segment");
	write_to_data(sg_buf);
}

// gen data segment end
void	gen_data_segment_end()
{
	// gen data end
	sprintf(sg_buf, _DATA_SEG_NAME, "ends");
	write_to_data(sg_buf);
}

// gen code segment start & end
void	gen_code_segment_head()
{
	// _text	segment
	sprintf(sg_buf, _CODE_SEG_NAME, "segment");
	write_to_code(sg_buf);
	// assume	cs....
	strcpy(sg_buf1, "\tassume cs:");
	strcat(sg_buf1, _CODE_SEG_NAME);
	strcat(sg_buf1, "ds:");
	strcat(sg_buf1, _DATA_SEG_NAME);
	sprintf(sg_buf, sg_buf1, ",","");
	write_to_code(sg_buf);
}

void	gen_code_segment_end()
{
	// _text	ends
	sprintf(sg_buf, _CODE_SEG_NAME, "ends");
	write_to_code(sg_buf);
	// end	start
	sprintf(sg_buf, "\tend\t%s", _START_LABEL_NAME);
	write_to_code(sg_buf);
}

// is main function exist
int		is_main_function_exist()
{
	return	sg_is_main_func_exist;
}

// get match regist xx, or xl
char	*get_match_reg(symbol *p, char *reg)
{
	static	char buf[10];

	strcpy(buf, reg);

	switch(p->NOUN)
	{
	case	SPEC_CHAR:
		buf[1] = 'l';
		break;
	case	SPEC_FLOAT:	// just as int
	case	SPEC_DOUBLE:// just as int
	case	SPEC_INT:
		buf[1] = 'x';
		break;
	default:
		yyerror("can't match register in get_match_reg()");
		user_exit(1);
	}

	// not reach
	return	buf;
}

// clear reg high position if needed
void	clear_reg_high_if_needed(symbol *p,char *reg)
{
	static	char buf[10];

	assert(p);
	
	strcpy(buf, reg);
	buf[1] = 'l';

	if ( !strcmp(get_match_reg(p, reg), buf) )
	{
		buf[1] = 'h';
		gen_mov_cl(buf, 0);
	}
}

// get a not dup label for gen code
char	*get_a_label()
{
	static	int		label_count = 0;
	static	char	buf[LABEL_LEN];

	sprintf(buf, _GB_LABEL_NAME, label_count++);
	return	buf;
}

// gen mov	not pushed cl or var to reg
void	gen_mov_nopush_to_reg(symbol *p, char *reg)
{
	assert(p);
	assert( !IS_PUSHED(p) );

	if ( IS_CL(p) )
	{
		// mov reg, value
		gen_mov_cl(get_match_reg(p, reg), get_sym_value(p));
	}
	else
	{
		if ( IS_ARRAY_HAS_INDEX(p) )
		{
			gen_get_array_element(p);
			// set rvalue flag
			p->is_rvalue = 1;
		}
		// mov reg, var
		gen_mov(get_match_reg(p, reg), p->rname);
	}

	clear_reg_high_if_needed(p, reg);
}

// mov value (pushed or no pushed) to reg
void	gen_mov_value_to_reg(symbol *p,char *reg)
{
	assert(p);

	if ( !IS_PUSHED(p) )
		gen_mov_nopush_to_reg(p, reg);
	else
		gen_pop_reg(reg);
}

// get two operator , at least one is not cl
// return value is the attribute that be translate
symbol	*gen_get_two_op_not_cl(symbol *p1, symbol *p2, char *reg1, char *reg2)
{
	assert(p1);
	assert(p2);
	assert( !IS_CL(p1) || !IS_CL(p2) );

	gen_mov_value_to_reg(p2, reg2);
	gen_mov_value_to_reg(p1, reg1);

	if ( IS_CL(p1) )
	{
		del_symbol(p1);
		return	p2;
	}

	del_symbol(p2);
	return	p1;
}

// gen code that mov reg to a var address
void	gen_mov_reg_to_var(char *reg, symbol *p)
{
	assert(p);
	//forarray can use this after gen become value
//	assert( IS_VAR(p) );

	// mov	p,	al
	// or
	// mov	p,	ax
	gen_mov(p->rname, get_match_reg(p, reg));
}

// gen get array element code
void	gen_get_array_element(symbol *a)
{
	assert(a);
	assert(a->args);
	assert( IS_ARRAY(a) );

	// protected cx value
	// mov	si,	cx
	gen_mov("si", "cx");
	// mov	cx,	index
	gen_mov_value_to_reg(a->args, "cx");
	// shl	cx,	1 (if is int)
	if ( a->NOUN != SPEC_CHAR )
		write_to_code2("\tshl\tcx,\t1");
	// lea	bx, $1 ( local var ) or mov	bx, $1 (argument)
	if ( IS_ARGUMENT(a) )
		// mov	bx, $1
		gen_mov("bx", a->rname);
	else
		// lea	bx, $1
		gen_lea("bx", a->rname);

	// add	bx,	cx
	gen_add("bx", "cx");

	// restore cx value
	// mov	cx, si
	gen_mov("cx", "si");
	// assign ->rname word ptr [bx] or byte ptr [bx]
	if ( a->NOUN == SPEC_CHAR )
	{
		strcpy(a->rname, "byte ptr [bx]");
	}
	else
	{
		strcpy(a->rname, "word ptr [bx]");
	}
	del_symbol(a->args);
	a->args = NULL;
}

// gen push argument code
void	gen_push_argument(symbol *a)
{
	assert(a);

	// push the argument
	if ( IS_ARRAY(a) && !IS_RVALUE(a) && !IS_ARRAY_HAS_INDEX(a) )
	{
		// push array address
		// 2 status
		if ( IS_ARGUMENT(a) )
			// mov	ax,	address
			gen_mov("ax", a->rname);
		else 
			// local var
			// lea	ax, a
			gen_lea("ax", a->rname);
	}
	else
	{
		gen_mov_value_to_reg(a, "ax");
	}
	gen_push_reg("ax");
}

// gen assign init
void	gen_var_assign_init(symbol *v)
{
	while (v)
	{
		if ( IS_VAR(v) && !IS_GLOBE(v) && IS_ASSIGN(v) )
		{
			// gen assign code
			// initalizer in the ->args
			assert(v->args);
			gen_mov_cl(v->rname, get_sym_value(v->args));
			// delete the initalizer symbol
			// and clear the ->assign flag
			del_symbol(v->args);
			v->args = NULL;
			v->is_assign = 0;
		}

		v = v->next;
	}
}

// gen extern file declaration
void	gen_extern_func(symbol *func)
{
	assert(func);
	assert(IS_FUNC_DECL(func));
	assert(func->IS_EXTERN);
	
	sprintf(sg_buf, "extrn\t%s\t\t:proc", func->rname);
	write_to_decl(sg_buf);
}

// remove all tmp file
void	remove_all_tmp()
{
	if ( sg_code2_fp )
	{
		fclose( sg_code2_fp );
		sg_code2_fp  = NULL;
	}

	if ( sg_code_fp )
	{
		fclose( sg_code_fp );
		sg_code_fp  = NULL;
	}

	if ( sg_data_fp )
	{
		fclose( sg_data_fp );
		sg_data_fp  = NULL;
	}

	if ( sg_decl_fp )
	{
		fclose( sg_decl_fp );
		sg_decl_fp  = NULL;
	}

	remove(_TMP_DECL_FILE_NAME);
	remove(_TMP_DATA_FILE_NAME);
	remove(_TMP_CODE_FILE_NAME);
	remove(_TMP_CODE2_FILE_NAME);
}

void	InitGenCode()
{
	sg_decl_fp = fopen(_TMP_DECL_FILE_NAME,"w+");
	sg_data_fp = fopen(_TMP_DATA_FILE_NAME,"w+");
	sg_code_fp = fopen(_TMP_CODE_FILE_NAME,"w+");
	if (!sg_decl_fp || !sg_data_fp || !sg_code_fp)
	{
		yyerror("error in open tmp file");
		user_exit(1);
	}
	// assume main function not exist
	sg_is_main_func_exist = 0;
}

void	DestoryGenCode(char *out_name)
{
	FILE	*fp;

	assert(sg_decl_fp);
	assert(sg_data_fp);
	assert(sg_code_fp);

	fp = fopen(out_name,"w");
	if ( !fp )
	{
		parse_error("can't open output file:", out_name);
		user_exit(1);
	}

	append_file_by_file(fp, sg_decl_fp);
	fputs("\n", fp);
	append_file_by_file(fp, sg_data_fp);
	fputs("\n", fp);
	append_file_by_file(fp, sg_code_fp);
	fclose( fp );

	remove_all_tmp();
}



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -