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