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

📄 compiler.cpp

📁 PL0的一个编译器
💻 CPP
📖 第 1 页 / 共 4 页
字号:
		{
          strcpy(sym,wsym[k]);//找到保留字,把sym置为相应的保留字值

		}
		else
		{
			strcpy(sym,"ident");//否则就把sym置为标识符
		}
	}
	
	else if(ch>='0'&&ch<='9') //如果读出字符是数字
	{
		k=0;   //数字位数置0
		num=0; //数字置为0
		strcpy(sym,"number");//置sym为number,表示这一次读到的是数字
		do
		{
			num=10*num+(int)ch-'0';//num*10加上最近读出的字符ASCII减'0'的ASCII得到相应的数值
			k++; //数字位数加1
			getCh();
		}while(ch>='0'&&ch<='9');
         
		if(k>NMAX) //如果组成的数字位数大于最大允许的数字位数
		{
			error(30);//发出第30号错误
		}
	}

    else if(ch==':')//如果读出的是冒号
	{
		getCh(); //再读取下一次字符
        if(ch=='=')
		{
         strcpy(sym,"becomes");
		 getCh();
		}
		else
	     strcpy(sym,"nul");
	}
	else if(ch=='<')//如果读出的不是字母也不是数字也不是冒号
	{
     getCh();
	 if(ch=='=')
	 {
		 strcpy(sym,"leq");
		 getCh();
	 }

	 else if(ch=='>')
	 {
		 strcpy(sym,"neq");
		 getCh();
	 }

	 else
		 strcpy(sym,"lss");
	}
	else if (ch=='>')
	{
		getCh();
		if(ch=='=')
		{
			strcpy(sym,"geq");
			getCh();
		}
		else 
			strcpy(sym,"gtr");
	}
    else//如果读到不是字母也不是数字也不是冒号也不是小于号大于号
	{
		switch(ch)
		{
		case '+': strcpy(sym,"plus");
			      break;
		case '-': strcpy(sym,"minus");
			      break;
		case '*': strcpy(sym,"times");
		          break;
		case '/': strcpy(sym,"slash");
			      break;
		case '(': strcpy(sym,"lparen");
			      break;
		case ')': strcpy(sym,"rparen");
			      break;
		case '=': strcpy(sym,"eql");
			      break;
		case ',': strcpy(sym,"comma");
			      break;
		case '.': strcpy(sym,"period");
			      break;
		//case '#': strcpy(sym,"neq");
		//	      break;
		case ';': strcpy(sym,"semicolon");
			      break;
		}
		getCh();
	}
}


//参数p是要生成的一行代码的助记符
//参数q,r是代码的两个操作数
//该函数用于把生成的目标代码写入目标代码数组,供后面的解释器解释执行
void gen(enum fct p,int q,int r)
{
	if(cx>CXMAX)//表示当前生成的代码行号大于允许的最大代码行数
	{
		cout<<"程序太长";
	}
	else
	{  
		code[cx].f=p;
		code[cx].l=q;
		code[cx].a=r;
		cx++;  //移动cx指向下一个空位
	}
}

//test:测试当前单词是否合法
//s1:当语法进入或退出某一语法单元时当前单词符合应属于的集合
//s2:在某一出错状态下,可恢复语法分析政党工作的补充单词集合
//n:出错信息编号,当当前符号不属于合法的s1集合时发出的出错信息
/*void test(symset s1,symset s2,int n)
{
   if(s1.find(sym)==s1.end()) //如果当前符号不在s1中
   {
	   error(n);
	   symset::iterator ii;
	   for(ii=s2.begin();ii!=s2.end();ii++)
		   s1.insert(*ii);            //s1=s1+s2 把s2集合补充进s1集合
       while(s1.find(sym)==s1.end())  //通过循环找到下一个合法的符号,以恢复语法分析工作
		   getsym();
	   
   }
   //else 
	 //  return;
   
  }//test end */

//检查str串是否在set结构体记录中,若在返回1,否则返回0
int in(char *str,struct node *set)
{
	int i=0;
	while(set->pa[i]!=NULL)
	{
		if(strcmp(str,set->pa[i])==0)
			return 1;
		else
			i++;
	}
	return 0;
}

//将set1和set1中没有的set2的内容合成为一个node类型并返回(合并set1,set2)
struct node *add(struct node *set1,struct node *set2)
{
	int i=0,j=0,k=0,cnt;

	//定义pt,并申请空间
	struct node *pt;
	pt=(struct node *)malloc(sizeof(struct node));
	for(cnt=0;cnt<32;cnt++)
	{
		pt->pa[cnt]=(char *)malloc(10*sizeof(char));
	}

	//将set1中内容拷贝到pt
	while(set1->pa[i]!=NULL)
		strcpy(pt->pa[j++],set1->pa[i++]);
	
	//现在pt和set1中内容相同,但若set2中有与set1不同的内容,加入到pt中
	while((set2->pa[k])!=NULL)
	{
		if(in(set2->pa[k],set1)==0)
			strcpy(pt->pa[j++],set2->pa[k++]);
		else
			k++;
	}
	pt->pa[j]=NULL;
	return(pt);
}



//test:测试当前单词是否合法
//p:当语法进入或退出某一语法单元时当前单词符合应属于的结构
//q:在某一出错状态下,可恢复语法分析政党工作的补充单词结构
//n:出错信息编号,当当前符号不属于合法的s1集合时发出的出错信息
void test(struct node *p,struct node *q,int n)
{
	if(in(sym,p)==0)        //如果当前符号不在p中
	{
		error(n);        
		p=add(p,q);          //把s2补充进s1
		while(in(sym,p)==0)  //通过循环找到下一个合法的符号,以恢复语法分析工作
			getsym();
	}
}


void enter(enum object k)//登录符号表过程enter
{
  tx++;						  //符号表指针指向一个新的空位
  strcpy(table1[tx].name,id); //符号名字
  table1[tx].kind=k;		  //符号类型
  switch(k)					  //根据不同的类型进行不同的操作
  {
  case constant:        //如果是常量名
	  if(num>AMAX)      //在常量的数值大于允许的最大值的情况下
	  {
		  error(31);    //抛出31号错误
		  num=0;        //实际登录的数字以0代替
	  }
	  else 
	  {
		  table1[tx].val=num; //如果是合法的数值就登录到符号表
	  }
	  break;

  case variable:           //如果是变量名
	  table1[tx].level=lev;//记下它所属的层次号
	  table1[tx].adr=dx;   //记下它在当前层中的偏移量
      dx++;                //偏移量自增一,为下一次做好准备
	  break;

  case procedur:           //如果要登录的是过程名
	  table1[tx].level=lev;//记录这个过程所在层次
	  break;
  }
} //enter end


//position函数:在符号表中查找指定符号所在位置
//参数:id要找的符号
//返回值:要找的符号在符号表中的位置,如果找不到就返回0
int position(char id[10])
{
  int i;
  strcpy(table1[0].name,id);  //先把id放入符号表0号位置
  i=tx;            //从符号表中当前位置也即最后一个符号开始找
  while(i>=0&&strcmp(table1[i].name,id)!=0)  
      i--;   //如果当前的符号与要找的不一致,找前面一个
  return i;  //返回找到的位置号,如果没找到则一定正好为0
} //end position


//常量声明处理过程
void constdeclaration()
{
   if(strcmp(sym,"ident")==0)//常量声明过程开始遇到的第一个符号必然应为标识符
   {
	   getsym();//获取下一个token
	   if(strcmp(sym,"becomes")==0||strcmp(sym,"eql")==0) //如果是等号或赋值号
	   {
         if(strcmp(sym,"becomes")==0)//如果是赋值号(常量声明中应应该是等号)
				error(1);    //抛出1号错误
		                     //这里其实是自动进行了错误纠正使编译继续进行,把赋值号当作等号处理
		 
		 getsym();
		 if(strcmp(sym,"number")==0)
		 {
			 enter(constant); //把这个常量登录到符号表
			 getsym(); //获取下一个token,为后面作准备
		 }
		 else
			 error(2);  //如果等号后面接的不是数字,抛出2号错误
	   }
	   else
		   error(3);    //如果常量标识符后接的不是等号或赋值号,抛出3号错误
   }
   else 
	   error(4);         //如果常量声明过程遇到的第一个符号不为标识符,抛出4号错误

}//constdeclaration end


//变量声明过程
void vardeclaration()
{
	if(strcmp(sym,"ident")==0)  //变量声明过程开始最到的第一个符号必然应为标识符
	{
		enter(variable);  //将标识符登录到符号表中
		getsym();         //获取下一个token,为后面作准备
	}
	else
		error(4);         //如果变量声明过程最到的第一个符号不是标识符,抛出4号错误
} //vardeclaration end
   

//函数listcode:列出当前一层类PCODE目标代码
/*void listcode(int *cx0)
{
	int i=*cx0;
	if(listswitch) //如果用户选择是要列出代码的情况下才列出代码
	{
		cout<<endl;
		while(i<=cx-1) //从当前层代码开始位置到当前代码位置-1处,即为本分程序块
		{
			cout<<"  "<<i<<"  "<<mnemonic[(int)code[i].f]<<"  "<<code[i].l<<"  "<<code[i].a<<endl;  //显示出第i行代码的助记符和L与A操作数
           // fprintf(fa,"%2d %5s %3d %5d\n",i,mnemonic[(int)code[i].f],code[i].l,code[i].a);   //同时把屏显打印到文件
			i++;
		}
		cout<<endl<<endl;
	}
}*/
void listcode(int *cx0)
{
	//打印本层的伪代码
	int i;
	if(listswitch)
	{
		cout<<endl;
		for(i=*cx0;i<=cx-1;i++)
		{
			printf("%2d %5s %3d %5d\n",i,mnemonic[(int)code[i].f],code[i].l,code[i].a);
			fprintf(fa,"%2d %5s %3d %5d\n",i,mnemonic[(int)code[i].f],code[i].l,code[i].a);
		}
		printf("\n");
		printf("\n");
	}
}


//因子处理过程factor
//参数说明:fsys:如果出错可用来恢复语法分析的符号集合
void factor(struct node *fsys)
{   
	int i;
	int m=0,n=0;
	void expression(struct node *fsys);
	struct node *tp;
	char *tpset[]={"rparen",NULL};
	tp=(struct node*)malloc(sizeof(struct node));
	while(tpset[m]!=NULL)
		tp->pa[n++]=tpset[m++];
	
	tp->pa[n]=NULL;
	test(facbegsys,fsys,24);       //开始因子处理前,先检查当前token是否在facbegsys集合中
	                               //如果不是合法的token,抛24号错误,并通过fsys集恢复使用权语法处理可以继续进行

	while(in(sym,facbegsys)==1)    //循环处理因子
	{
		if(strcmp(sym,"ident")==0) //如果最到的是标识符
		{
			i=position(id);        //查符号表,找到当前标识符在符号表中的位置
			if(i==0)			   //如果查符号表返回0,表示没有找到标识符
				error(11);		   //抛出11号错误
			else				   //如果在符号表中找到了当前标识符的位置,开始生成相应代码
			{
				switch(table1[i].kind)
				{
				case constant:      
					gen(lit,0,table1[i].val);//如果是常量,值为val,生成lit指令,把val放到栈顶
					break;
				case variable:
					gen(lod,lev-table1[i].level,table1[i].adr);  //如果是变量,生成lod指令,把位于距离当前层level的层的偏移地址为adr的变量放到栈顶
					break;
				case procedur:				 
					error(21);				 //如果在因子处理中最到的标识符是过程名,抛出21号错误码
					break;
				}
			}
			getsym();  //获取下一个token,继续循环处理
		}
		else if(strcmp(sym,"number")==0) //当因子处理遇到数字时
		{
			if(num>AMAX)     //如果数字的大小超过允许最大值AMAX
			{
				error(31);	 //抛出31号错
				num=0;		 //把数字按0值处理
			}
			else
			{
				gen(lit,0,num);//生成lit指令,把这个数值字面常量放到栈顶
			    getsym();
			}
		}
		else if(strcmp(sym,"lparen")==0) //如果最到的是左括号
		{
			getsym();					 //获取下一个token
			expression(add(tp,fsys));    //递归调用expression子程序分析一个子表达式
			

			//子表达式分析完后,应最到右括号
			if(strcmp(sym,"rparen")==0)  //如果的确最到右括号
				getsym();                //读取下一个token
			else
				error(22);				 //否则抛出22号错误

		}

		test(fsys,facbegsys,23);         //一个因子处理完毕,最到的token应在fsys集合中
										 //如果不是,抛23号错误,并找到下一个因子的开始,使语法分析可以继续运行下去
	}
}//factor end


//项处理过程term

⌨️ 快捷键说明

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