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

📄 pl0.java

📁 编译原理课程设计 PL0编译器 java版本
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
import  java.io.*;
import  java.lang.*;
import java.util.*;

/*错误号
0  ,"缺少左括号"
1   ,"非法字符:赋值符号:="
2  ,"等号后的字符为非法字符"
3   ,"缺少等号"
4   ,"声明过程中遇到的字符不是标识符"
5   ,"缺少分号"
6   ,"非法语句"
7   ,"整数大小越界"
8   ,"整数位数越界"
9   ,"缺少右括号"   
10   ,"语句和语句之间没有分号"
11  ,"标识符不存在"
12  ,"标识符不是变量名"
13   ,"缺少赋值符号"
14   ,"call后不是标识符"
15   ,"call后不是过程名"
16   ,"if后不是then"
17   ,"没有遇到end"
18   ,"while循环缺少do"
19   ,"标识符长度越界"
20   ,"缺少逻辑运算符"
21   ,"标识符为过程名"
22   ,"缺少右括号"

*/
public class  pl0//主程序
{
	public static void main(String [] args)
  {
  	String filename=" ";
  	new  pl0();//初始化一个PL0对象  
  	System.out.print("请输入PL源程序的文件名:");
  	try
  	{
  		InputStreamReader fin=new InputStreamReader(System.in);
  		BufferedReader br=new   BufferedReader(fin);
      filename=br.readLine();
  	}
  	catch(IOException e)
  	{
  		System.out.println("错误!请输入源程序文件名");
  	}
    //声明一个词法分析类,获得源程序的第一个词(token)
  	CiFaAnalyse Cifa=new CiFaAnalyse(filename);
  	YuFaAnalyse YuFa=new YuFaAnalyse(Cifa);
  	int  errorNumber=Cifa.getErroNumber()+YuFa.getErroNumber();
  	if(errorNumber==0)
  	{
  		YuFa.printCode();
  		System.out.println("错误总数为"+errorNumber);
  		YuFa.interpret();  		 
  	}
  	else {System.out.println("错误总数为"+errorNumber);}
  	//YuFa.printCode();
  	//YuFa.printName();
  	 	
  }
}
 class erro   //错误处理类
{
	String[] err={" 缺少左括号"
	 ,"非法字符:赋值符号:="
   ,"等号后的字符为非法字符"
   ,"缺少等号"
   ,"声明过程中遇到的字符不是标识符"
   ,"缺少分号"
   ,"非法语句"
   ,"整数大小越界"
   ,"整数位数越界"
   ,"缺少右括号"   
   ,"语句和语句之间没有分号"
   ,"标识符不存在"
   ,"标识符不是变量名"
   ,"缺少赋值符号"
   ,"call后不是标识符"
   ,"call后不是过程名"
   ,"if后不是then"
   ,"没有遇到end"
   ,"while循环缺少do"
   ,"标识符长度越界"
   ,"缺少逻辑运算符"
   ,"标识符为过程名"
   ,"缺少右括号"
               };
	erro(int linenumber,int t)
	{
		System.out.println("行:"+linenumber+"    错误号"+t+"  "+err[t]);
	}
}
 class nameClass  //用于表示符号类,存放于符号表中
{
	String name=null;
	String kind=null;
	int   val;
	int   level;
	int    adr;
	public nameClass(String a,String b,int c,int d,int e)
	{
		name=a;
		kind=b;
		val=c;
		level=d;
		adr=e;
	}
	public void setAdr(int cx0)
	{
		adr=cx0;
	}
	public int  getAdr()
	{
		return adr;
	}
	public  String getKind()
	{
		return  kind;
	}
	public  int   getVal()
	{
		return val;
	}
	public  String getNam()
	{
		return  name;
	}
	public int getLev()
	{
		return  level;
	}
}
 class pcode//pcode类  表示pcode指令
{
	String f=" ";//第一个参数:操作码
	int l;       //第二个参数:层次差
	int a;       //
	public pcode(String x,int y,int z)
	{
		f=x;
		l=y;
		a=z;
			
	}
	public  void  setA(int t)
	{
		a=t;
	}
	public String getF()
	{return f;}
	public int getL()
	{return l;}
	public int getA()
	{return a;}
}
 class token//声明一个类"token类”  用于存放读取的token单词
{
	private  String  sym="原来的";  //保存token的类型
	private  String  name="原来的";  //保存token的内容
	public  int  lineNum;
	token(String name1,String sym1)
	{
		name=name1;
		sym=sym1;
	}
	token(String name1,String sym1,int l)
	{
		name=name1;
		sym=sym1;
		lineNum=l;
	}
	public  void setLineNum(int l)
	{
		lineNum=l;
	}
	public int getLineNum()
	{return lineNum;}
	public  String  getNam()
	{
		return  name;
	}
	public  String  getSym()
	{
		return   sym;
	}
	
}
 class YuFaAnalyse //语法分析类
{
	public CiFaAnalyse  CiFa;
	public token  word;
	public String id=null;     //用于登录名字表时的token名字
	public int  lineNum;       //用于错误处理时的行数记录
	public int errorNumber=0;   //用于保存语法分析中的错误数目
	int cx;
	int cx0;
	int dx;
	int lev=-1;
	int errorNum=0;
  public int t=-1;         //堆栈顶指针
	final public int stacksize =500;
  public int p=0;            //下一条指令位置
  public int b=0;           //基地址指针
  public pcode i;         //指令
  public int []s=new int[501];
	Vector pcodeArray= new Vector(); ;   //生成一个vector矢量! // 此矢量用作存放pcode代码的数组
  Vector nameArray=new Vector();//生成一个存放矢量 作为名字表;
	public YuFaAnalyse(CiFaAnalyse CF)//语法分析构造函数
	{  
    CiFa=CF;//从主程序传入一个词法分析对象,将其赋给CiFa
		word=CiFa.GetToken();  //获得一个token
		analyse();           //然后调用分析程序
	}
	public  int  getErroNumber()
  {return errorNumber;}
	public void printCode()//pcode的显示方法,如果没有错误,则打印pcode代码
	{
	 for(int n=0;n<pcodeArray.size();n++)
		{
			pcode code=(pcode)pcodeArray.get(n);
			System.out.println(n+"  "+code.getF()+"   "+code.getL()+"   "+code.getA());
		}
	}
	public void analyse()
	{
		int tx0;      
		lev++;
		dx=3;
		tx0=nameArray.size();   //用tx0保存当前层的符号在符号表中的起始位置
		nameArray.addElement(new nameClass(" "," ",0,0,0));//在这里给符号表填加一个元素,否则下一条代码会运行出界
		((nameClass)nameArray.get(tx0)).setAdr(pcodeArray.size());//在上面加的那个元素里的私有字段adr里保存当前层代码的开始位置
		pcodeArray.addElement(new pcode("jmp",0,0)); //生成跳转指令  由于跳转位置未知 暂时添0
		while(word.getSym().equals("constsym")||word.getSym().equals("varsym")||word.getSym().equals("procsym"))
		{	
		  if(word.getSym().equals("constsym"))//常量处理
		  {
		  	word=CiFa.GetToken();
			  delcaration();            //调用常量声明,注意常量声明完毕时还要再次读取一个token
			  while(word.getSym().equals("comma"))//若在常量声明后读取的token为逗号,则要继续进行常量声明,这里采用while循环,直到token不是逗号
			  {
				  word=CiFa.GetToken();
			    delcaration();          //调用常量声明,注意常量声明完毕时还要再次读取一个token
			  }
			  if(word.getSym().equals("semicolon"))//若token不是逗号,则应该是分号了,标志常量声明结束
			  {
				  word=CiFa.GetToken();
			  }
			  else
			  {
				  errorNumber++;new erro(word.getLineNum(),5);//如果常量声明完毕后没有遇到分号;则抛出15号错误
			  }
		   }
		//变量处理
		else if(word.getSym().equals("varsym"))
		{
			word=CiFa.GetToken();//读取一个token,应该是一个ident标识符
			vardeclaration();        //调用变量声明,注意常量声明完毕时还要再次读取一个token
			while(word.getSym().equals("comma"))
			{
				word=CiFa.GetToken();
				vardeclaration();       //调用变量声明,注意常量声明完毕时还要再次读取一个token
			}
			if(word.getSym().equals("semicolon"))
			{
				word=CiFa.GetToken();
			}
			else
			{
				errorNumber++;new erro(word.getLineNum(),5);//如果变量声明完毕后没有遇到分号;则调用错误处理程序抛出5号错误
			}
		}
		//循环声明各个子过程
		while(word.getSym().equals("procsym"))
		{
			word=CiFa.GetToken();
			if(word.getSym().equals("ident"))
			{
				id=word.getNam();
				enter("procedure");
				word=CiFa.GetToken();
			}
			else
			{
			  errorNumber++;new erro(word.getLineNum(),4);//过程名不是标识符,抛出4号错误 
			}
			if(word.getSym().equals("semicolon"))
			{
				word=CiFa.GetToken();
			}
			else  {errorNumber++;new erro(word.getLineNum(),5);}//过程名后没有分号
		//	System.out.println(dx);
		  int dxxxxx=dx;
		  int levv=lev;
			analyse();//在这里递归调用下一层的分程序段分析
			dx=dxxxxx;
			lev=levv;
		//	System.out.println(dx);                   
			if(word.getSym().equals("semicolon"))
			{
				word=CiFa.GetToken();
				//接下来是一段test程序   若end;后的符号不在ident,procsym,begin,call,if,while中,则调用6号错误
				String sym=word.getSym();
				if(!(sym.equals("ident")||sym.equals("procsym")||sym.equals("beginsym")||sym.equals("callsym")||sym.equals("ifsym")||sym.equals("while")))
				{
					errorNumber++;new erro(word.getLineNum(),6);
				}
			}
			else  { errorNumber++;new erro(word.getLineNum(),5);}
			//这儿也是有一段test程序   当前符号不在ident,begin,call,if,while中,则调用7号错误
		}
	}
		((pcode)pcodeArray.get(((nameClass)nameArray.get(tx0)).getAdr())).setA(pcodeArray.size());//把前面生成的跳转指令的跳转位置改成当天前位置
		((nameClass)nameArray.get(tx0)).setAdr(pcodeArray.size());//在符号表中,对于过程名,adr应填入编译该过程所生成的pcode指令序列的入口地址
		cx0=pcodeArray.size();//在cx0中保存当前代码的分配地址
		pcodeArray.addElement(new pcode("int",0,dx));//生成空间分配指令,分配dx个空间(3个空间+变量的数目)
	  statement1();//处理当前遇到的语句;
	  pcodeArray.addElement(new pcode("opr",0,0));//生成子程序返回指令;
	  
}
	public  void delcaration()    //常量声明的方法
	{
		if(word.getSym().equals("ident"))//在analyse调用常量声明时,上一个token为const,这一个应该是ident标识符
		{
			id=word.getNam();//调用token类的getNam方法,获得当前token的内容,这里将其保存在id中,为的是一会进行的符号表插入工作
			word=CiFa.GetToken();//然后再读取一个token,应该是等号"="了
			if(word.getSym().equals("becomes"))
			{
				errorNumber++;new erro(word.getLineNum(),1);//如果不是等号,而是赋值符号:=,抛出1号错误
			}
			else if(word.getSym().equals("eql"))		
			{
			word=CiFa.GetToken();//继续读取一个token,现在应该是一个数字了
			if(word.getSym().equals("number"))
			{
					enter("constant");//如果当前token是数字,则调用符号表插入方法,将常量插入符号表;
					word=CiFa.GetToken();//再次读取一个token,为后边做准备,应该是一个逗号或者是分号		    
		  }
			else// 如果等号后不是数字,调用2号错误
			{
				errorNumber++;new erro(word.getLineNum(),2);
			}
		  }
			else//如果标识符后不是等号,调用3号错误
			{ 

⌨️ 快捷键说明

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