⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cgen.cpp

📁 snl语言是一个简单的具有嵌套过程定义的过程式语言
💻 CPP
📖 第 1 页 / 共 2 页
字号:
			}/*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 + -