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

📄 yufaanalyse.java

📁 tiger编译器的驱动程序的描述 tiger编译器的驱动程序的描述
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
package ecust.edu.cn.pl0;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Vector;

public 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());
		}
	}

	// 分程序分析,相当于block()
	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号错误
			{
				errorNumber++;
				new erro(word.getLineNum(), 3);
			}
		} else// 如果常量声明过程中遇到的第一个字符不是标识符,调用4号错误
		{
			errorNumber++;
			new erro(word.getLineNum(), 4);
		}
	}

	public void vardeclaration() // 变量声明的方法
	{
		if (word.getSym().equals("ident")) {
			id = word.getNam();
			enter("variable");// 调用符号表注册方法 进行变量的注册
			word = CiFa.GetToken();
		} else// 如果变量声明过程中遇到的第一个字符不是标识符,调用4号错误
		{
			errorNumber++;
			new erro(word.getLineNum(), 4);
		}
	}

	public void enter(String k) // 注册符号表
	{ // k中保存的是传过来的 string
		if (k.equals("constant")) {// 如果是常量,则要判断此常量的赋值是否大于整数的最大允许值2047
			int num = Integer.parseInt(word.getNam());
			if (num > 2047) {
				nameArray.addElement(new nameClass(id, k, 0, 0, 0));
				new erro(word.getLineNum(), 31);// 若整数越界,抛出31号错误,并将其赋为0,继续进行分析
			} else
				// 若整数没有越界,则给nameArray增加一个nameClass对象
				nameArray.addElement(new nameClass(id, k, num, 0, 0));
		} else if (k.equals("variable")) {
			nameArray.addElement(new nameClass(id, k, 0, lev, dx));
			dx = dx + 1;
		} else if (k.equals("procedure")) {
			nameArray.addElement(new nameClass(id, k, 0, lev, 0));
		}
	}// 符号表注册完成

	public int position(String id) // 查找符号表
	{
		int i = 0;
		while (i < nameArray.size()
				&& (!((nameClass) nameArray.get(i)).getNam().equals(id))) {
			i++;
		}
		if (i >= nameArray.size()) {
			return -1;
		}// 如果没有找到,则返回负值
		else {
			return i;
		}
	}

	public void statement1()// 语句的分析处理
	{
		int i;
		int cx1;
		int cx2;
		if (word.getSym().equals("ident")) // 所谓语句可能是赋值语句,以标识符开头;
		{
			i = position(word.getNam()); // 在符号表中找到该标识符所在位置;
			if (i == -1) // 如果返回的i为负值,则表示没有找到;抛出11号错误
			{
				errorNumber++;
				new erro(word.getLineNum(), 11);
			} else if (!((nameClass) nameArray.get(i)).getKind().equals(
					"variable"))// 如果在符号表中找到了,但是该标识符不是变量名,则抛出12号错误
			{
				errorNumber++;
				new erro(word.getLineNum(), 12);
				i = -1;// 并将i置为-1做为错误的标志;
			}
			word = CiFa.GetToken(); // 继续读取下一个token,正常应该是赋值符号
			if (word.getSym().equals("becomes")) {
				word = CiFa.GetToken();// 如果是赋值符号,则继续读取一个token,正常应该是一个表达式;
			} else {
				errorNumber++;
				new erro(word.getLineNum(), 13);// 如果不是赋值符号,则抛出13号错误
			}
			expression(); // 进行表达式的处理;
			if (i != -1)// 如果i不是负值,则表示未曾出错,i所表示的是当前语句左边标识符在符号表中的位置;
			{// 生成一条把表达式的值写往指定内存的代码;
				pcodeArray.addElement(new pcode("sto", lev
						- ((nameClass) nameArray.get(i)).getLev(),
						((nameClass) nameArray.get(i)).getAdr()));
			}
		} else if (word.getSym().equals("callsym"))// 如果遇到了call语句
		{
			word = CiFa.GetToken();// 读取一个token,正常应该是一个过程名型的标识符
			if (!word.getSym().equals("ident"))// 如果不是标识符,抛出14号错误
			{
				errorNumber++;
				new erro(word.getLineNum(), 14);
			} else {
				i = position(word.getNam());// 查找符号表
				if (i == -1) {
					errorNumber++;
					new erro(word.getLineNum(), 11);
				}// 如果没有找到,抛出11号错误
				else if (((nameClass) nameArray.get(i)).getKind().equals(
						"procedure")) {// 生成call指令,call这个过程
					pcodeArray.addElement(new pcode("cal", lev
							- ((nameClass) nameArray.get(i)).getLev(),
							((nameClass) nameArray.get(i + 1)).getAdr()));
				} else {
					errorNumber++;
					new erro(word.getLineNum(), 15);
				}// 如果找到的不是过程名,抛出15号错误
				word = CiFa.GetToken();
			}
		} else if (word.getSym().equals("ifsym"))// 如果是if语句
		{
			word = CiFa.GetToken();// if后正常是条件,所以执行condition函数
			condition();
			if (word.getSym().equals("thensym")) {
				word = CiFa.GetToken();
			} else {
				errorNumber++;
				new erro(word.getLineNum(), 16);
			}// 如果if后不是then 则抛出16号错误!
			cx = pcodeArray.size();
			cx1 = cx;
			pcodeArray.addElement(new pcode("jpc", 0, 0));
			statement1();
			((pcode) pcodeArray.get(cx1)).setA(pcodeArray.size());

		} else if (word.getSym().equals("beginsym")) {
			word = CiFa.GetToken();
			statement1();
			while (word.getSym().equals("semicolon")
					|| word.getSym().equals("beginsym")
					|| word.getSym().equals("callsym")
					|| word.getSym().equals("ifsym")
					|| word.getSym().equals("whilesym")) {
				if (word.getSym().equals("semicolon")) {
					word = CiFa.GetToken();
				} else {
					errorNumber++;
					new erro(word.getLineNum(), 10);
				}
				statement1();
			}
			if (word.getSym().equals("endsym")) {
				word = CiFa.GetToken();
			} else {
				errorNumber++;
				new erro(word.getLineNum(), 17);
			}
		} else if (word.getSym().equals("whilesym")) {
			cx = pcodeArray.size();
			cx1 = cx;// 记录当前代码分配位置,这是while循环的开始位置
			word = CiFa.GetToken();// 读取token,应该是一个条件表达式
			condition();
			cx = pcodeArray.size();
			cx2 = cx;// 记录当天代码位置,这是while循环的do中的语句的开始位置
			pcodeArray.addElement(new pcode("jpc", 0, 0));// 生成条件跳转指令,跳转位置暂时填0
			if (word.getSym().equals("dosym"))// 判断是否是do,否则抛出18号错误
			{
				word = CiFa.GetToken();
			} else {
				errorNumber++;
				new erro(word.getLineNum(), 18);
			}
			statement1();// 开始分析do后的语句块
			pcodeArray.addElement(new pcode("jmp", 0, cx1));// 跳转到cx1处,即再次进行判断是否进行循环
			((pcode) pcodeArray.get(cx2)).setA(pcodeArray.size());// 把刚才跳转暂时填0的位置改成当前位置,完成对循环的处理
		} else if (word.getSym().equals("readsym")) {
			word = CiFa.GetToken();// 如果遇到了“读”语句块,则继续读取token,应该是左括号
			if (word.getSym().equals("lparen")) {
				word = CiFa.GetToken();
				if (word.getSym().equals("ident")) {
					i = position(word.getNam());
					if (i == -1) {
						errorNumber++;
						new erro(word.getLineNum(), 11);
					} else {
						pcodeArray.addElement(new pcode("opr", 0, 16));// 生成16号读指令,从键盘读取数字
						pcodeArray.addElement(new pcode("sto", lev
								- ((nameClass) nameArray.get(i)).getLev(),
								((nameClass) nameArray.get(i)).getAdr()));// 生成sto指令,存入指定变量
					}
				}
				word = CiFa.GetToken();

⌨️ 快捷键说明

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