?? cgen.cpp
字號:
}/*while循環結束*/
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/*@@@@@@@@@@ 進入子程序入口 @@@@@@@@@@@@@*/
/*保存當前sp*/
emitRM("ST",sp,0,top," save old sp");
/*保存寄存器0,1,2,4*/
emitRM("ST",ac,3,top," save ac");
emitRM("ST",ac1,4,top," save ac1");
emitRM("ST",ac2,5,top," save ac2");
emitRM("ST",displayOff,6,top," save nOff");
/*新的displayOff的值*/
emitRM("LDC",displayOff,pp->table[0]->attrIR.More.ProcAttr.nOff,0," new displayOff");
/*返回值*/
//emitRM("LDC",ac,0,0,"");
//emitRM("ST",ac,7,top,"return value");
/*保存返回地址*/
savedLoc1 = emitSkip(2);
/*過程層數*/
emitRM("LDC",ac1,pp->table[0]->attrIR.More.ProcAttr.level,0," save procedure level");
emitRM("ST",ac1,2,top,"");
/*移display表*/
for(ss = 0;ss<(pp->table[0]->attrIR.More.ProcAttr.level);ss++)
{
/*取原displayOff,存入ac2中*/
emitRM("LD",ac2,6,top," fetch old display Off");
/*ss要加上當前nOff才是對于sp的偏移*/
emitRM("LDA",ac2,ss,ac2," old display item");
/*ac2中為絕對地址*/
emitRO("ADD",ac2,ac2,sp,"");
/*取當前AR中display表的的第ss項,存入ac1中*/
emitRM("LD",ac1,0,ac2," fetch display table item");
/*當前AR的displayOff*/
emitRM("LDA",ac2,ss,displayOff," current display item");
/*ac2中為絕對地址*/
emitRO("ADD",ac2,ac2,top,"");
/*將ac1中的內容送入ac2所指地址中*/
emitRM("ST",ac1,0,ac2," send display table item");
}
/*在display表中的最上層填寫本層的sp*/
/*ac2中存儲的為display表最上層的相對off*/
emitRM("LDA",ac2,pp->table[0]->attrIR.More.ProcAttr.level,displayOff," current sp in display");
emitRO("ADD",ac2,top,ac2," absolute off");
emitRM("ST",top,0,ac2," input value" );
/*修改sp和top*/
emitRM("LDA",sp,0,top," new sp value");
emitRM("LDA",top,pp->table[0]->attrIR.More.ProcAttr.mOff,top," new top value");
/*回填返回地址*/
currentLoc = emitSkip(0)+1;
emitBackup(savedLoc1);
emitRM("LDC",ac1,currentLoc,0," save return address");
emitRM("ST",ac1,1,top,"");
emitRestore();
/*轉向子程序*/
emitRM("LDC",pc,pp->table[0]->attrIR.More.ProcAttr.procEntry,0," procedure entry ");
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/*@@@@@@@@@@ 子程序出口處 @@@@@@@@@@@@@*/
/*恢復寄存器值*/
emitRM("LD",ac,3,sp," resume ac");
emitRM("LD",ac1,4,sp," resume ac1");
emitRM("LD",ac2,5,sp," resume ac2");
emitRM("LD",displayOff,6,sp," resume nOff");
/*恢復sp和top值*/
emitRM("LDA",top,0,sp," resume top");
emitRM("LD",sp,0,sp," resume sp");
/*讀函數值入ac中*/
//emitRM("LD",ac,7,top," procedure return value");
break;
/*處理return返回語句,主程序中沒有return語句*/
case ReturnK:
/*REG[sp]+1地址中存放的是函數的返回地址*/
//emitRM("LD",ac2,1,sp,"");
//emitRM("LDA",pc,0,ac2," return address");
break;
default:
break;
}
}
/************************************************/
/* 函數名 genExp */
/* 功 能 表達式類型語法樹節點代碼生成函數 */
/* 說 明 該函數根據表達式類型分類處理, */
/* 生成目標代碼和注釋 */
/************************************************/
void genExp(TreeNode * t)
{
/* 語法樹節點各個子節點 */
TreeNode * p1, * p2;
/* 對語法樹節點的表達式類型細分處理 */
switch (t->kind.exp)
{
/* 語法樹節點tree為ConstK表達式類型 */
case ConstK :
/* 如果代碼生成追蹤標志TraceCode為TRUE,寫入注釋,常數部分開始 */
if (TraceCode) emitComment("-> Const") ;
/* 生成載入常量指令,載入常量到累加器ac */
emitRM("LDC",ac,t->attr.ExpAttr.val,0,"load const");
/* 如果代碼生成追蹤標志TraceCode為TRUE,寫入注釋,常數部分結束 */
if (TraceCode) emitComment("<- Const") ;
break;
/* 語法樹節點tree為IdK表達式類型 */
case VariK :
/* 如果代碼生成追蹤標志TraceCode為TRUE,寫入注釋,標注標識符開始 */
if (TraceCode) emitComment("-> Id") ;
FindAdd(t);
/*其中ac返回的是基本類型變量、域變量或下標變量的絕對偏移*/
if(t->table[0]->attrIR.More.VarAttr.access==indir)
{
/*地址*/
/*取值,作為地址*/
emitRM("LD",ac1,0,ac,"indir load id value");
/*ac1中為地址值*/
/*按地址取單元內容*/
emitRM("LD",ac,0,ac1,"");
}
else
{
/*值*/
/* 寫入數值載入指令,載入變量標識符的值*/
emitRM("LD",ac,0,ac,"load id value");
}
/* 如果代碼生成追蹤標志TraceCode為TRUE,寫入注釋,標注標識符結束 */
if (TraceCode) emitComment("<- Id") ;
break;
/* 語法樹節點tree為OpK表達式類型 */
case OpK :
/* 如果代碼生成追蹤標志TraceCode為TRUE,寫入注釋,標注操作開始 */
if (TraceCode) emitComment("-> Op") ;
/* 語法樹節點tree第一子節點為左操作數,賦給p1 */
p1 = t->child[0];
/* 語法樹節點tree第二子節點為右操作數,賦給p2 */
p2 = t->child[1];
/* 對第一子節點遞歸調用函數cGen(),為左操作數生成目標代碼 */
cGen(p1);
/* 生成單元設置指令,在臨時數據存儲區中壓入左操作數 */
emitRM("ST",ac,tmpOffset--,mp,"op: push left");
/* 對第二子節點遞歸調用函數cGen(),為右操作數生成目標代碼 */
cGen(p2);
/* 生成數值載入指令,從臨時數據存儲區中載入左操作數 */
emitRM("LD",ac1,++tmpOffset,mp,"op: load left");
/* 對語法樹節點t的成員運算符attr.op分類處理 */
switch (t->attr.ExpAttr.op)
{
/* 語法樹節點成員運算符為PLUS,生成加法指令 */
case PLUS :
emitRO("ADD",ac,ac1,ac,"op +");
break;
/* 語法樹節點成員運算符為MINUS,生成減法指令 */
case MINUS :
emitRO("SUB",ac,ac1,ac,"op -");
break;
/* 語法樹節點成員操作符為TIMES,寫入乘法指令 */
case TIMES :
emitRO("MUL",ac,ac1,ac,"op *");
break;
/* 語法樹節點成員操作符為OVER,寫入除法指令 */
case OVER :
emitRO("DIV",ac,ac1,ac,"op /");
break;
/* 語法樹節點成員操作符為LT,寫入相應的指令序列 */
/* 如果為真,結果為1;否則結果為0 */
case LT :
/* 寫入減指令,將(左-右)操作數相減,結果送累加器ac */
emitRO("SUB",ac,ac1,ac,"op <") ;
/* 寫入判斷跳轉指令,如果累加器ac的值小于0, *
* 則代碼指令指示器跳過兩條指令 */
emitRM("JLT",ac,2,pc,"br if true") ;
/* 寫入載入常量指令,將累加器ac賦值為0 */
emitRM("LDC",ac,0,ac,"false case") ;
/* 寫入數值載入指令,代碼指令指示器pc跳過下一條指令 */
emitRM("LDA",pc,1,pc,"unconditional jmp") ;
/* 寫入載入常量指令,將累加器ac賦值為1 */
emitRM("LDC",ac,1,ac,"true case") ;
break;
/* 語法樹節點成員操作符為EQ,寫入相應的指令序列 */
/* 如果為真,結果為1;否則結果為0 */
case EQ :
/* 寫入減法指令,將左,右操作數相減,結果送累加器ac */
emitRO("SUB",ac,ac1,ac,"op ==") ;
/* 寫入判斷跳轉指令,如果累加器ac等于0, *
* 代碼指令指示器pc跳過兩條指令 */
emitRM("JEQ",ac,2,pc,"br if true");
/* 寫入載入常量指令,將累加器ac賦值為0 */
emitRM("LDC",ac,0,ac,"false case") ;
/* 寫入數值載入指令,代碼指令指示器pc跳過一條指令 */
emitRM("LDA",pc,1,pc,"unconditional jmp") ;
/* 寫入載入常量指令,將累加器ac賦值為1 */
emitRM("LDC",ac,1,ac,"true case") ;
break;
/* 其他未知運算符,寫入注釋,標注未知運算符信息 */
default:
emitComment("BUG: Unknown operator");
break;
}
/* 如果代碼生成追蹤標志TraceCode為TRUE,寫入注釋信息,標注操作結束 */
if (TraceCode) emitComment("<- Op") ;
break;
default:
break;
}
}
/************************************************************/
/* 函數名 cGen */
/* 功 能 語法樹代碼生成函數 */
/* 說 明 該函數通過遍歷語法樹,根據語法樹的不同類型, */
/* 分別調用不同代碼生成函數,遞歸生成目標代碼 */
/************************************************************/
void cGen( TreeNode * tree)
{ if (tree != NULL)
{
/* 對語法樹節點類型成員nodekind分類處理 */
switch (tree->nodekind)
{
/* 對語句類型語法樹節點調用代碼生成函數,生成目標代碼 */
case StmtK:
genStmt(tree);
break;
/* 對表達式類型語法樹節點調用代碼生成函數,生成目標代碼 */
case ExpK:
genExp(tree);
break;
default:
break;
}
/* 對語法樹節點的兄弟節點遞歸調用函數cGen(),生成目標代碼 */
cGen(tree->sibling);
}
}
/************************************************/
/************* 代碼生成器的基本函數 *************/
/************************************************/
/* 函數名 codeGen */
/* 說 明 該函數通過遍歷語法樹產生目標代碼文件 */
/* 第二個參數codefile為目標代碼文件名 */
/************************************************/
void codeGen(TreeNode * syntaxTree, char * codefile)
{
/*存儲主程序的入口地址*/
int currentLoc;
/*目標代碼的第一條指令地址*/
int savedLoc;
/* 在內存中動態分配字串單元,返回單元指針s, *
* codefile為存儲目標代碼的代碼文件名 */
char * s = (char *)malloc(strlen(codefile)+7);
/* 將給定字串拷貝到s */
strcpy(s,"File: ");
/* 將目標代碼文件名的字串拼接到s */
strcat(s,codefile);
fprintf(listing,"\n\n");
/* 生成代碼文件說明注釋,寫入代碼文件 */
emitComment("TINY Compilation to TM Code");
emitComment(s);
/* 生成標準先驅指令 */
emitComment("Standard prelude:");
/* 寫入載入指令,從0地址處載入最大地址值賦給存儲指示器mp *
* 使mp指向數據存儲區的最高地址 */
emitRM("LD",mp,0,ac," load maxaddress from location 0");
/* 寫入單元設置指令,清空0地址單元中內容 */
emitRM("ST",ac,0,ac," clear location 0");
/* 寫入注釋,先驅指令寫完 */
emitComment(" End of standard prelude.");
/* 為TINY程序調用遞歸處理函數cGen()生成目標代碼 */
TreeNode * t1 = syntaxTree->child[1];
/*為主程序入口留一個跳轉語句*/
savedLoc = emitSkip(1);
while(t1!=NULL)
{
if(t1->nodekind==ProcDecK)
genProc(t1);
t1=t1->sibling;
}
/*主程序入口*/
currentLoc = emitSkip(0);
/*回退到目標代碼第一條空語句處*/
emitBackup(savedLoc);
/*添加指令,將主程序入口地址傳至指令寄存器pc*/
emitRM("LDC",pc,currentLoc,0," main entry");
/*返回當前地址*/
emitRestore();
emitComment("-> main procedure");
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/*@@@@@@@@@@ 處理主程序 @@@@@@@@@@@@@*/
/*處理主程序的過程活動記錄,需要填寫的內容有:全局變量、display表*/
/*初始化寄存器*/
emitRM("LDC",ac,0,0,"initialize ac");
emitRM("LDC",ac1,0,0,"initialize ac1");
emitRM("LDC",ac2,0,0,"initialize ac2");
/*確定sp*/
emitRM("ST",ac,0,sp," main sp");
/*確定displayOff*/
emitRM("LDA",displayOff,mainOff,sp," main displayOff");
/*填寫display表,只有主程序本層的sp(0)*/
emitRM("ST",ac,0,displayOff," main display ");
/*填寫top*/
emitRM("LDA",top,1,displayOff," main top");
/*主程序體的代碼生成部分*/
TreeNode * t2= syntaxTree->child[2]->child[0];
if(t2!=NULL)
cGen(t2);
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
/*@@@@@@@@@@ 處理完主程序,退出AR @@@@@@@@@@@@@*/
emitComment("<- end of main ");
/* 寫入注釋,標志文件執行的結束 */
emitComment("End of execution.");
/* 寫入停止指令,結束程序執行 */
emitRO("HALT",0,0,0,"");
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -