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

📄 pl0.cpp

📁 使用C语言实现的PL0编译器。 扩充了++ -- 以及添加注释功能
💻 CPP
📖 第 1 页 / 共 3 页
字号:
				getchdo;  
				if(ch=='=')  
				{  
					sym=becomes;  
					getchdo;  
				}  
				else  
				{  
                   sym=nul;                                     /* 不能识别的符号 */  
				}  
	      }  
	      else  
	      {  
               if(ch=='<')                                       /* 检测小于或小于等于符号 */  
				{  
                    getchdo;  
					  if(ch=='=')  
					{  
						sym=leq;  
                      getchdo;  
                   }  
					else  
		           {  
                      sym=lss;  
		           }  
                }  
                else  
                {  
                    if(ch=='>') /* 检测大于或大于等于符号 */  
                    {  
							getchdo;  
							if(ch=='=')  
							{  
								sym=geq;  
								getchdo;  
							}  
							else  
							{		  
								sym=gtr;  
							}  
                     }  
					  else  
                    {  
                          sym=ssym[ch]; /* 当符号不满足上述条件时,全部按照单字符符号处理 */  
                          if(sym!=period)
						  {		
							  getchdo;
						  }
                     }  
				}
		  }
	 }
	}
	return 0;
}

/*y:instruction.l;
 * z:instruction.a;
 */  
int gen(enum fct x,int y,int z)  
{  
    if(cx>=cxmax)  
    {  
         printf("Program too long"); /* 程序过长 */  
         return -1;  
    }
    code[cx].f=x;  
    code[cx].l=y;  
    code[cx].a=z;  
    cx++;  
    return 0;  
}
/* 测试当前符号是否合法
 *
 * 在某一部分(如一条语句,一个表达式)将要结束时时我们希望下一个符号属于某集合(该部分的后跟  
 * 符号),test负责这项监测,并且负责当监测不通过时的补救措施,程序在需要检测时指定当前需要的符  
 * 号集合和补救用的集合(如之前未完成部分的后跟符号),以及检测不通过时的错误号、
 * s1:我们需要的符号
 * s2:如果不是我们需要的,则需要一个补救用的集合
 * n:错误号
 */  
int test(bool* s1,bool* s2,int n)
{  
    if(!inset(sym,s1))  
    {  
         error(n);  
         /* 当检测不通过时,不停获取符号,直到它属于需要的集合或补救的集合 */  
         while((!inset(sym,s1))&&(!inset(sym,s2)))  
         {  
              getsymdo;  
         }  
    }  
    return 0;  
}  
/* 
 * 编译程序主体 
 * lev:当前分程序所在层
 * tx:名字表当前尾指针
 * fsys:当前模块后跟符号集合
 */  
int block(int lev,int tx,bool* fsys)  
{  
    int i;  
    int dx; /* 名字分配到的相对地址 */  
    int tx0; /* 保留初始tx */  
    int cx0; /* 保留初始cx */  
    bool nxtlev[symnum];    /* 在下级函数的参数中,符号集合均为值参,但由于使用数租实现,  
										传递进来的是指针,为防止下级函数改变上级函数的集合,开辟新的空间  
										传递给下级函数,之后所有的nxtlev都是这样 */  
    dx=3;   
    tx0=tx; /* 记录本层名字的初始位置 */  
    table[tx].adr=cx;  
    gendo(jmp,0,0);  
    if(lev>levmax)
         error(32);  
    do  
    {  
		if(sym==constsym) /* 收到常量声明符号,开始处理常量声明 */  
		{  
			getsymdo;  
			do  
			{  
              constdeclarationdo(&tx,lev,&dx); /* dx的值会被constdeclaration改变,使用指针 */  
              while(sym==comma)   
              {  
                   getsymdo;  
                   constdeclarationdo(&tx,lev,&dx);  
              }  
              if(sym==semicolon)  
              {  
                   getsymdo;  
              }  
              else error(5);  
			} while(sym==ident);  
		}  
		if(sym==varsym) /* 收到变量声明符号,开始处理变量声明 */  
		{  
         getsymdo;  
         do  
         {  
              vardeclarationdo(&tx,lev,&dx);  
              while(sym==comma)   
              {  
                   getsymdo;  
                   vardeclarationdo(&tx,lev,&dx);  
              }  
              if(sym==semicolon)  
              {  
                   getsymdo;  
              }  
              else error(5);  
         } while(sym==ident);  
		}  
    while(sym==procsym) /* 收到过程声明符号,开始处理过程声明 */  
    {  
         getsymdo;  
         if(sym==ident)  
         {  
              enter(procedur,&tx,lev,&dx); /* 记录过程名字 */  
              getsymdo;  
         }  
         else  
	      error(4); /* procedure后应为标识符 */  
         if(sym==semicolon)  
         {  
              getsymdo;  
         }
         else 
              error(5); /* 漏掉了分号 */  
         memcpy(nxtlev,fsys,sizeof(bool)*symnum);  
         nxtlev[semicolon]=true;  
         if(-1==block(lev+1,tx,nxtlev))
              return -1; /* 递归调用 */  
              if(sym==semicolon)  
              {  
                    getsymdo;  
					memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);  
					nxtlev[ident]=true;  
				    nxtlev[procsym]=true;  
				    testdo(nxtlev,fsys,6);  
              }  
              else 
                   error(5); /* 漏掉了分号 */  
         }  
          memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);  
		  nxtlev[ident]=true;  
		  testdo(nxtlev,declbegsys,7);  
    } while(inset(sym,declbegsys)); /* 直到没有声明符号 */  
    code[table[tx0].adr].a=cx; /* 开始生成当前过程代码 */  
    table[tx0].adr=cx; /* 当前过程代码地址 */  
	table[tx0].size=dx; /* 声明部分中每增加一条声明都会给dx增加1,声明部分已经结束,dx就是当前过程数据的size */  
	
	cx0=cx;  
	gendo(inte,0,dx); /* 生成分配内存代码 */  
	if(tableswitch) /* 输出名字表 */  
	{  
		printf("TABLE:\n");  
		if(tx0+1>tx)
		{
			printf("NULL\n");  
		}
			for(i=tx0+1;i<=tx;i++)  
			{  
				switch(table[i].kind)  
				{  
					case constant:  
						printf("	%d const %s ",i,table[i].name);  
						printf("val=%d\n",table[i].val);  
						fprintf(fas,"	%d const %s ",i,table[i].name);  
						fprintf(fas,"val=%d\n",table[i].val);  
						break;  
					case variable:  
						printf("    %d var   %s ",i,table[i].name);  
						printf("lev=%d addr=%d\n",table[i].level,table[i].adr);  
						fprintf(fas,"    %d var   %s ",i,table[i].name);  
						fprintf(fas,"lev=%d addr=%d\n",table[i].level,table[i].adr);  
						break;  
					case procedur:  
						printf("    %d proc  %s ",i,table[i].name);  
						printf("lev=%d addr=%d size=%d\n",table[i].level,table[i].adr,table[i].size);  
						fprintf(fas,"    %d proc  %s ",i,table[i].name);  
						fprintf(fas,"lev=%d addr=%d size=%d\n",table[i].level,table[i].adr,table[i].size);  
						break;  
				}  
		}  
		printf("\n");  
	}  
	/* 语句后跟符号为分号或end */  
	memcpy(nxtlev,fsys,sizeof(bool)*symnum); /* 每个后跟符号集和都包含上层后跟符号集和,
																		以便补救 */  
	nxtlev[semicolon]=true;  
	nxtlev[endsym]=true;  
	statementdo(nxtlev,&tx,lev);  
	gendo(opr,0,0); /* 每个过程出口都要使用的释放数据段指令 */  
	memset(nxtlev,0,sizeof(bool)*symnum); /*分程序没有补救集合 */  
	testdo(fsys,nxtlev,8); /* 检测后跟符号正确性 */  
	listcode(cx0); /* 输出代码 */  
	return 0;  
}  
/* 生成一项名字表 */  
void enter(enum object k, /* 名字种类const,var or procedure */  
   int* ptx, /* 名字表尾指针的指针,为了可以改变名字表尾指针的值,以后所有的ptx都是这样 */  
   int lev, /* 名字所在的层次,,以后所有的lev都是这样 */  
   int* pdx /* dx为当前应分配的变量的相对地址,分配后要增加1,所以使用指针,以后所有的pdx都是这样 */  
   )  
{  
	(*ptx)++;  
	strcpy(table[(*ptx)].name,id); /* 全局变量id中已存有当前名字的名字 */  
	table[(*ptx)].kind=k;  
	switch(k)  
	{  
		case constant: /* 常量名字 */  
			if(num>amax)  
			{  
				error(31); /* 数值越界 */  
				num=0;  
			}  
			table[(*ptx)].val=num;  
			break;  
		case variable: /* 变量名字 */  
			table[(*ptx)].level=lev;  
			table[(*ptx)].adr=(*pdx);  
			(*pdx)++;  
			break;  
		case procedur: /* 过程名字 */  
			table[(*ptx)].level=lev;  
			break;  
	}  
}  
/* 查找名字的位置 */  
/* 找到则返回在名字表中的位置,否则返回0 */  
int postion(char* idt, /* 要查找的名字 */  
				int tx /* 当前名字表尾指针 */  )  
{  
	int i;  
	strcpy(table[0].name,idt);  
	i=tx;  
	while(strcmp(table[i].name,idt)!=0)i--;  
	return i;  
}  
/* 常量声明处理 */  
int constdeclaration(int* ptx,  int lev,  int* pdx)  
{  
	if(sym==ident)  
	{  
		getsymdo;  
		if(sym==eql||sym==becomes)  
		{  
			if(sym==becomes)error(1); /* 把=写成了:= */  
			getsymdo;  
			if(sym==number)  
			{  
				enter(constant,ptx,lev,pdx);  
				getsymdo;  
			}  
			else error(2); /* 常量说明=后应是数字 */  
		}  
		else error(3); /* 常量说明标识后应是= */  
	}  
	else error(4); /* const后应是标识 */  
	return 0;  
}  
/* 变量声明处理 */  
int vardeclaration(int* ptx,int lev,int* pdx)  
{  
	if(sym==ident)  
	{  
		enter(variable,ptx,lev,pdx); /* 填写名字表 */  
		getsymdo;  
	}  
	else error(4); /* var后应是标识 */  
	return 0;  
}  
/* 输出代码 */  
void listcode(int cx0)  
{  
	int i;  
	if(listswitch)  
	{  
		for(i=cx0;i<cx;i++)  
		{  
			printf("%d %s %d %d\n",i,mnemonic[code[i].f],code[i].l,code[i].a);  
			fprintf(fa,"%d %s %d %d\n",i,mnemonic[code[i].f],code[i].l,code[i].a);  
		}  
	}  
}  
/* 语句处理 */  
int statement(bool* fsys,int* ptx,int lev) /* 参数意义见block和enter函数 */  
{  
	int i,cx1,cx2;  
	bool nxtlev[symnum]; /* 意义见block函数 */  
	if(sym==ident) /* 准备按照赋值语句处理 */  
	{  
		i=postion(id,*ptx);  
		if(i==0)
		{
			error(11); /* 变量未找到 */  
		}
		else  
		{  
			if(table[i].kind!=variable)  
			{  
				error(12); /* 赋值语句格式错误 */  
				i=0;  
			}  
			else
			{
				getsymdo;  
				if(sym==becomes)   
				{  
					getsymdo;  
				}  
				else error(13); /* 检测赋值符号 */  
				memcpy(nxtlev,fsys,sizeof(bool)*symnum);  
				expressiondo(nxtlev,ptx,lev); /* 处理赋值符号右侧表达式 */  
				if(i!=0)  
				{  
					gendo(sto,lev-table[i].level,table[i].adr); /* expression将执行一系列指令,但最终结果将会保存在栈顶,执行sto命令完成赋值 */  
				}  
			}  
		}//if(i==0)
	}
	else  
	{  
		if(sym==readsym) /* 准备按照read语句处理 */  
		{  
			getsymdo;  
			if(sym!=lparen)error(34); /* 格式错误,应是左括号 */  
			else  
			{  
				do
				{  
					getsymdo;  
					if(sym==ident)
					{
						i=postion(id,*ptx); /* 查找要读的变量 */  
					}
					else 
					{
						i=0;  
					}
					if(i==0)
					{
					error(35); /* read()中应是声明过的变量名 */  
					}
					else  
					{  
						gendo(opr,0,16); /* 生成输入指令,读取值到栈顶 */  
						gendo(sto,lev-table[i].level,table[i].adr); /* 储存到变量 */  
					}  
					getsymdo;  
				}  while(sym==comma); /* 一条read语句可读多个变量 */  
			}  
			if(sym!=rparen)   
			{  
				error(33); /* 格式错误,应是右括号 */  
				while(!inset(sym,fsys)) /* 出错补救,直到收到上层函数的后跟符号 */  
				{
					getsymdo;  
				}
			}  
			else  
			{  
				getsymdo;  
			}  
		}  
		else  
		{	  
			if(sym==writesym) /* 准备按照write语句处理,与read类似 */  
			{  
				getsymdo;  
				if(sym==lparen)  
				{  
					do  {  
							getsymdo;  
							memcpy(nxtlev,fsys,sizeof(bool)*symnum);  
							nxtlev[rparen]=true;  
							nxtlev[comma]=true; /* write的后跟符号为) or , */  
							expressiondo(nxtlev,ptx,lev); /* 调用表达式处理,此处与read不同,read为给变量赋值 */  
							gendo(opr,0,14); /* 生成输出指令,输出栈顶的值 */  
						}  while(sym==comma);   
					if(sym!=rparen)
					{
						error(33); /* write()中应为完整表达式 */  
					}
					else  
					{  
						getsymdo;  
					}  
				}  
				gendo(opr,0,15); /* 输出换行 */  
			}  
			else  
			{  
				if(sym==callsym) /* 准备按照call语句处理 */  
				{  
					getsymdo;  
					if(sym!=ident)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -