📄 ex86asm.cpp
字号:
// Ex86asm.cpp: implementation of the Ex86asm class.
//
//////////////////////////////////////////////////////////////////////
#include "Ex86asm.h"
#include "stdarg.h"
#include "scope.h"
#include "type.h"
#include "decllist.h"
#include "errors.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
void PraseString(const char * s,char *t)
{
int i,j,len;
len=strlen(s);
for(i=0,j=0;i<len-1;i++,j++)
{
if(s[i]!='\\')
{
t[j]=s[i];
}
else
{
if(s[i+1]=='t')
{
t[j]='\t';
i++;
}
else if(s[i+1]=='\\')
{
t[j]='\\';
i++;
}
else if(s[i+1]=='n')
{
t[j]='\r';
t[j+1]='\n';
j++;
i++;
}
else if(s[i+1]=='r')
{
t[j]='\r';
t[j+1]='\n';
j++;
i++;
}
else if(s[i+1]=='"')
{
t[j]='"';
i++;
}
else if(s[i+1]<='9' && s[i+1]>='0')
{
if(s[i+2]<='9' && s[i+2]>='0')
{
if(s[i+3]<='9' && s[i+3]>='0')
{
char buf[4]={s[i+1],s[i+2],s[i+3],'\0'};
t[j]=(char)atoi(buf);
i+=3;
}
else
{
char buf1[3]={s[i+1],s[i+2],'\0'};
t[j]=(char)atoi(buf1);
i+=2;
}
}
else
{
t[j]=s[i+1]-'0';
i++;
}
if(t[j]=='\0')
j--;
}
else
{
j--;
}
}
}
t[j]='\0';
}
Ex86asm::Ex86asm()
{
nStringCount=0;
}
Ex86asm::~Ex86asm()
{
}
void Ex86asm::EmitPreamble()
{
FILE * fp;
char buf[1024];
fp=fopen("lib32.asm","r");
if(fp==NULL)
{
printf("Fail to find the standard libray of PC ASM");
exit(0);
}
while(!feof(fp))
{
fgets(buf,1024,fp);
printf("%s",buf);
}
}
void Ex86asm::Emit(const char *fmt, ...)
{
va_list args;
char buf[1024];
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);
if (buf[strlen(buf) - 1] != ':') printf("\t"); // don't tab in labels
if (buf[0] != ';') printf(" "); // outdent comments a little
printf("%s", buf);
if (buf[strlen(buf)-1] != '\n') printf("\n"); // end with a newline
}
void Ex86asm::EmitACall(Declaration *dst, Declaration *fn, int bytes)
{
StoreVarInEAX(fn);
EmitOp1("CALL","EAX","Call the function");
if(dst!=NULL)
StoreEAXInVar(dst);
}
void Ex86asm::EmitLCall(Declaration *dst, const char *label, int bytes)
{
EmitOp1("CALL",label,"Call the function");
if(dst!=NULL)
StoreEAXInVar(dst);
}
void Ex86asm::EmitArg(Declaration *arg)
{
StoreVarInEAX(arg);
EmitOp1("PUSH","EAX","Push this parameter to stack");
}
void Ex86asm::EmitBeginFunction(Declaration * fun,int frameSize)
{
Assert(frameSize >= 0);
char buf[32];
Emit(";--------------------------------------------");
Emit("; The start of function %s",fun->GetFunctionLabel());
Emit(";--------------------------------------------");
printf("\n.code\n%s proc \n",fun->Getx86FunctionLabel());
EmitOp1("PUSH","EBP","Save old EBP in stack");
EmitOp2("MOV","EBP","ESP","EBP <==== current ESP");
sprintf(buf,"%d",frameSize);
EmitOp2("SUB","ESP",buf,"Make room for local and temp variables");
}
void Ex86asm::EmitEndFunction(Declaration * fun)
{
char buf[32];
EmitOp2("MOV","ESP","EBP","Restroe ESP");
EmitOp1("POP","EBP","Restore EBP");
if(fun->IsGlobal()||!strcmp(fun->GetName(),"New"))
sprintf(buf,"%d",fun->GetType()->GetFnFormals()->NumElements()*4);
else
sprintf(buf,"%d",fun->GetType()->GetFnFormals()->NumElements()*4+4);
EmitOp1("RET",buf,"Return from function and clean the stack that hold by parameters");
printf("%s ENDP\n",fun->Getx86FunctionLabel() );
}
void Ex86asm::StoreVarInEAX(Declaration *decl)
{
Scope * s;
s=decl->GetScope();
Assert(!s->IsClassScope());
char buf[128];
if(s->IsGlobalScope())
{
sprintf(buf,"_%s",decl->GetName());
EmitOp2("MOV","EAX",buf,"EAX <==== Global variable",decl->GetName());
}
else
{
int off=decl->GetOffset();
if(off>=0)
sprintf(buf,"[EBP+%d]",off);
else
sprintf(buf,"[EBP-%d]",-off);
EmitOp2("MOV","EAX",buf,"EAX <==== Local variable",decl->GetName());
}
}
void Ex86asm::StoreVarInEDX(Declaration *decl)
{
Scope * s;
s=decl->GetScope();
Assert(!s->IsClassScope());
char buf[128];
if(s->IsGlobalScope())
{
sprintf(buf,"_%s",decl->GetName());
EmitOp2("MOV","EDX",buf,"EDX <==== Global variable",decl->GetName());
}
else
{
int off=decl->GetOffset();
if(off>=0)
sprintf(buf,"[EBP+%d]",off);
else
sprintf(buf,"[EBP-%d]",-off);
EmitOp2("MOV","EDX",buf,"EDX <==== Local variable",decl->GetName());
}
}
void Ex86asm::StoreEAXInVar(Declaration *decl)
{
Scope * s;
s=decl->GetScope();
Assert(!s->IsClassScope());
char buf[32];
if(s->IsGlobalScope())
{
sprintf(buf,"_%s",decl->GetName());
EmitOp2("MOV",buf,"EAX","EAX ====> Global variable",decl->GetName());
}
else
{
int off=decl->GetOffset();
if(off>=0)
sprintf(buf,"[EBP+%d]",off);
else
sprintf(buf,"[EBP-%d]",-off);
EmitOp2("MOV",buf,"EAX","EAX ====> Local variable",decl->GetName());
}
}
void Ex86asm::StoreEDXInVar(Declaration *decl)
{
Scope * s;
s=decl->GetScope();
Assert(!s->IsClassScope());
char buf[32];
if(s->IsGlobalScope())
{
sprintf(buf,"_%s",decl->GetName());
EmitOp2("MOV",buf,"EDX","EDX ====> Global variable",decl->GetName());
}
else
{
int off=decl->GetOffset();
if(off>=0)
sprintf(buf,"[EBP+%d]",off);
else
sprintf(buf,"[EBP-%d]",-off);
EmitOp2("MOV",buf,"EDX","EDX ====> Local variable",decl->GetName());
}
}
void Ex86asm::EmitBinaryOp(Tac::OpCode code, Declaration *dst,
Declaration *op1, Declaration *op2)
{
StoreVarInEAX(op1);
StoreVarInEDX(op2);
//Add, Sub, Mul, Div, Mod, Eq, Less, And, Or
switch(code)
{
case Tac::Add:
EmitOp2("ADD","EAX","EDX","Add them:)");
break;
case Tac::Sub:
EmitOp2("SUB","EAX","EDX","Sub them:)");
break;
case Tac::Mul:
EmitOp2("MOV","ECX","EDX","Move the multiplier to ECX");
EmitOp2("SUB","EDX","EDX","Clean EDX");
EmitOp1("IMUL","ECX","Multiply EAX by ECX,and the result stored in EDX:EAX");
break;
case Tac::Div:
EmitOp2("MOV","ECX","EDX","Move the divider to ECX");
EmitOp2("SUB","EDX","EDX","Clean EDX");
EmitOp1("IDIV","ECX","Divide EDX:EAX by ECX,and the result stored in EAX");
break;
case Tac::Mod:
EmitOp2("MOV","ECX","EDX","Move the devider to ECX");
EmitOp2("SUB","EDX","EDX","Clean EDX");
EmitOp1("IDIV","ECX","Divide EDX:EAX by ECX");
EmitOp2("MOV","EAX","EDX","Move the arithmetical compliment in EDX to EAX");
break;
case Tac::Eq:
EmitOp2("MOV","EBX","EAX","Move OP1 to EBX");
EmitOp2("SUB","EAX","EAX","Clean EAX");
EmitOp2("SUB","EBX","EDX","Compare the OP1 in EBX and the OP2 in EDX");
EmitOp0("LAHF","Load flag to AH");
EmitOp2("AND","AH","40H","And AH with 40H");
EmitOp2("SHR","EAX","14","Shift the result to the lowest bit of EAX");
break;
case Tac::Less:
EmitOp2("SUB","EAX","EDX","Compare the OP1 in EAX and the OP2 in EDX, if OP1 < OP2 then the highest bit of result in EAX should be 1,or else be 0");
EmitOp2("AND","EAX","80000000H","And ah with 80000000H");
EmitOp2("ROL","EAX","1","Shift the result bit to the lowest bit of EAX");
break;
case Tac::And:
EmitOp2("AND","EAX","EDX","And them :)");
break;
case Tac::Or:
EmitOp2("OR","EAX","EDX","Or them :)");
break;
}
StoreEAXInVar(dst);
}
void Ex86asm::EmitGoto(const char *label)
{
char buf[256];
sprintf(buf,"_@@%s",label);
EmitOp1("JMP",buf,"Uncondition jump");
}
void Ex86asm::EmitIfZ(Declaration *test, const char *label)
{
char buf[256];
sprintf(buf,"_@@%s",label);
StoreVarInEAX(test);
EmitOp2("CMP","EAX","0","Test the condition");
EmitOp1("JZ",buf,"Jump when the condition is zero");
}
void Ex86asm::EmitLabel(const char *label)
{
Emit("_@@%s:", label);
}
void Ex86asm::EmitLoad(Declaration *dst, Declaration *reference, int offset)
{
StoreVarInEAX(reference);
if(offset!=0)
{
char buf[32];
sprintf(buf,"%d",offset);
EmitOp2("ADD","EAX",buf,"Add the offset");
}
EmitOp2("MOV","EDX","[EAX]","Load the valiable to EDX");
StoreEDXInVar(dst);
}
void Ex86asm::EmitLoadConstant(Declaration *dst, int val)
{
char buf[32];
sprintf(buf,"%d",val);
EmitOp2("MOV","EAX",buf,"Load constant to EAX");
StoreEAXInVar(dst);
}
void Ex86asm::EmitLoadStringConstant(Declaration *dst, const char *str)
{
static int strNum = 1;
char label[32];
char buf[64];
char * sptr;
if(!strcmp(str,err_arr_out_of_bounds)||
!strcmp(str,"\"Decaf runtime error: Array subscript out of bounds\n\""))
{
EmitOp2("MOV","EAX","offset _@strRTErrWrongIndex");
StoreEAXInVar(dst);
}
else if(!strcmp(str,err_arr_neg_size)||
!strcmp(str,"\"Decaf runtime error: Cannot create negative-sized array\n\""))
{
EmitOp2("MOV","EAX","offset _@strRTErrWrongSize");
StoreEAXInVar(dst);
}
else
{
sprintf(label,"_@StringL@%d",nStringCount);
nStringCount++;
sptr=new char [strlen(str)+1];
PraseString(str+1,sptr);
Emit("; String constant for %s",str);
printf("\n.data\n %s db ",label);
int i,c=strlen(sptr);
for(i=0;i<c;i++)
{
if(i==0)
printf("%d",(int) sptr[i]);
else if(i%16==0)
printf("\n\t\tdb %d",(int) sptr[i]);
else
printf(",%d",(int) sptr[i]);
}
delete []sptr;
printf(",0\n");
printf("\n.code\n");
sprintf(buf,"Offset %s",label);
EmitOp2("MOV","EAX",buf,"Load the string constant to EAX");
StoreEAXInVar(dst);
}
}
void Ex86asm::EmitStore(Declaration *reference, Declaration *value, int offset)
{
StoreVarInEDX(value);
StoreVarInEAX(reference);
if(offset!=0)
{
char buf[32];
sprintf(buf,"%d",offset);
EmitOp2("Add","EAX",buf);
}
EmitOp2("MOV","[EAX]","EDX","Store EDX back to memory");
}
void Ex86asm::EmitVTable(const char *label, DeclList *methods)
{
int i,c=methods->NumElements();
printf("\n.data\n");
for(i=0;i<c;i++)
{
if(i==0)
printf("_%s",label);
Emit("\tdd offset %s",methods->Nth(i)->Getx86FunctionLabel());
}
if(c==0)
{
if(i==0)
printf("_%s dd ?",label);
}
printf("\n.code\n");
}
void Ex86asm::EmitGVar(Declaration *decl)
{
printf("\n.data\n");
Emit("_%s dd ?",decl->GetName());
printf("\n.code\n");
}
void Ex86asm::EmitCopy(Declaration *dst, Declaration *src)
{
StoreVarInEAX(src);
StoreEAXInVar(dst);
}
void Ex86asm::EmitReturn(Declaration *returnVal)
{
if(returnVal!=NULL)
{
Emit(";Return value store in EAX");
StoreVarInEAX(returnVal);
}
}
void Ex86asm::EmitLoadLabel(Declaration *dst, const char *label)
{
char buf[1024];
sprintf(buf,"offset _%s", label);
EmitOp2("MOV","EAX",buf,"Load label to EAX");
StoreEAXInVar(dst);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -