实验2《预测分析法设计与实现》(java版)

目录

第1关: 实验2《预测分析法设计与实现》

任务描述

相关知识

自上而下的语法分析器

预测分析法

实验步骤

目标语言的语法规则

求解预测分析方法需要的符号集和分析表

编程要求

答案: 


第1关: 实验2《预测分析法设计与实现》

任务描述

本关任务:加深对语法分析器工作过程的理解;加强对预测分析法实现语法分析程序的掌握;能够采用一种编程语言实现简单的语法分析程序;能够使用自己编写的分析程序对简单的程序段进行语法翻译。

相关知识

为了完成本关任务,你需要掌握:用预测分析法编制语法分析程序。

自上而下的语法分析器

语法分析在编译中是一个重要的环节,语法分析可以分为自上而下分析和自下而上分析两种方式。

自上而下分析法是从文法开始符号开始,不断进行推导,直到推导所得的符号串与输入串相同为止。简单来解释这句话:我们有一个既定的文法,和一个需要分析的符号串。接下来我们从文法的开始符号出发,反复地使用文法规定的一些产生式匹配符号串的每一个符号,直到所得的符号串和待分析的符号串相同,则为分析成功,反之匹配不成功。

下面我们举例来进行说明: 我们有文法G(E)

E→aF
F→b|c 

以及待输入的字符 ab,从文法开始符号E出发,E→aFa匹配成功后,指针指向F,找非终结符F的产生式合适的候选式 b匹配,于是匹配成功。

想要对一个文法进行自上而下的分析,要消除文法的二义性,消除左递归,提取左公共因子,计算FIRST集合和FOLLOW集合,判断文法是否为LL(1)型文法,一个文法经过这些步骤,并且是LL(1)文法,则可以用LL(1)分析法的具体实现去分析。我们在后续的实验步骤中会进行该过程的一一实验。

预测分析法

预测分析法是LL(1)分析法的一种实现方法,它通过一张表来关联非终结符和终结符,这张表就是预测分析表,预测分析表可以说是预测分析法的核心部分。我们在进行该方法时,首先要构建预测分析表。

首先介绍一下预测分析表的结构,简单来说他就是一张表,表的两个属性分别是非终结符和终结符(包括‘#’),形如:

,


其中对应的内容是产生式的形式,若是没有产生式则可以写入标记来表示其匹配不到具体的产生式,进入报错处理程序。

在根据文法构造预测分析表时需要扫描全部产生式:

  1. 计算产生式的右部的FIRST集合,如果求出来的FIRST集合中包含终结符,那么就把这条产生式放入对应非终结符和终结符的格子中
  2. 如果εFIRST集合中,则计算该非终结符的FOLLOW集合,如果求出来的FOLLOW集合中包含终结符,那么就把这条产生式放入对应的非终结符和终结符的格子中

当预测分析表构造完成后,我们便可以运用预测分析法进行语法分析了。我们使用用一个栈来存放过程数据,主要步骤如下:

  1. 获取栈顶的元素A,获取输入串目前指针指向的元素a
  2. A = ‘#’ ,a = ‘#’ 则匹配成功
  3. A = a 但是Aa不为’#’,则pop栈顶元素,输入串指针+1
  4. A为非终结符,这查询预测分析表,把由Aa确定的产生式的右部从右往左依次压入到栈中,若右部是ε,那就不做操作
  5. 查找预测分析表得到预设的出错字符则调用error()
实验步骤

根据语法分析器的一般功能,我们的程序应具有如下的要求及实验步骤:

  1. 定义目标语言的语法规则;
  2. 求解预测分析方法需要的符号集和分析表;
  3. 依次读入测试用例,根据预测分析的方法进行语法分析,直到源程序结束;该部分具体见上。
  4. 对遇到的语法错误做出错误处理。

下面我们对步骤1,2进行说明。

目标语言的语法规则

该部分重点在于消除文法的二义性,消除左递归,提取左公共因子。想要让程序自动地消除左递归,具体的做法如下: 1.把文法的所有非终结符进行排序S = [‘A’,‘B’,…] 2.做一个嵌套循环: 其中S[k]为排在S[j]之后的非终结符,bunch_i为非终结符和终结符组成的串

for j in range(len(s)):
        for k in range(j):
            原产生式中:S[j]→S[k]bunch_1的S[k]用其对应的产生式代替
            S[k]→bunch_2|bunch_3|...
            推出:S[j]→bunch_2 bunch_1|bunch_3 bunch_1|...
            如此,做完循环后该文法若有间接左递归,就将其转换成直接左递归了
            消除直接左递归,具体做法见上文
循环结束后删除无用产生式 
求解预测分析方法需要的符号集和分析表

符号集主要是构造FIRST集和FOLLOW集,其主要目的是为了消除回溯,也就是选择候选式的时候能够更加准确,当然,这些集合在别的地方也有用处。

构造FIRST集: 扫描所有的产生式,对于每一个X,连续使用以下规则,直至每个集合的FIRST集合不再增大为止,每一遍扫描所有产生式如果有FIRST集合变化则重新扫描:

  1. 如果X是终结符,则FIRST(X) = {X}.
  2. 如果X是非终结符 ,且有产生式 X → a… 则把a加入到FIRST集合中. 若 X → ε也是其中一条产生式,则把ε也加入到FIRST集合中.
  3. 如果X是非终结符,且X → Y…是一条产生式,其中Y是非终结符,那么则把FIRST(Y) \ {ε}(即FIRST集合去除ε)加入到FIRST(X)中.

构造FOLLOW集: 扫描所有产生式.对于文法G的每一个非终结符A构造FOLLOW(A)可以连续使用以下规则,直至每一个FOLLOW集合不在增大为止:

  1. 对于文法的开始符号S,置#FOLLOW(S)中.
  2. 若有产生式 A → αBβ,其中αβ是非终结符和终结符构成的串,B为非终结符,则把FIRST(β) \ {ε}加入到FOLLOW(B)中.
  3. 若有产生式 A → αB 或 A → αBβ,ε∈FIRST(β) ,则把FOLLOW(A)加入到FOLLOW(B)中.

分析表的构成见上所述。

 

编程要求

根据提示,在右侧编辑器Begin和End之间依次完成划分产生式、消除左递归、计算FIRST集、计算follow集、构建LL(1)分析表等代码,然后点击测评,运行程序,进行结果对比。

答案: 
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class ex2 {
	//非终结符集
	static List<String> noTerminal = new ArrayList<>();
	//终结符集
	static List<String> terminal = new ArrayList<>();
	//语法规则存储
	static String[][] grammarRules;
	//消除左递归后语法规则存储
	static String[][] grammar_rules;
	static String[][] newGrammer;
	//文法开始符号
	static String init;
	//FIRST集
	static String[][] firstSet;
	//FOLLOW集
	static String[][] followSet;
	//LL(1)分析表
	static int[][] analysis;
	
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		//读入非终结符
		//System.out.println("请输入非终结符: ");
		String noTer = new String("ETF");
		for (int i = 0; i < noTer.length(); i++){
			noTerminal.add(String.valueOf(noTer.charAt(i)));
		}
		//读入终结符
		terminal.add("#");
		//System.out.println("请输入终结符: ");
		String ter = new String("+*()i");
		for (int i = 0; i < ter.length(); i++){
			terminal.add(String.valueOf(ter.charAt(i)));
		}
		//初始化
		grammarRules = new String[noTer.length()][2];
		grammar_rules = new String[noTer.length() * 2][2];
		newGrammer = new String[noTerminal.size() * 5][3];
		//输入语法规则
		//System.out.println("请输入语法规则:");
		String grammar = new String("E->E+T|T");
		init = String.valueOf(grammar.charAt(0));
		divide(grammar);
		eliminate(grammar);
		
		String grammar1 = new String("T->T*F|F");
		divide(grammar1);
		eliminate(grammar1);
		
		String grammar2 = new String("F->(E)|i");
		divide(grammar2);
		eliminate(grammar2);
		//请输入测试用例
		System.out.println("请输入测试用例:");
		String test = input.nextLine();
		//输出信息
		System.out.println("------------------基本信息-----------------------");
		System.out.println("产生式:");
		output(grammarRules);
		System.out.println("终结符:");
		for (int i = 0; i < terminal.size(); i++){
			System.out.print(terminal.get(i) + "     ");
		}
		System.out.println();
		System.out.println("非终结符:");
		for (int i = 0; i < noTerminal.size(); i++){
			System.out.print(noTerminal.get(i) + "     ");
		}
		System.out.println();
		System.out.println("读取测试:");
		System.out.println(test);
		System.out.println("-------------------消除左递归---------------------");
		System.out.println("产生式:");
		output(grammar_rules);
		System.out.println("----------------FIRST集和FOLLOW集-----------------");
		firstSet = new String[noTerminal.size()][terminal.size()];
		for (int i = 0; i < noTerminal.size(); i++){
			first(noTerminal.get(i));
			System.out.print("FIRST(" + noTerminal.get(i) + ") = " );
			for (int j = 0; j < terminal.size(); j++){
				if (firstSet[i][j] != null){
					System.out.print(firstSet[i][j] + " ");
				}
			}
			System.out.println();
		}
		followSet = new String[noTerminal.size()][terminal.size()];
		for (int i = 0; i < noTerminal.size(); i++){
			follow(noTerminal.get(i));
			System.out.print("FOLLOW(" + noTerminal.get(i) + ") = ");
			for (int j = 0; j < terminal.size(); j++){
				if (followSet[i][j] != null){
					System.out.print(followSet[i][j] + " ");
				}
			}
			System.out.println();
		}
		System.out.println("----------------LL(1)分析表-----------------");
		analysis = new int[noTerminal.size()][terminal.size()];
		table();
		System.out.print("      ");
		for (int i = 0; i < terminal.size(); i++){
			System.out.print(terminal.get(i) + "     ");
		}
		System.out.println();
		for (int i = 0; i < noTerminal.size(); i++){
			System.out.print(noTerminal.get(i) + "     ");
			for (int j = 0; j < terminal.size(); j++){
				if (analysis[i][j] != 0) {
					System.out.print(analysis[i][j] + "     ");
				}else{
					System.out.print("      ");
				}
			}
			System.out.println();
		}
		System.out.println("--------------------分析栈-------------------");
		System.out.println(String.format("%-10s","分析栈") + String.format("%-10s","剩余字符串"));
		analysisStack(test);
	}
	
	/********Beign********/
	/*** 划分出产生式*/
	static void divide(String grammar){
		int st=grammar.indexOf("|");
		int flag=grammar.indexOf(">");
		String str=String.valueOf(grammar.charAt(0));
		grammarRules[noTerminal.indexOf(str)][0]=grammar.substring(flag+1,st);
		grammarRules[noTerminal.indexOf(str)][1]=grammar.substring(st+1);
	}
	/********End********/
	
	/********Beign********/
	/*** 消除左递归*/
	static void eliminate(String grammar){
		int st=grammar.indexOf("|");
		int flag=grammar.indexOf(">");
		if(grammar.charAt(0)==grammar.charAt(flag+1)){
			String str=String.valueOf(Character.toLowerCase(grammar.charAt(0)));
			noTerminal.add(str);
			if(!terminal.contains("-")){
				terminal.add("-");
			}
			String s="";
			for(int i=flag;i<grammar.length();i++){
				s=String.valueOf(grammar.charAt(i));
				flag=terminal.indexOf(s);
				if(flag!=-1){
					flag=grammar.indexOf(s);
					break;
				}
			}
			s=s+grammar.substring(flag+1,st)+str;
			grammar_rules[noTerminal.indexOf(str)][0]=s;
			grammar_rules[noTerminal.indexOf(str)][1]="-";
			grammar_rules[noTerminal.indexOf(String.valueOf(grammar.charAt(0)))][0]=grammar.substring(st+1)+str;
		}else{
			grammar_rules[noTerminal.indexOf(String.valueOf(grammar.charAt(0)))][0]=grammarRules[noTerminal.indexOf(String.valueOf(grammar.charAt(0)))][0];
			grammar_rules[noTerminal.indexOf(String.valueOf(grammar.charAt(0)))][1]=grammarRules[noTerminal.indexOf(String.valueOf(grammar.charAt(0)))][1];
		}
	}
	/********End********/
	
	/*** 输出产生式*/
	static void output(String[][] array){
		int k = 0;
		for (int i = 0; i < array.length; i++){
			for (int j = 0; j < array[i].length; j++){
				if (array[i][j] != null) {
					newGrammer[k][0] = String.valueOf(k+1);
					newGrammer[k][1] = noTerminal.get(i);
					newGrammer[k][2] = array[i][j];
					System.out.println(newGrammer[k][0] + "     " + newGrammer[k][1] + "     " + newGrammer[k][2]);
					k++;
				}
			}
		}
	}
	
	/********Beign********/
	/*** 计算FIRST集*/
	static void first(String noTer){
		int flag=noTerminal.indexOf(noTer);
		for(int i=0;i<2;i++){
			if(grammar_rules[flag][i]!=null){
				String str=grammar_rules[flag][i];
				String s=String.valueOf(str.charAt(0));
				if(noTerminal.contains(s)){
					first(s);
					for(int j=0;j<terminal.size();j++){
						int t=noTerminal.indexOf(s);
						if(firstSet[t][j]!=null){
							firstSet[flag][j]=firstSet[t][j];
						}
					}
				}else{
					firstSet[flag][terminal.indexOf(s)]=String.valueOf(str.charAt(0));
				}
			}
		}
	}
	/********End********/
	
	/********Beign********/
	/*** 计算follow集*/
	static void follow(String noTer){
		for(int i=0;i<noTerminal.size();i++){
			for(int j=0;j<2;j++){
				if(grammar_rules[i][j]!=null){
					String str=grammar_rules[i][j];
					if(noTer.equals(init)){
						followSet[noTerminal.indexOf(init)][terminal.indexOf("#")]="#";
					}
					int index=str.indexOf(noTer);
					if(index!=-1&&index!=str.length()-1){
						String ch=String.valueOf(str.charAt(index+1));
						if(noTerminal.contains(ch)){
							for(int k=0;k<terminal.size();k++){
								if(firstSet[noTerminal.indexOf(ch)][k]!=null&&!firstSet[noTerminal.indexOf(ch)][k].equals("-")){
									followSet[noTerminal.indexOf(noTer)][k]=firstSet[noTerminal.indexOf(ch)][k];
									for(int l=0;l<terminal.size();l++){
										if(followSet[i][l]!=null){
											followSet[noTerminal.indexOf(noTer)][l]=followSet[i][l];
										}
									}
								}
							}
						}else{
							followSet[noTerminal.indexOf(noTer)][terminal.indexOf(ch)]=ch;
						}
					}else if(index>0&&index==str.length()-1){
						if(!noTerminal.get(i).equals(noTer)){
							follow(noTerminal.get(i));
							for(int k=0;k<terminal.size();k++){
								if(followSet[i][k]!=null){
									followSet[noTerminal.indexOf(noTer)][k]=followSet[i][k];
								}
							}
						}
					}
				}
			}
		}
	}
	/********End********/
	
	/********Beign********/
	/*** 构建LL(1)分析表*/
	static void table(){
		int index=0;
		for(int i=0;i<noTerminal.size();i++){
			int num=0,t=0;
			int []flag=new int[terminal.size()];
			for(int j=index;j<newGrammer.length;j++){
				if(newGrammer[index][1].equals(newGrammer[j][1])){
					flag[t]=Integer.valueOf(newGrammer[j][0]);
					num++;
					t++;
				}
			}
			index+=num;
			if(num==1){
				for(int j=0;j<firstSet[i].length;j++){
					if(firstSet[i][j]!=null){
						analysis[i][j]=flag[0];
					}
				}
			}else{
				t=0;
				for(int j =0;j<firstSet[i].length;j++){
					if(firstSet[i][j]!=null){
						if(!firstSet[i][j].equals("-")){
							analysis[i][j]=flag[t];
							t++;
						}else{
							for(int k=0;k<followSet[i].length;k++){
								if(followSet[i][k]!=null){
									analysis[i][k]=flag[t];
								}
							}
						}
					}
				}
			}
		}
	}
	/********End********/
	
	/*** 输出分析栈*/
	static void analysisStack(String test){
		List<String> stack = new ArrayList<>();
		stack.add("#");
		stack.add("E");
		String outStack = test + "#";
		boolean flag = true;
		while (flag){
			String inStack = "";
			for (int i = 0; i < stack.size(); i++){
				inStack = inStack + stack.get(i);
			}
			System.out.println(String.format("%-10s",inStack) + String.format("%-10s",outStack));
			String NT = stack.get(stack.size()-1);
			String T = String.valueOf(outStack.charAt(0));
			if (NT.equals(T) && NT.equals("#")){
				System.out.println("分析成功");
				break;
			} else if (NT.equals(T)){
				stack.remove(stack.size()-1);
				outStack = outStack.substring(1);
			} else {
				if (analysis[noTerminal.indexOf(NT)][terminal.indexOf(T)] > 0){
					int num = analysis[noTerminal.indexOf(NT)][terminal.indexOf(T)];
					String s = newGrammer[num-1][2];
					stack.remove(stack.size()-1);
					for (int i = s.length()-1; i >= 0; i--){
						if (!s.equals("-")) {
							stack.add(String.valueOf(s.charAt(i)));
						}
					}
				}else {
					System.out.println("ERROR: 分析出错");
				}
			}
		}
	}
}
  • 20
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
实验旨在让学生通过实现预测分析法,加深对于语法分析的理解和掌握。 ## 实验要求 1. 学习预测分析法的原理和算法; 2. 实现预测分析法的代码; 3. 使用所实现的代码对给定的文法进行语法分析,并输出语法树或语法分析结果; 4. 对所实现预测分析法做出必要的优化。 ## 实验内容 ### 1. 预测分析法 预测分析法是一种自顶向下的语法分析方法,它的本质是根据给定的文法,构建出预测分析表,然后根据该表进行语法分析。 在构建预测分析表时,需要分析每个非终结符号的产生式,确定其可以推导出的终结符号,以及在遇到该非终结符号时应该选择哪个产生式。这个过程中,需要用到First集和Follow集。 First集:对于文法符号串而言,它所能推导出的终结符号串的首符号集合。 Follow集:对于文法的每个非终结符号而言,它所能推导出的终结符号串的后继符号集合。 预测分析表:对于每个非终结符号A和每个终结符号a,表格中的元素M[A,a]包含A可以推导出的所有产生式中,右部符号串的First集合中包含a的那些产生式的编号。 构建预测分析表的算法如下: 1. 将预测分析表初始化为空; 2. 对于每个产生式A→α,找到First(α)中所有元素a,将M[A,a]中填入该产生式的编号; 3. 如果ε∈First(α),则对于任何终结符号b∈Follow(A),令M[A,b]中填入该产生式的编号; 4. 重复以上两个步骤,直到预测分析表不再改变。 预测分析过程如下: 1. 首先将待分析串和分析栈初始化; 2. 每次从分析栈的栈顶取出一个符号,如果它是终结符号,则将待分析串中的第一个符号与之比较,如果相同,则将待分析串中的第一个符号弹出,并将分析栈顶的符号也弹出,继续下一次分析; 3. 如果栈顶符号是非终结符号,则在预测分析表中查找该非终结符号和待分析串中第一个符号的交点,如果该交点为空,则出错;否则,将该交点所对应的产生式中的符号逆序压入分析栈中; 4. 重复以上两个步骤,直到分析完成或出错。 ### 2. 实现预测分析法的代码 请根据上述算法实现预测分析法的代码。 ### 3. 使用所实现的代码对给定的文法进行语法分析,并输出语法树或语法分析结果 请使用所实现的代码,对如下文法进行语法分析,并输出语法树或语法分析结果。 ``` E → T E' E' → + T E' | ε T → F T' T' → * F T' | ε F → ( E ) | id ``` ### 4. 对所实现预测分析法做出必要的优化 请分析所实现预测分析法存在的问题,进行必要的优化。并给出分析和优化的代码实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星与星熙.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值