实现预测分析法的原理其实很简答,步骤如下:
1.判断文法有没有左递归,若有左递归,则对该文法消除左递归
2.对处理后的文法进行遍历,求出终结符号和非终结符号
3.求出first集合和follow集合
4.判断是不是LL(1)文法,若是,则构建预测分表
5.若是LL(1)文法,输入一个句子,模拟输出进栈出栈情况
截图如下:
代码如下:
package cn.mahui;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
public class Function {
public static List
public static List
/**
* 从指定文件中读取文法
* @param path(文件的路径)
* @return
* @throws IOException
*/
public static String readGrammarFile(String path) throws IOException{
StringBuilder grammar=new StringBuilder();
File file=new File(path);
@SuppressWarnings("resource")
BufferedReader bufferedReader=new BufferedReader(new FileReader(file));
String readline;
while((readline=bufferedReader.readLine())!=null){
grammar.append(readline+"\n");
}
return grammar.toString();
}
/**
* 获得文法的产生式
* @param scanner(输入的文法)
* @return
*/
public static List
List
String[] grammarItems=scanner.split(" |\n");
for(int i=0;i
}
return oldList;
}
/**
* 获得每一条产生式
* @param scanner(输入的文法)
* @return
*/
public static List
List
List
String[] grammarItems=scanner.split(" |\n");
for(int i=0;i
String[] items=grammarItems[i].split(">|\\|");
//添加每一条产生式
for(int k=1;k
}
return oldListItems;
}
/**
* 如果vn包含str,则返回真,不包含返回false
* @param vn
* @param ch(要判断的字符串)
* @return
*/
public static boolean isContain(List
for(int i=0;i
return true;
}
}
return false;
}
/**
* 获得所有非终结符
* @param grammarItem(输入的文法)
* @return
*/
public static List
List
String[] string=grammarItems.split("\n");
for(int i=0;i
String str=string[i].substring(0, index);
if(vn.size()==0){
vn.add(str);
}else{
if(!isContain(vn, str)){
vn.add(str);
}
}
}
return vn;
}
/**
* 消除文法的左递归
* @param oldListItems(未消除左递归的每一台产生式的集合)
* @return
*/
public static List
List
for(int i=0;i
for(int j=0;j
&&oldListItems.get(j).length()==5){
newList.add(oldListItems.get(i).charAt(0)+"-->"+oldListItems.get(j).charAt(4)+oldListItems.get(i).charAt(0)+"’");
newList.add(oldListItems.get(i).charAt(0)+"’"+"-->"+oldListItems.get(i).substring(5, oldListItems.get(i).length())+oldListItems.get(i).charAt(0)+"’");
//~代表空
newList.add(oldListItems.get(i).charAt(0)+"’"+"-->"+"~");
}
}
}else{
int tag=0;
for(int k=0;k
tag=1;
break;
}
}
if(tag==0){
newList.add(oldListItems.get(i));
}
}
}
return newList;
}
/**
* 获得非终结符号的first集合
* @param vn(非终结符号的集合)
* @param newList( 消除左递归后的文法)
* @return
*/
public static Map
Map
for(int i=0;i
getOneFirst(vn.get(i),newList);
List
for(int k=0;k
}
firstList.put(vn.get(i), temp);
}
return firstList;
}
/**
* 得到任意一个非终结符号的first集合
* @param vnItem(任意一个非终结符号)
* @param newList(消除左递归后的文法)
* @return
*/
public static void getOneFirst(String vnItem,List
for(int i=0;i
if(newList.get(i).startsWith(vnItem)&&newList.get(i).charAt(1)=='-'){
int index=newList.get(i).indexOf('>')+1;
if(Character.isUpperCase(newList.get(i).charAt(index))){
getOneFirst(""+newList.get(i).charAt(index),newList);
}else{
if(!isContain(oneFirstList,""+newList.get(i).charAt(index))){
oneFirstList.add(""+newList.get(i).charAt(index));
}
}
}
}else{
if(newList.get(i).startsWith(vnItem)){
int index=newList.get(i).indexOf('>')+1;
if(Character.isUpperCase(newList.get(i).charAt(index))){
getOneFirst(""+newList.get(i).charAt(index),newList);
}else{
if(!isContain(oneFirstList,""+newList.get(i).charAt(index))){
oneFirstList.add(""+newList.get(i).charAt(index));
}
}
}
}
}
}
/**
* 获得任意一个非终结符号的follow集合
* @param vnItem(任意的一个非终结符号)
* @param vn(终结符号的集合)
* @param newList(消除左递归后的文法)
* @param firstList(所有非终结符号的first集合)
* @return
*/
public static void getOneFollow(String vnItem,List
//求follow集合的第一条
if(vnItem.equals(vn.get(0))){
if(!isContain(oneFollowList,"#")){
oneFollowList.add("#");
}
}
//求follow集合的第二条
for(int i=0;i
String str=newList.get(i).substring(index1);
if(vnItem.length()==1){
//判断E类型的
if(str.contains(vnItem)&&str.charAt(str.indexOf(vnItem.charAt(0))+1)!='’'){
if(str.indexOf(vnItem.charAt(0))!=str.length()){
String temp=str.substring(str.indexOf(vnItem.charAt(0))+1);
StringBuilder stringBuilder=new StringBuilder();
stringBuilder.append(temp);
for(int k=stringBuilder.length();k>1;k--){
if(isVN(stringBuilder.toString(),vn)){
break;
}else{
int length=stringBuilder.length();
stringBuilder.deleteCharAt(length-1);
}
}
if(stringBuilder.length()>0){
if(Character.isUpperCase(stringBuilder.charAt(0))){
if(firstList.containsKey(stringBuilder.toString())){
List
for(int q=0;q
if(!isContain(oneFollowList,list.get(q))){
oneFollowList.add(list.get(q));
}
}
}
}
}else{
if(!isContain(oneFollowList,stringBuilder.toString())){
oneFollowList.add(stringBuilder.toString());
}
}
}
}
}
}else{
//判断E’类型的
if(str.contains(vnItem)){
int index=str.indexOf(vnItem);
String left=str.substring(index+vnItem.length(), str.length());
StringBuilder stringBuilder=new StringBuilder();
stringBuilder.append(left);
for(int k=stringBuilder.length();k>1;k--){
if(isVN(stringBuilder.toString(),vn)){
break;
}else{
int length=stringBuilder.length();
stringBuilder.deleteCharAt(length);
}
}
if(stringBuilder.length()>0){
if(Character.isUpperCase(stringBuilder.charAt(0))){
if(firstList.containsKey(stringBuilder.toString())){
List
for(int q=0;q
if(!isContain(oneFollowList,list.get(q))){
oneFollowList.add(list.get(q));
}
}
}
}
}else{
if(!isContain(oneFollowList,stringBuilder.toString())){
oneFollowList.add(stringBuilder.toString());
}
}
}
}
}
}
//求follow集合的第三条
for(int i=0;i
String str=newList.get(i).substring(index1);
if(vnItem.length()==1){
if(str.contains(vnItem)){
if(str.indexOf(vnItem)==str.length()&&str.charAt(str.indexOf(vnItem.charAt(0))+1)!='’'){
String s=newList.get(i).substring(0,newList.get(i).indexOf("-"));
getOneFollow(s, vn, newList, firstList);
}else{
String left=str.substring(str.indexOf(vnItem)+1);
StringBuilder stringBuilder=new StringBuilder();
stringBuilder.append(left);
for(int k=stringBuilder.length();k>1;k--){
if(isVN(stringBuilder.toString(),vn)){
break;
}else{
int length=stringBuilder.length();
stringBuilder.deleteCharAt(length-1);
}
}
if(isVN(stringBuilder.toString(), vn)){
if(firstList.containsKey(stringBuilder.toString())){
List
if(isContain(temp)){
String s=newList.get(i).substring(0,newList.get(i).indexOf("-"));
getOneFollow(s, vn, newList, firstList);
}
}
}
}
}
}else{
if(str.contains(vnItem)){
String st=newList.get(i);
if(st.endsWith(vnItem)){
if(!st.startsWith(vnItem)){
String s=newList.get(i).substring(0,newList.get(i).indexOf("-"));
getOneFollow(s, vn, newList, firstList);
}
}else{
String left=str.substring(str.indexOf(vnItem)+2);
StringBuilder stringBuilder=new StringBuilder();
stringBuilder.append(left);
for(int k=stringBuilder.length();k>1;k--){
if(isVN(stringBuilder.toString(),vn)){
break;
}else{
int length=stringBuilder.length();
stringBuilder.deleteCharAt(length-1);
}
}
if(isVN(stringBuilder.toString(), vn)){
if(firstList.containsKey(stringBuilder.toString())){
List
if(isContain(temp)){
String s=newList.get(i).substring(0,newList.get(i).indexOf("-"));
getOneFollow(s, vn, newList, firstList);
}
}
}
}
}
}
}
}
/**
* 获得所有非终结符号的follow集合
* @param vn(非终结符号的集合)
* @param newList(消除左递归的文法)
* @param firstList(所有非终结符号的first集合)
* @return
*/
public static Map
Map
for(int i=0;i
getOneFollow(vn.get(i),vn,newList,firstList);
List
for(int k=0;k
}
followList.put(vn.get(i),temp );
}
return followList;
}
/**
* 判断是不是LL(1)文法
* @param firstList
* @param followList
* @return
*/
public static boolean isLL1(Map
//因为消除了左递归,所以文法判断的第一条默认成立
//判断文法条件的第三条
for(int i=0;i
List
first.addAll(firstList.get(vn.get(i)));
List
follow.addAll(followList.get(vn.get(i)));
first.retainAll(follow);
if(first.size()!=0){
return false;
}
}
}
//判断文法的第二条
for(int i=0;i
for(int j=0;j
String str=newList.get(j).substring(newList.get(j).indexOf(">")+1);
stringBuilder.append(str+" ");
}
}
String[] items=stringBuilder.toString().split(" ");
if(items.length>1){
for(int k=0;k
for(int n=k+1;n
first.retainAll(second);
if(first.size()!=0){
return false;
}
}
}
}
}
return true;
}
/**
* 判断是不是终结符号,是则返回true,不是则返回false
* @param ch(要判断的字符串)
* @return
*/
public static boolean isVN(String ch,List
for(int i=0;i
return true;
}
}
return false;
}
/**
* 判断相应的first集合有没有空串,如果有返回true,反之为false
* @param list
* @return
*/
public static boolean isContain(List
for(int i=0;i
return true;
}
}
return false;
}
/**
* 获得每一个非终结符号的候选首符集
* @param str
* @param firstlist
* @return
*/
public static List
List
if(Character.isUpperCase(str.charAt(0))){
if(str.length()>1){
if(str.charAt(1)!='’'){
list.addAll(firstlist.get(""+str.charAt(0)));
}else{
list.addAll(firstlist.get(""+str.charAt(0)+str.charAt(1)));
}
}
}else{
list.add(""+str.charAt(0));
}
return list;
}
/**
* 获得终结符号
* @param newList
* @return
*/
public static List
List
for(int i=0;i
String str=newList.get(i).substring(index1);
for(int k=0;k
if(str.charAt(k)!='’'&&str.charAt(k)!='~'){
if(!isContain(list, ""+str.charAt(k))){
list.add(""+str.charAt(k));
}
}
}
}
}
return list;
}
/**
* 生成LL(1)预测分析表
* @param vn
* @param vt
* @param firstList
* @param followList
* @param newList
* @throws IOException
*/
public static void print(List
removeFile();
vt.add("#");
for(int i=0;i
}
System.out.println();
for(int i=0;i
for(int k=0;k
if(str!=null){
System.out.printf(str+" ");
writeToFile(vn.get(i),vt.get(k),str);
}else{
if(!firstList.get(vn.get(i)).contains(""+vt.get(k))&&firstList.get(vn.get(i)).contains("~")){
if(followList.get(vn.get(i)).contains(""+vt.get(k))){
System.out.printf(vn.get(i)+"-->~"+" ");
writeToFile(vn.get(i),vt.get(k),vn.get(i)+"-->~");
}else{
System.out.printf(" \t");
}
}else{
System.out.printf(" \t");
}
}
}
System.out.println();
}
}
/**
* 填充预测分析表,找到非终结符号要推出终结符号时所用的产生式
* @param vn
* @param newList
* @param firstList
* @param followList
* @param vtItem
* @param vnItem
* @return
*/
public static String findItems(List
for(int i=0;i
if(newList.get(i).startsWith(vnItem)&&newList.get(i).charAt(1)!='’'){
int index=newList.get(i).indexOf(">")+1;
String str=newList.get(i).substring(index);
if(Character.isUpperCase(str.charAt(0))){
StringBuilder stringBuilder=new StringBuilder();
stringBuilder.append(str);
for(int k=stringBuilder.length();k>1;k--){
if(isVN(stringBuilder.toString(),vn)){
break;
}else{
int length=stringBuilder.length();
stringBuilder.deleteCharAt(length-1);
}
}
if(firstList.get(stringBuilder.toString()).contains(vtItem)){
return newList.get(i);
}else{
}
}else{
if(vtItem.equals(""+str.charAt(0))){
return newList.get(i);
}else{
}
}
}
}else{
if(newList.get(i).startsWith(vnItem)){
int index=newList.get(i).indexOf(">")+1;
String str=newList.get(i).substring(index);
if(Character.isUpperCase(str.charAt(0))){
StringBuilder stringBuilder=new StringBuilder();
stringBuilder.append(str);
for(int k=stringBuilder.length();k>1;k--){
if(isVN(stringBuilder.toString(),vn)){
break;
}else{
int length=stringBuilder.length();
stringBuilder.deleteCharAt(length-1);
}
}
if(firstList.get(stringBuilder.toString()).contains(vtItem)){
return newList.get(i);
}else{
}
}else{
if(vtItem.equals(""+str.charAt(0))){
return newList.get(i);
}else{
}
}
}
}
}
return null;
}
/**
* 将预测分析表以三元组的形式写入文件
* @param vn
* @param vt
* @param str
* @throws IOException
*/
public static void writeToFile(String vn,String vt,String str) throws IOException{
String path="/Users/mahui/Desktop/table.txt";
File file=new File(path);
if(!file.exists()){
file.createNewFile();
}
FileWriter fileWriter=new FileWriter(file,true);
fileWriter.write(vn+" "+vt+" "+str+"\n");
fileWriter.close();
}
/**
* 每次运行之前都删除文件,避免内容重复
* (因为我向文件写数据是以追加的形式,所以再将预测分析表写入文件时,先清除之前的数据)
*/
public static void removeFile(){
String path="/Users/mahui/Desktop/table.txt";
File file=new File(path);
if(file.exists()){
file.delete();
}
}
/**
* 将存储在文件中的预测分析表存储在List
package cn.mahui;
import java.io.IOException;
import java.util.List;
import java.util.Map;
public class MainFunction {
public static void main(String[] args) throws IOException {
String path="/Users/mahui/Desktop/grammar.txt";
String grammar=Function.readGrammarFile(path);
System.out.println("文法如下:");
List
System.out.println(oldList);
System.out.println("文法的每一条产生式如下:");
List
System.out.println(oldListItems);
System.out.println("所有非终结符号如下:");
List
System.out.println(vn);
System.out.println("文法的终结符号如下:");
List
System.out.println(vt);
System.out.println("消除左递归后的文法如下:");
List
System.out.println(newList);
StringBuilder stringBuilder=new StringBuilder();
for(int i=0;i
}
System.out.println("消除左递归后的文法的非终结符号如下:");
vn=Function.getVN(stringBuilder.toString());
System.out.println(vn);
System.out.println("消除左递归后的文法的终结符号如下:");
vt=Function.getVT(newList);
System.out.println(vt);
System.out.println("first集合如下:");
Map
System.out.println(firstList);
System.out.println("follow集合如下:");
Map
System.out.println(followList);
System.out.println("该文法是LL(1)文法吗?"+Function.isLL1(firstList, followList, newList, vn));
if(Function.isLL1(firstList, followList, newList, vn)){
System.out.println("预测分析表如下:");
Function.print(vn, vt,firstList,followList,newList);
}
vt=Function.getVT(newList);
Function.analyse(vn,vt,vn.get(0));
}
}
本代码仅仅实现了此功能,代码中还有很多可以优化的地方