📄 gencode.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 + -