?? codegen.cpp
字號:
/****************************************************/
/* 文件 codegen.cpp */
/* 說明 類PASCAL語言編譯器代碼生成程序 */
/* 主題 編譯器結構:原理和實例 */
/****************************************************/
#include "globals.h" /*定義全局類型和變量 */
#include "util.h" /*定義了一些實用函數*/
#include "string.h"
#include "codegen.h" /*定義了目標代碼生成文件的界面*/
#include "code.h" /*目標代碼生成用到的一些實用函數*/
/*標號地址表*/
LabelAddr *labelAddrT = NULL;
/*********函數聲明***********/
void codeGen(CodeFile *midcode, char * destcode);
void arithGen(CodeFile *midcode);
void operandGen(ArgRecord *arg);
void compaGen(CodeFile *midcode);
void aaddGen(CodeFile *midcode);
void readGen(CodeFile *midcode);
void writeGen(CodeFile *midcode);
void returnGen(CodeFile *midcode);
void assigGen(CodeFile *midcode);
void labelGen(CodeFile *midcode);
void jumpGen(CodeFile *midcode , int i);
void jump0Gen(CodeFile *midcode);
void valactGen(CodeFile *midcode);
void varactGen(CodeFile *midcode);
void callGen(CodeFile *midcode);
void pentryGen(CodeFile *midcode);
void endprocGen(CodeFile *midcode);
void FindAddr(ArgRecord *arg );
void FindSp(int varlevel);
void mentryGen(CodeFile *midcode,int savedLoc);
/************************************************/
/* 函數名 codeGen */
/* 功 能 目標代碼生成主函數 */
/* 說 明 該函數通過掃描中間代碼序列產生目標代碼*/
/* 文件第二個參數codefile為目標代碼文件名*/
/************************************************/
void codeGen(CodeFile *midcode, char * destcode)
{
/* 在內存中動態分配字串單元,返回單元指針s, *
* codefile為存儲目標代碼的代碼文件名 */
char * s = (char *)malloc(strlen(destcode)+7);
/* 將給定字串拷貝到s */
strcpy(s,"File: ");
/* 將目標代碼文件名的字串拼接到s */
strcat(s,destcode);
fprintf(listing,"\n\n");
getchar();
/* 生成代碼文件說明注釋,寫入代碼文件 */
emitComment("TINY Compilation to TM Code");
emitComment(s);
/* 生成標準先驅指令 */
emitComment("Standard prelude:");
/* 寫入單元設置指令,清空0地址單元中內容 */
emitRM("ST",ac,0,ac,"clear location 0");
/* 寫入注釋,先驅指令寫完 */
emitComment("End of standard prelude.");
/*為主程序入口留一個跳轉語句*/
int savedLoc = emitSkip(1);
/*循環處理各條中間代碼,調用相應得函數產生相應得目標代碼*/
while (midcode!=NULL)
{
switch(midcode->codeR.codekind)
{ /*運算處理,包括算術運算和關系運算*/
case ADD:
case SUB:
case MULT:
case DIV:
case LTC:
case EQC:
arithGen(midcode); break;
/*地址加運算*/
case AADD:
aaddGen(midcode); break;
/*輸入語句*/
case READC:
readGen(midcode); break;
/*輸出語句*/
case WRITEC:
writeGen(midcode); break;
/*返回語句*/
case RETURNC:
returnGen(midcode); break;
/*賦值語句*/
case ASSIG:
assigGen(midcode); break;
/*標號聲明語句*/
case LABEL:
case WHILESTART:
case ENDWHILE:
labelGen(midcode); break;
/*跳轉語句*/
case JUMP:
jumpGen(midcode,1); break;
/*條件跳轉語句*/
case JUMP0:
jump0Gen(midcode); break;
/*形實參結合語句:形參是值參*/
case VALACT:
valactGen(midcode); break;
/*形實參結合語句:形參是變參*/
case VARACT:
varactGen(midcode); break;
/*過程調用語句*/
case CALL:
callGen(midcode); break;
/*過程入口聲明*/
case PENTRY:
pentryGen(midcode); break;
/*過程出口聲明*/
case ENDPROC:
endprocGen(midcode); break;
/*主程序入口處理*/
case MENTRY:
mentryGen(midcode,savedLoc); break;
default : fprintf(listing , " midcode bug.\n");
}
midcode = midcode->next;
}
/*處理完主程序,退出AR*/
emitComment("<- end of main ");
/* 寫入注釋,標志文件執行的結束 */
emitComment("End of execution.");
/* 寫入停止指令,結束程序執行 */
emitRO("HALT",0,0,0,"");
}
/************************************************/
/* 函數名 arithGen */
/* 功 能 生成算術運算的目標代碼 */
/* 說 明 */
/************************************************/
void arithGen(CodeFile *midcode)
{
/* 如果代碼生成追蹤標志TraceCode為TRUE,寫入注釋,標注操作開始 */
if (TraceCode) emitComment("-> Op");
/*生成左操作數的目標代碼,值存在ac中*/
operandGen(midcode->codeR.arg1);
/* 暫存左操作數 */
emitRM("LDA",ac2,0,ac,"op: store left ");
/*生成右操作數的目標代碼,值存在ac中*/
operandGen(midcode->codeR.arg2);
/* 取出左操作數ac1*/
emitRM("LDA",ac1,0,ac2,"op: load left");
/*根據操作符,生成運算的目標代碼,ac中為計算結果*/
switch(midcode->codeR.codekind)
{ /*相加*/
case ADD: emitRO("ADD",ac,ac1,ac,"op +"); break;
/*相減*/
case SUB: emitRO("SUB",ac,ac1,ac,"op -"); break;
/*相乘*/
case MULT: emitRO("MUL",ac,ac1,ac,"op *"); break;
/*相除*/
case DIV: emitRO("DIV",ac,ac1,ac,"op /"); break;
/*小于*/
case LTC:
/* 寫入減指令,將(左-右)操作數相減,結果送累加器ac */
emitRO("SUB",ac,ac1,ac,"op <") ;
/* 寫入判斷跳轉指令,如果累加器ac的值小于0, *
* 則代碼指令指示器跳過兩條指令 */
emitRM("JLT",ac,2,pc,"br if true") ;
/* 寫入載入常量指令,將累加器ac賦值為0 */
emitRM("LDC",ac,0,0,"false case") ;
/* 寫入數值載入指令,代碼指令指示器pc跳過下一條指令 */
emitRM("LDA",pc,1,pc,"unconditional jmp") ;
/* 寫入載入常量指令,將累加器ac賦值為1 */
emitRM("LDC",ac,1,0,"true case") ;
break;
/*等于*/
case EQC:
/* 寫入減法指令,將左,右操作數相減,結果送累加器ac */
emitRO("SUB",ac,ac1,ac,"op ==") ;
/* 寫入判斷跳轉指令,如果累加器ac等于0, *
* 代碼指令指示器pc跳過兩條指令 */
emitRM("JEQ",ac,2,pc,"br if true");
/* 寫入載入常量指令,將累加器ac賦值為0 */
emitRM("LDC",ac,0,0,"false case") ;
/* 寫入數值載入指令,代碼指令指示器pc跳過一條指令 */
emitRM("LDA",pc,1,pc,"unconditional jmp") ;
/* 寫入載入常量指令,將累加器ac賦值為1 */
emitRM("LDC",ac,1,0,"true case") ;
break;
default : break;
}
/*后面要用ac,故保存ac*/
emitRM("LDA",ac2,0,ac,"op: store result ");
/*計算目的操作數的地址,存在ac中*/
FindAddr(midcode->codeR.arg3);
/*取出暫存的計算結果,存入ac1*/
emitRM("LDA",ac1,0,ac2,"op: load result");
/*計算結果存入目的操作數*/
emitRM("ST",ac1,0,ac, "");
/* 如果代碼生成追蹤標志TraceCode為TRUE,寫入注釋信息,標注操作結束 */
if (TraceCode) emitComment("<- Op") ;
}
/************************************************/
/* 函數名 operandGen */
/* 功 能 生成操作數的目標代碼 */
/* 說 明 分操作數為常數或者變量兩種情況處理 */
/* 注意不能用ac2 */
/************************************************/
void operandGen(ArgRecord *arg)
{
switch(arg->form)
{ /*操作數為常數*/
case ValueForm :
/* 如果代碼生成追蹤標志TraceCode為TRUE,寫入注釋,常數部分開始 */
if (TraceCode) emitComment("-> Const") ;
/* 生成載入常量指令,載入常量到累加器ac */
emitRM("LDC",ac,arg->Attr.value,0,"load const");
/* 如果代碼生成追蹤標志TraceCode為TRUE,寫入注釋,常數部分結束 */
if (TraceCode) emitComment("<- Const") ;
break;
/*分量為標號*/
case LabelForm:
/* 如果代碼生成追蹤標志TraceCode為TRUE,寫入注釋,標號部分開始 */
if (TraceCode) emitComment("-> Label") ;
/* 生成載入標號指令,載入標號值到累加器ac */
emitRM("LDC",ac,arg->Attr.label,0,"load label");
/* 如果代碼生成追蹤標志TraceCode為TRUE,寫入注釋,標號部分結束 */
if (TraceCode) emitComment("<- Label") ;
break;
/*操作數為變量,有可能是臨時變量*/
case AddrForm:
/* 如果代碼生成追蹤標志TraceCode為TRUE,寫入注釋,標注標識符開始 */
if (TraceCode) emitComment("-> var") ;
FindAddr(arg);
/*其中ac返回的是源變量或臨時變量的絕對偏移*/
if(arg->Attr.addr.access==indir)
{
/*取內容作為地址,再取內容*/
emitRM("LD",ac1,0,ac,"indir load id value");
emitRM("LD",ac,0,ac1,"");
}
else
{ /*存的是值*/
/* 寫入數值載入指令,載入變量標識符的值*/
emitRM("LD",ac,0,ac,"load id value");
}
/* 如果代碼生成追蹤標志TraceCode為TRUE,寫入注釋,標注標識符結束 */
if (TraceCode) emitComment("<- var") ;
break;
default: break;
}
}
/************************************************/
/* 函數名 aaddGen */
/* 功 能 生成地址加操作的目標代碼 */
/* 說 明 */
/************************************************/
void aaddGen(CodeFile *midcode)
{ /* 如果代碼生成追蹤標志TraceCode為TRUE,寫入注釋,aadd語句開始 */
if(TraceCode) emitComment("->address add");
if(midcode->codeR.arg1->Attr.addr.access == dir)
{ /*ac中的地址即為基地址*/
/*計算變量的絕對偏移,ac中存為變量的絕對偏移*/
FindAddr(midcode->codeR.arg1);
}
else
{ /*ac中的地址存放的內容為基地址*/
/*計算變量的絕對偏移,ac中存為變量的絕對偏移*/
FindAddr(midcode->codeR.arg1);
emitRM("LD",ac,0,ac,"");
}
/*基地址轉存到ac2*/
emitRM("LDA",ac2,0,ac,"op: store baseaddr ");
/*求地址相加運算的偏移量,存在ac中*/
operandGen(midcode->codeR.arg2);
/*地址相加,結果在ac中*/
emitRO("ADD",ac2,ac2,ac,"op +");
/*求目的變量的地址,存入ac*/
FindAddr(midcode->codeR.arg3);
/*地址相加結果寫入目的變量*/
emitRM("ST",ac2,0, ac,"");
}
/************************************************/
/* 函數名 readGen */
/* 功 能 生成讀操作的目標代碼 */
/* 說 明 根據變量是直接變量還是間接變量進行 */
/* 不同的處理 */
/************************************************/
void readGen(CodeFile *midcode)
{
/*生成讀指令,該指令完成讀入外部數值到累加器ac2的動作*/
emitRO("IN",ac2,0,0,"read integer value");
/*計算變量的絕對偏移,ac中存為變量的絕對偏移*/
FindAddr(midcode->codeR.arg1);
if(midcode->codeR.arg1->Attr.addr.access == dir)
{ /*直接存*/
/*最后生成存儲指令*/
emitRM("ST",ac2,0,ac," var read : store value");
}
else
{
/*以ac內容作為地址找變量單元,再存*/
emitRM("LD",ac1,0,ac,"");
emitRM("ST",ac2,0,ac1," indir var read : store value");
}
}
/************************************************/
/* 函數名 writeGen */
/* 功 能 生成寫操作的目標代碼 */
/* 說 明 調用函數得到值,并產生輸出代碼 */
/************************************************/
void writeGen(CodeFile *midcode)
{
/*調用函數,得到輸出的值,存在ac中*/
operandGen(midcode->codeR.arg1);
/*生成寫指令,該指令完成將累加器ac中的值輸出的動作*/
emitRO("OUT",ac,0,0,"write ac");
}
/************************************************/
/* 函數名 returnGen */
/* 功 能 生成返回語句的目標代碼 */
/* 說 明 返回過程調用的下一條語句,注意return*/
/* 語句只在過程中出現 */
/************************************************/
void returnGen(CodeFile *midcode)
{
/*從過程里跳出,所做的工作與過程結束相同*/
endprocGen(midcode);
}
/************************************************/
/* 函數名 assigGen */
/* 功 能 */
/* 說 明 */
/************************************************/
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -