📄 code.cpp
字号:
// This file do the most terrible job: code generation
// It's really a challenging job, you must design carefully
// all the time
//
// Written by bood, boodweb@163.com, http://boodweb.126.com
// 2004-08-06
// Now generating the assemble codes of CPU above pentium 386
// and with a simple I/O library & an assembler like MASM/TASM
// an executable file is avaiable
// bood, 2004-08-13
// Generate code for initializations
//
// Bug fixed:
// SP/BP is used instead of ESP/EBP, for dos mode of windows,
// operators like POP/PUSH are with SP/BP, use of ESP can cause
// overflow exception
// by bood, 2005-01-17
// Generate external symbol declarations for function declarations
// without definitions, so that multi-file compilation supported
// Function 'genExternSymbol' does the main job
//
// by bood, 2005-03-13
#pragma warning(disable:4786)
#include <string>
#include <sstream>
#include "global.h"
#include "symtable.h"
#include "code.h"
#include "util.h"
#include "analyze.h"
// Define the registers
#define STACK 100
#define NONE -1
#define EAX 0
#define EBX 1
#define ECX 2
#define EDX 3
#define SP 4
#define BP 5
#define EBP 6
#define CS 7
#define DS 8
#define ES 9
#define SS 10
using namespace std;
static string regs[]={"EAX","EBX","ECX","EDX","SP","BP","EBP",
"CS","DS","ES","SS"};
static int labelNumber = 0; //for jump use
//static string FuncName;
void emitComment(const string &comment, int tabs = 0)
{
if(tabs) fcode<<'\t';
fcode<<';'<<comment<<'\n';
}
// emit a jump label: L<number>
string emitLabel(int tabs = 0)
{
ostringstream os;
os<<'L'<<labelNumber++;
return os.str();
}
// just emit a line with anything, this can simplify
// the calling procedure
void emitLine(const string &code, int tabs = 0)
{
if(tabs) fcode<<'\t';
fcode<<code<<'\n';
}
// just emit a line of code with anything, just like
// emitLine except this keeps a tab in front by default
void emitCode(const string &code, int tabs = 1)
{
if(tabs) fcode<<'\t';
fcode<<code<<'\n';
}
// emit the global variable declaration
void emitDeclare(const string &name, int space, int tabs = 1)
{
if(tabs) fcode<<'\t';
fcode<<'_'<<name<<"\tdd\t"<<space<<" dup(0)\n";
}
// emit an line of code with no operand
void emitNoOprand(const string &op, int tabs = 1)
{
if(tabs) fcode<<'\t';
fcode<<op<<'\n';
}
// emit an line of code with one operand
void emitOneOprand(const string &op, const string &imm, int tabs = 1)
{
if(tabs) fcode<<'\t';
fcode<<op<<'\t'
<<imm<<'\n';
}
// emit an line of code with two operands
void emitTwoOprand(const string &op,
const string &op1, const string &op2,
int tabs = 1)
{
if(tabs) fcode<<'\t';
fcode<<op<<'\t'
<<op1<<','
<<op2<<'\n';
}
// emit a memory address like [base+index*scale+disp]
string memAddr(int base, int index, int scale, const string& disp = "")
{
ostringstream os;
os<<'[';
if(base != NONE) os<<regs[base];
if(index != NONE) {
if(base != NONE) os<<'+';
os<<regs[index];
}
if(scale != 0) {os<<'*';os<<scale;}
if(!disp.empty()) {os<<'+'<<disp;}
os<<']';
//if(mem=="[]") GenError("Empty memory address generated.");
return os.str();
}
// same as above except the last parameter
string memAddr(int base, int index, int scale, int disp = 0)
{
ostringstream os;
os<<'[';
if(base != NONE) os<<regs[base];
if(index != NONE) {
if(base != NONE) os<<'+';
os<<regs[index];
}
if(scale != 0) {os<<'*';os<<scale;}
if(disp != 0) {os<<'+'<<disp;}
os<<']';
return os.str();
}
// emit code for temp result
// result is pre-saved in EAX
void emitTemp(int tmpR)
{
if(tmpR==STACK){
emitCode("PUSH EAX");
}
else if(tmpR==NONE) return;
else if(tmpR!=EAX){
emitTwoOprand("MOV", regs[tmpR], regs[EAX]);
}
return;
}
//emit code for I/O of variable
//loc(fp): variable replacement
//bAddr: get address OR get value
// 1: get address
// 0: get value
//Address or value is returned in EAX
void emitRefer(SymbolRecord *s, int bAddr)
{
switch(s->symboltype){
// ARRAYADDR_SYMBOL represents for a array symbol
// needs an indirected access(i.e. as parameter)
case ARRAYADDR_SYMBOL:
emitTwoOprand("MOV", regs[EAX],
memAddr(BP, NONE, 0, s->location));
emitTwoOprand(bAddr?"LEA":"MOV", regs[EAX],
memAddr(EAX, EBX, Int_Bytes, 0));
break;
// Arrays that can be accessed directly
case ARRAY_SYMBOL:
// Global variables need a different way
if(s->nestlevel == 0){
emitTwoOprand(bAddr?"LEA":"MOV", regs[EAX],
memAddr(NONE, EBX, Int_Bytes, "OFFSET _"+s->name));
}
else{
emitTwoOprand(bAddr?"LEA":"MOV", regs[EAX],
memAddr(EBP, EBX, Int_Bytes, s->location));
}
break;
// Regular variables
case VAR_SYMBOL:
if(s->nestlevel == 0){
emitTwoOprand(bAddr?"LEA":"MOV", regs[EAX],
'_'+s->name);
}
else{
emitTwoOprand(bAddr?"LEA":"MOV", regs[EAX],
memAddr(BP, NONE, 0, s->location));
}
break;
}
}
//
// Core code for code generation
//
// tempR: Register for temp result
// 0-6: R0-R6
// 8: On stack
// -1: Abandon
void genCodePart(TreeNode *t,int tempR)
{
TreeNode *ttemp;
string label,label2;
SymbolRecord *s;
ostringstream os;
int i;
if (t != NULL)
{
switch(t->kind)
{
case DECLAR:
if(t->childkind.declarK==FUNC_DEFINE)
{
//FuncName=t->name;
s=st_lookup(t->name);
emitComment(string("Function name: ")+t->name);
emitLine('_'+t->name+" PROC");
emitCode("PUSH BP"); //save the old-frame-pointer(ofp)
emitCode("MOV BP,SP"); //set new fp
if(s->localAlloc > 0){ //reserve for local variables
os<<s->localAlloc;
emitTwoOprand("SUB", regs[SP], os.str());
os.str()="";
}
st_addon(t->pBucketList); //add on corresponding ST
genCodePart(t->pChild[1], NONE); //initialization part
genCodePart(t->pChild[2], NONE); //statement part
st_takeoff(); //take it off
emitCode("MOV SP,BP");
emitCode("MOV EAX,0"); //return 0 by default
emitCode("POP BP"); //fp=ofp
emitNoOprand("RET"); //return
emitLine('_'+t->name+" ENDP");
//FuncName="";
nestlevel=0;
}
// generate code for initialization
else if(t->childkind.declarK==VAR_DECLAR_LIST) {
ttemp = t->pChild[0];
while(ttemp!=NULL) {
genCodePart(ttemp->pChild[0], NONE);
ttemp = ttemp->pNext;
}
}
break;
case CSTMT:
emitComment("Compound statement start");
st_addon(t->pBucketList); //add on corresponding ST
genCodePart(t->pChild[0], NONE); //deal with possible initialization
genCodePart(t->pChild[1], NONE);
st_takeoff(); //take it of
emitComment("Compound statement end");
break;
case OP:
genCodePart(t->pChild[0], STACK); //oprand1 save to stack
genCodePart(t->pChild[1], EBX); //oprand2 save to EBX
emitCode("POP EAX"); //get oprand1
switch(t->tokenT)
{
case PLUS:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -