实验内容要求
一、实验目的 加深对语法分析器工作过程的理解;加强对预测分析法实现语法分析程序的掌握;能够 采用一种编程语言实现简单的语法分析程序;能够使用自己编写的分析程序对简单的程序段 进行语法翻译。
二、实验内容 用预测分析法编制语法分析程序,语法分析程序的实现可以采用任何一种编程语言和工 具。
三、实验要求: 1. 对语法规则有明确的定义; 2. 编写的分析程序能够对测试用例进行正确的语法分析; 3. 对于遇到的语法错误,能够做出简单的错误处理,给出简单的错误提示,保证顺 利完成语法分析过程; 4. 实验报告要求用文法的形式对语法定义做出详细说明,说明语法分析程序的工作 过程,说明错误处理的实现。
四、实验步骤 1. 定义目标语言的语法规则; 2. 求解预测分析方法需要的符号集和分析表; 3. 依次读入测试用例,根据预测分析的方法进行语法分析,直到源程序结束; 4. 对遇到的语法错误做出错误处理。
实验步骤
设计一个主类用来进行文件的输入,和结果的输出;然后按照四步走的策略来创建相对于的类操作。
第一步:创建LeftRecursion类来消除左递归,获取原始的产生式、终结符、非终结符;消除左递归之后的产生式、终结符和非终结符。然后简化产生式,每一个产生式只包含一个候选式。
第二步:创建FirstAndFollow类来求FIRST集和FOLLOW集。
第三步:创建AnalyzeTable类来获取分析表。
第四步:创建LL1Stack类来对测试用例进行入栈操作求解结果。
为了完成以上的任务,还需要创建一个Grammar类保存数据。以上就是设计的主要方案。
- LL1 .java
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
/*
* 实验的主要方法:
* 1、消除左递归
* 1.1构造出终结符集、非终结符集
* 1.2把消除左递归得到的产生式进行简化,即一条产生式里面只有一个候选式
* 2、构造FIRST集和FOLLOW集
* 3、构造预测分析表
* 4、构造符号栈和输入串栈进行测试实例分析
* */
public class LL1 {
//原始的产生式
static ArrayList<String> expression;
//语法器
static Grammar grammar;
public static void main(String []args) throws FileNotFoundException {
grammar=new Grammar();
expression=new ArrayList<>();
//采用文件读入的方式
File file=new File("E:\\code\\bytest\\test11\\test4.txt");
try(Scanner input=new Scanner(file)) {
while (input.hasNextLine()){
String line=input.nextLine();
if (line.equals("")){
//采用空一行这种方式,下一行就是测试用例
grammar.setTestEx(input.nextLine());
break;
}else {
expression.add(line);
}
}
}
//消除左递归
LeftRecursion leftRecursion=new LeftRecursion();
leftRecursion.setExpression(expression);
leftRecursion.work();
//分别给语法器开始设置非终结符集、终结符集、文法开始符号、简化之后的产生式
grammar.setNa(leftRecursion.getNa());
grammar.setNt(leftRecursion.getNt());
grammar.setStart(leftRecursion.getStart());
grammar.setSimpleExpression(leftRecursion.getSimpleExpression());
System.out.println();
System.out.println("--------------------------------------------------");
System.out.println("消除左递归");
System.out.println();
System.out.println("产生式");
for(Map.Entry<Character, ArrayList<String>> entry : grammar.getSimpleExpression().entrySet()){
for (String s:entry.getValue()){
System.out.println(entry.getKey()+"->"+s);
}
}
System.out.println("--------------------------------------------------");
System.out.println("非终结符");
for (Character na:grammar.getNa().keySet()){
System.out.printf("%-10c",na);
}
System.out.println();
System.out.println("--------------------------------------------------");
System.out.println("终结符");
for (Character nt:grammar.getNt().keySet()){
System.out.printf("%-10c",nt);
}
System.out.println();
System.out.println("--------------------------------------------------");
System.out.println("读取测试用例");
System.out.println(grammar.getTestEx());
//开始构造FIRST集和FOLLOW集
FirstAndFollow firstAndFollow=new FirstAndFollow(grammar);
firstAndFollow.work();
grammar.setFirst(firstAndFollow.getFirst());
grammar.setFollow(firstAndFollow.getFollow());
System.out.println("--------------------------------------------------");
System.out.println("FIRST集");
for (Character na:grammar.getNa().keySet()){
String FirstSet=grammar.getFirst().get(na).toString().replace("[","");
FirstSet=FirstSet.replace("]","");
System.out.println("FIRST("+na+")={"+FirstSet+"}");
}
System.out.println("--------------------------------------------------");
System.out.println("FOLLOW集");
for (Character na:grammar.getNa().keySet()){
String FollowSet=grammar.getFollow().get(na).toString().replace("[","");
FollowSet=FollowSet.replace("]","");
System.out.println("FOLLOW("+na+")={"+FollowSet+"}");
}
//构造预测分析表
AnalyzeTable analyzeTable=new AnalyzeTable(grammar);
analyzeTable.work();
grammar.setAnalyzeTable(analyzeTable.getAnalyzeTable());
System.out.println("--------------------------------------------------");
System.out.println("预测分析表");
System.out.printf("%-11s","");
for (Character nt:grammar.getNt().keySet()){
if (nt!='ε') {
System.out.printf("%-10s", nt);
}
}
System.out.println();
for (Character na:grammar.getNa().keySet()){
System.out.printf("%-10s",na);
for (int i=1;i<=grammar.getNt().size();i++){
if(grammar.getAnalyzeTable()[grammar.getNa().get(na)][i]!=null){
System.out.printf("%-10s",na+"->"+ grammar.getAnalyzeTable()[grammar.getNa().get(na)][i]);
}else{
System.out.printf("%-10s","");
}
}
System.out.println("");
}
System.out.println("--------------------------------------------------");
System.out.println("预测分析步骤");
System.out.println();
//利用LL1开始测试测试用例
LL1Stack stack=new LL1Stack(grammar);
stack.work();
}
}
- Grammar.java
import java.util.*;
public class Grammar {
//非终结符
/*
* 这里解释一下为什么要采用Map,而不是采用Set,因为我觉得采用map方便生成预测分析表,可以利用键对应的值,找到产生式在
* 分析表中的位置。如 E->FA.要找到它在分析表中的位置,先要确定E在哪一行,直接判断FIRST(E)对应的符号所在哪一列,才可
* 以确定表达式的位置,这样也有利于最后的测试用例测试。
* */
private Map<Character,Integer> Na;
//终结符
private Map<Character,Integer> Nt;
//原始的产生式
private ArrayList<String> expression;
//简化之后的产生式
private Map<Character,ArrayList<String>> simpleExpression;
//开始符
private Character start;
//测试实例
private String testEx;
//分析表
private String[][] analyzeTable;
//first集
private Map<Character, HashSet<Character>> First;
//Follow集
private Map<Character, HashSet<Character>> Follow;
public Grammar() {
Na=new LinkedHashMap<>();
Nt=new LinkedHashMap<>();
simpleExpression=new LinkedHashMap<>();
Follow=new HashMap<>();
First=