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