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

📄 pl0.cpp

📁 pl0的编译程序源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "pl0.h"
#include <stdio.h>
#include <fstream>
#include <vector>
#include <string>
#include <iostream>


string PL0::errStr[]={" ","error 0001:  常数说明中“=”写成“:=”",//错误的数组,输出的错误就是从中查找得到。
	"error 0002:  常数说明中的“=”后应为数字",
	"error 0003:  常数说明中的标识符后应是“=”",
	"error 0004:  const,var,procedure后应为标识符",
	"error 0005:  漏掉了‘,’或‘;’",
	"error 0006:  过程说明后的符号不正确(应是语句开始符或过程开始符)",
	"error 0007:  应是语句开始符",
	"error 0008:  过程体内语句部分的后跟符不正确",
	"error 0009:  程序皆为丢了句号‘.’",
	"error 0010:  语句之间漏了‘;’",
	"error 0011:  标识符没说明",
	"error 0012:  赋值语句中,赋值号左部标识符属性应是变量",
	"error 0013:  赋值语句左部标识符应是赋值号:=",
	"error 0014:  call后应为标识符",
	"error 0015:  call后标识符属性应为过程",
	"error 0016:  条件语句中丢了then",
	"error 0017:  丢了end或;",
	"error 0018:  while型循环语句中丢了do",
	"error 0019:  语句后的标识符不正确",
	"error 0020:  应为关系运算符",
	"error 0021:  表达式内标识符属性不能是过程",
	"error 0022:  表达式中漏掉了右括号‘)’",
	"error 0023:  因子后的非法符号",
	"error 0024:  表达式开始符不能是此符号",
	"error 0025:  文件在不该结束的地方结束了",
	"error 0026:  结束符出现在不该结束的地方",
	"error 0027:  ","error 0028:  ","error 0029:  ","error 0030:  ",
	"error 0031:  数越界",
	"error 0032:  read语句括号中标识符不是变量"};

PL0::PL0(char* source,char*destination)//构造函数,用与初始化
{
	listswitch=true,sourceEnd=false;
	strcpy(word[1],"begin");//设置保留字名字
	strcpy(word[2],"call");
	strcpy(word[3],"const");
	strcpy(word[4],"do");
	strcpy(word[5],"end");
	strcpy(word[6],"if");
	strcpy(word[7],"odd");
	strcpy(word[8],"procedure");
	strcpy(word[9],"read");
	strcpy(word[10],"then");
	strcpy(word[11],"var");
	strcpy(word[12],"while");
	strcpy(word[13],"write");
	wsym[1]= BEGINSYM;   wsym[2]=CALLSYM;//设置保留字符号
	wsym[3]= CONSTSYM;   wsym[4]=DOSYM;
	wsym[5]=ENDSYM;     wsym[6]=IFSYM;
	wsym[7]=ODDSYM;     wsym[8]=PROCSYM;
	wsym[9]=READSYM;	wsym[10]=THENSYM;
	wsym[11]=VARSYM;    wsym[12]=WHILESYM;
	wsym[13]=WRITESYM;
	memset(code,0,sizeof(code));
	memset(ssym,0,100*sizeof(symbol));
	memset(table,0,sizeof(table));
	memset(line,0,sizeof(line));
	ssym['+']= PLUS;//设置单字符符号
	ssym['-']= MINUS;
	ssym['*']= TIMES;
	ssym['/']= SLASH;
	ssym['(']= LPAREN;
	ssym[')']= RPAREN;
	ssym['=']= EQL;
	ssym[',']= COMMA;
	ssym['.']= PERIOD;
	ssym['#']= NEQ;
	ssym['<']= LSS;
	ssym['>']= GTR;
	ssym[';']= SEMICOLON;
	strcpy(mnemonic[LIT]," lit ");//设置指令名称
	strcpy(mnemonic[OPR]," opr ");
	strcpy(mnemonic[LOD]," lod ");
	strcpy(mnemonic[STO]," sto ");
	strcpy(mnemonic[CAL]," cal ");
	strcpy(mnemonic[INT]," int ");
	strcpy(mnemonic[JMP]," jmp ");
	strcpy(mnemonic[JPC]," jpc ");
	declbegsys.insert(CONSTSYM),declbegsys.insert(VARSYM),declbegsys.insert(PROCSYM);//设置声明开始符号集
	statbegsys.insert(BEGINSYM),statbegsys.insert(CALLSYM),statbegsys.insert(IFSYM),statbegsys.insert(WHILESYM);//设置语句开始符号集
	facbegsys.insert(IDENT),facbegsys.insert(NUMBER),facbegsys.insert(LPAREN);//设置因子开始符号集
	err= 0;
	cc= 0;
	cx= 0;
	ll= 0;
	ch= ' ';
	kk= al;
	codeNo=0;
	fin=fopen(source,"r");
	fout=fopen(destination,"w");
}
void PL0::error(int n)//错误输出方法。
{
	char s[10];
	printf(s,"第 %d 行:",codeNo);
	errorString.push_back(s+errStr[n]+"\n");//将错误入栈。
	err= err+1;//错误计数自加
}//error结束
void PL0::getch()//供getsym取一个字符,每次读一行,存入line缓冲区,line被getsym取空时 再读一行
{
	if(cc==ll)
	{
		if(feof(fin))//如果已经取到文件尾的时候的一些动作
		{
			if(sym!=PERIOD)//PERIOD即是.--PL0的正常结束符。
				error(25);
			sourceEnd=true;
			return;
		}
		cc= 0;
		fgets(line,lineLength,fin);//从fin文件指针所指向的文件中读取lineLength长度的字符到字节数组line中。
		codeNo++;//行数指针自加
		ll=strlen(line);//计算出刚刚取到的line的字符数
	}
	ch= line[cc];//将取到的line存入ch中。
	cc= cc+1;//cc自加,为下一次将line存入ch做准备。
}
void PL0::getsym()
{
	if(sourceEnd)
		return;
	int i,j,k;
	while (ch ==' ')
		getch();//清除空格。
	if(isalpha(ch))//isalpha函数的功能是判断一个字符型变量,当变量为字母时返回值非零。
	{
		k=0;
		do{
			if (k < al)
			{
				a[k]= ch;
				k= k+1;
			}
			getch();
			if(sourceEnd)
				return;
		}while(isalpha(ch)||isdigit(ch));
		if(k >= kk)
			kk= k;//长度控制
		else
		{
			do{
				a[kk]= ' ';
				kk= kk-1;
			}while(kk > k);
		}//此前的代码实现的是如果取到的ch是字母或数字的话,进行关键字/标识符的取值.并存入a中
		strcpy(id,a);//将a赋值给id,为查找做准备。
		i= 1;//为下面的折半查找做准备。
		j= norw;//将关键字个数赋值给j,为以后的折半查找做准备。
		do{
			k= (i+j) / 2;
			if(strcmp(id, word[k])<=0)
				j= k-1;
			if(strcmp(id,word[k])>=0)
				i= k+1;
		}while(i<=j);
		if(i-1 > j)
			sym= wsym[k];
		else
			sym= IDENT;
	}//从此上12行中为折半查找word数组,以发现取到的是什么关键字,如果没查到就是标识符。
	else if(isdigit(ch))//数字
	{
		k= 0;
		num= 0;
		sym= NUMBER;//为数字类型
		do{
			num= 10 * num+ch-'0';//进行一位的取数,乘10是权值.
			k= k+1;
			getch();
		}while(isdigit(ch));
		if(k > nmax)//数字长度的限制即数字变量的上限
			error(30);
	}
	else if (ch == ':')
	{
		getch();
		if( ch== '=')
		{
			sym= BECOMES;
			getch();
		}
		else
			sym= NUL;//不能识别的符号。
	}
	else if(ch == '<')
	{
		getch();
		if (ch== '=')
		{
			sym= LEQ;
			getch();
		}
		else
			sym= LSS;
	}
	else if (ch == '>')
	{
		getch();
		if( ch == '=')
		{
			sym= GEQ;
			getch();
		}
		else
			sym= GTR;
	}
	else//当符号不满足上述条件时,全部按照单字符符号处理.
	{
		sym= ssym[ch];
		getch();
	}
}

void PL0::gen(fct x,int y,int z)//生成目标代码.
{
	if (cx > cxmax)//code数组的限制
	{
		cout<<"Program too long\n";
		return;
	}
	code[cx].f= x;
	code[cx].l= y;
	code[cx].a= z;
    cx= cx+1;
}//gen结束

void PL0::test(symset s1,symset s2,int n)/*在某一部分(如一条语句,一个表达式)将要结束时时我们希望下一个符号属于某集合(该部分的后跟
符号),test负责这项监测,并且负责当监测不通过时的补救措施,程序在需要检测时指定当前需要的符号集合和补救用的集合(如之前未完成部分的后跟
符号),以及检测不通过时的错误号*/
{
	if(sourceEnd)return;
	if (s1.find(sym)==s1.end())//如果没有查找到
	{
		error(n);
		symset::iterator it;//声明遍历对象it
		for(it=s2.begin();it!=s2.end();it++)
			s1.insert(*it);//s1=s1+s2
		while (s1.find(sym)==s1.end())
			getsym();//如果没找到则取关键字。
	}
}//test结束
void PL0::enter(obj0 k,int &tx,int &dx,int lev)//如分析表的方法
{
	tx= tx+1;//table指针自加。
	strcpy(table[tx].name,id);
	table[tx].kind=k;
	switch(k)//分析类型
	{
	case CONSTANT:
		if(num>amax)
		{
			error(31);
			num=0;
		}
		table[tx].other.val=num;
		break;
	case VARIABLE:
		table[tx].other.inOther.level=lev;
		table[tx].other.inOther.adr=dx;
		dx++;
		break;
	case PROCEDURE:
		table[tx].other.inOther.level=lev;
		break;
	}
}//enter结束

int PL0::position(alfa id,int tx)//在分析表中查找标识符和ID
{
	int i;
	strcpy(table[0].name, id);//“哨兵”位置,即顺序查找。
	i= tx;//从后向前查找。
	while (strcmp(table[i].name,id)!=0)i--;
	return i;
}//position结束。
void PL0::constdeclaration(int&tx,int&dx,int lev)//常量声明的处理方法。
{
	if(sym = IDENT)
	{
	  getsym();
	  if(sym>=EQL&&sym<=BECOMES)
	  {
		if( sym ==BECOMES)
			  error(1);
		getsym();
		if( sym == NUMBER)
		{
			enter(CONSTANT,tx,dx,lev);
			getsym();
		}
		else
		  error(2);
	  }
	  else
		error(3);
	}
	else
	  error(4);
}// constdeclaration结束

void PL0::vardeclaration(int&tx,int&dx,int lev)//变量声明的方法。
{
	if( sym == IDENT)
	{
		enter(VARIABLE,tx,dx,lev);
		getsym();
	}
	else
		error(4);
}//vardeclaration结束

void PL0::listcode(int cx0)//列出在语法分析中生成的中间代码
{
	int i;
	if(listswitch)
		for (i= cx0;i<cx;i++)
		   cout<<" "<<i<<"  "<<mnemonic[code[i].f]
			<<"  "<<code[i].l<<"  "<<code[i].a<<endl;
}// listcode结束
void PL0:: factor(symset fsys,int tx,int lev)//因子处理函数。
{
	int i;
	test(facbegsys,fsys,24);//查找因子开始符
	while(facbegsys.find(sym)!=facbegsys.end())
	{
		if( sym ==IDENT)
		{
			i= position(id,tx);
			if( i == 0)
				error(11);
			else
				switch(table[i].kind)
			{
			 case CONSTANT:
				 gen(LIT,0,table[i].other.val);
				 break;
			 case VARIABLE:
				 gen(LOD,lev-table[i].other.inOther.level,table[i].other.inOther.adr);//生成代码--将变量值取到栈顶,adr为偏移量,level为层差
				 break;
			 case PROCEDURE:
				 error(21);
				 break;
			}
			getsym();
		}
		else  if (sym ==NUMBER)
		{
			if (num>amax)
			{
				error(31);
				num= 0;
			}
			gen(LIT,0,num);//生成代码--将常数值取到栈顶,num为常数值
			getsym();
		}
		else if( sym ==LPAREN)
		{
			getsym();
			symset tmp=fsys;
			tmp.insert(RPAREN);
			expression(tmp,tx,lev);
			if (sym == RPAREN)
				getsym();
			else
				error(22);
		}
		test(fsys,facbegsys,23);
	}
}//factor结束
void PL0::term(symset fsys,int tx,int lev)//项的函数。
{
	if(sourceEnd)
		return;
	symset tmp=fsys;
	if(tmp=TIMES||t<=SLASH)
	factor(tmp,tx,lev);//当后续符号为乘号或者除号时调用因子分析,即<项>:=<乘法运算符><因子>的实现。
	while( sym>=TIMES && sym<=SLASH)
	{
		tmp= sym;
		getsym();
		if (tmp ==TIMES)
			gen(OPR,0,4);//生成代码--次栈顶乘以栈顶,退两个栈元素,结果值进栈
		else
			gen(OPR,0,5);//生成代码--次栈顶除以栈顶,退两个栈元素,结果值进栈
	}
}// term结束
void PL0::expression(symset fsys,int tx,int lev)//表达式的分析,参照项的分析
{
	symbol addop;
	symset tmp=fsys;
	if( sym>=PLUS&&sym<=MINUS)
	{
		addop= sym;
		getsym();
		term(tmp,tx,lev);
		if( addop ==MINUS)
			gen(OPR,0,1);//栈顶元素取反
	}
	else
		term(tmp,tx,lev);
	while (sym >=PLUS&&sym<=MINUS)
	{
		addop= sym;
		getsym();
		term(tmp,tx,lev);
		if (addop ==PLUS)
			gen(OPR,0,2);//次栈顶与栈顶相加,退两个栈元素,结果值进栈
		else
			gen(OPR,0,3);//次栈顶减去栈顶,退两个栈元素,结果值进栈
	}
}// expression结束
void PL0::condition(symset fsys,int tx,int lev)//条件分析,参照项的分析
{
	symbol relop;
	symset tmp=fsys;
	tmp.insert(EQL),tmp.insert(NEQ),tmp.insert(LSS),tmp.insert(LEQ),tmp.insert(GTR),tmp.insert(GEQ);
    if( sym ==ODDSYM)
	{
		getsym();
		expression(fsys,tx,lev);
		gen(OPR,0,6);//栈顶元素的奇偶判断,结果值在栈顶
	}
	else
	{
		expression(tmp,tx,lev);
		if(tmp.find(sym)==tmp.end())

⌨️ 快捷键说明

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