源代码链接:https://download.csdn.net/my
1.目录结构
2.文件内容
文件1:
文件2:
文件3:
文件4:
文件5:
3.源代码部分
1.建立存储模型
public class staticData {
//非终结符
public static String nfinalSign=null;
//终结符
public static String finalSign=null;
//产生式表
public static String[][] productType;
//first集表
public static String[] firstSet;
//first集元素对应的产生式
public static String[][] firstProductType;
//follow集表
public static String[] followSet;
}
.
2.文件扫描
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/*
* 1.提取终结符与非终结符
* 2.构建非终结产生式列表
*/
public class TakeSign {
public void selectFile(int number) throws IOException {
Scanner scan=new Scanner(System.in);
/*
* 文件读取部分
*/
String AppCodeUrl=System.getProperty("user.dir")+"/src/grammerRules";
//建立文件对象
File file=new File(AppCodeUrl,"grammerRules"+number);
//建立你问价读取对象
FileReader fileReader=new FileReader(file);
BufferedReader bufferedReader=new BufferedReader(fileReader);
//存储产生式String----代表若干个产生式
List<String> signStrList=new ArrayList<String>();
//文件读取
String tempstr=null;
while((tempstr=bufferedReader.readLine())!=null) {
signStrList.add(tempstr);
}
bufferedReader.close();
//输出
System.out.println("读取相关文法如下:");
for (String string : signStrList) {
System.out.println(string);
}
/*
* 提取终结符与非终结符
*/
//非终结符的相关产生式
staticData.productType=new String[signStrList.size()][7];
//非终结符号提取
for (int i = 0; i < signStrList.size(); i++) {
staticData.nfinalSign+=""+signStrList.get(i).charAt(0);
//提取产生式存放到后续
String temp=signStrList.get(i);
int index=temp.indexOf('>');
temp=temp.substring(index+1,temp.length());
String[] E_f=temp.split("\\|");
int num=0;
for (String it : E_f) {
staticData.productType[i][num++]=it;
}
}
System.out.println(signStrList.size()+" "+staticData.nfinalSign.length());
//终结符提取
staticData.finalSign="";
for (String it:signStrList) {
for (int i = 0; i < it.length(); i++) {
//临时符号
char tempchar=it.charAt(i);
//----判断终结符
if(tempchar!='>'&&tempchar!='-'&&tempchar!='n'&&tempchar!='@'&&tempchar!='|'&&(tempchar<'A'||tempchar>'Z')) {
if(staticData.finalSign==null||FinalExist(tempchar)) {
staticData.finalSign+=""+tempchar;
}
}
}
}
//------------------------------对是否为左递归文法进行判断---------------//
for (int i = 0; i <staticData.nfinalSign.length(); i++) { //对每一个非终结符进行考察
juageLeft(i,i);
}
//--------------------------------控制台输出----------------------------//
/*
* 输出终结符
*/
System.out.println("\n\n>>>终结符如下:");
for (int i = 0; i < staticData.finalSign.length(); i++) {
System.out.print(staticData.finalSign.charAt(i)+" ");
}
System.out.println();
/*
* 输出非终结符
*/
System.out.println("\n\n>>>非终结符及其相关候选产生式如下:");
for (int i = 0; i < signStrList.size(); i++) {
System.out.println(staticData.nfinalSign.charAt(i)+"候选产生式:");
for (String it :staticData.productType[i]) {
if(it==null)
break;
else {
System.out.println(it+" ");
}
}
}
}
//-------------------------子函数区域-----------------------------------//
/*
* 判断终结符是否已经加入过
*/
public Boolean FinalExist(char tempchar) {
if(staticData.finalSign.contains(""+tempchar)) {
return false;
}
return true;
}
/*
*
*
* 判断是否含有左递归
* i--------代表判断当前是那个文法
* recursive---递归的非终结符
*/
public void juageLeft(int i,int recursive) {
for (int j = 0; j < staticData.productType[recursive].length; j++) { //遍历所有产生式
for(int k=0;staticData.productType[recursive][j]!=null&&k<staticData.productType[recursive][j].length();k++) { //对每一个产生式考察
String temp=staticData.productType[recursive][j];
try {
if(staticData.nfinalSign.charAt(i)==temp.charAt(0)) {
//判断首符号是否与当前考察的非终结符是否相等
System.out.println("本文法含有左递归,不属于LL(1)文法!!!--------->("+temp.charAt(0)+"->"+temp+"...)");
System.exit(0);
//throw new Exception("此文发还有左递归,不属于LL(1)文法!!!");
}else if(staticData.nfinalSign.contains(""+temp.charAt(0))){ //判断是否为终结符这是否需要进行递归操作
//求其对应位置
int place=staticData.nfinalSign.indexOf(temp.charAt(0));
//递归进行
juageLeft(i,place);
}
} catch (Exception e) {
System.out.println(e);
}finally {
}
}
}
}
}
3.提取first集
/*
* 构建first集
*/
public class FirstSet {
static int num=0;
//非终结符
private String nFinalSign;;
//终结符
private String finalSign;
//first集
private String[] firstSet;
//产生式表
String[][] NfinalP_table=new String[nFinalSign.length()][finalSign.length()];
//首符集对应生式的表
String[][] firstSetp=new String[nFinalSign.length()][finalSign.length()];
/*
* 构造方法
*/
public FirstSet(String nFinalSign, String finalSign, String[][] nfinalP_table) {
super();
this.nFinalSign = nFinalSign;
this.finalSign = finalSign;
NfinalP_table = nfinalP_table;
}
/*
* 求解first集
*/
public String[] firstConstruction() {
//将first置空
firstSet=new String[nFinalSign.length()];
//初始化
for (int i = 0; i < firstSet.length; i++) {
firstSet[i]="";
}
//first表
String[][] foreTable=new String[nFinalSign.length()][finalSign.length()];
/*
* 求解first集
*/
//利用第<<1>><<2>>条规则求取first集及first集中每个对应的产生式
System.out.println("first集中元素所对应的产生式");
for (int j = 0; j < nFinalSign.length(); j++) {//遍历每一个非终结符
num=0;
takeProPress(j,nFinalSign.charAt(j),NfinalP_table[j],null);
}
//利用第<<3>>条规则求取判断是否将@--空添加到first集中
for (int i = 0; i < firstSetp.length; i++) {
if(juagenull(i)) {
if(!firstSet[i].contains("@")) {
//向首符集添加@
firstSet[i]+="@";
}
}
}
System.out.println("--------------------");
System.out.println("first集如下:");
for (int i = 0; i <firstSet.length; i++) {
System.out.println(nFinalSign.charAt(i)+":"+firstSet[i]);
}
return firstSet;
}
/*
* 求解first集元素对应的产生式
*/
public String[][] firstToProductTable() {
return firstSetp;
}
//-------------------------------子程序部分--------------------------------//
/*
* 获取每一个
*/
//int nplace对应求解的非终结符
// String Nfinal非终结符
// 产生式表
// first集合表
// Nuchangedstr
public void takeProPress(int nplace,char Nfinal,String[] NfinalP_arr,String Nuchangedstr){
//遍历每一个候选产生式
for (String p : NfinalP_arr) {
char firstSign=p.charAt(0);
if(firstSign=='@'||jugeFinal(firstSign)){ //1.根据第一条规则进行匹配
//添加到首符集
firstSet[nplace]+=firstSign;
//填写对应的首符集对应产生式
if(Nuchangedstr==null) {
firstSetp[nplace][num]=p;
}
else {
firstSetp[nplace][num]=Nuchangedstr;
}
System.out.print(num+": "+firstSetp[nplace][num]);
if(num==0)
System.out.println();
num++;
}else{ //2.根据第二条规则进行匹配
//获取首符号的位置
int fsplace=nFinalSign.indexOf(firstSign);
if(Nuchangedstr==null)
takeProPress(nplace,firstSign,NfinalP_table[fsplace],p);
else {
takeProPress(nplace,firstSign,NfinalP_table[fsplace],Nuchangedstr);
}
}
}
}
/*
* 判别其中一个非终结符的首符集是否应该添加@空
*/
public boolean juagenull(int nplace) {
next: for (int i = 0; i < NfinalP_table[nplace].length; i++) { //判别每个产生式
String temp=NfinalP_table[nplace][i];
if(temp.equals("@"))
continue;
char pAtrr[]=temp.toCharArray();
for (int j = 0; j < pAtrr.length; j++) {
if(jugeFinal(pAtrr[j])) //是终结符
continue next;
else { //是非终结符
//判断是否含有@
//获取位置信息
int mayNullPlace=nFinalSign.indexOf(pAtrr[j]);
//判断是否其非终结符中含有@
if(!juageHavenull(mayNullPlace)) {
continue next;
}
}
}
return true;
}
return false;
}
/*
* 判断是否含有终结符
*/
public boolean juageHavenull(int mayNullPlace) {
for (String string : NfinalP_table[mayNullPlace]) {
if(string.equals("@")) {
return true;
}
}
return false;
}
/*
* 判断是否为终结符
*/
public Boolean jugeFinal(char c) {
String temp=""+c;
if(finalSign.contains(temp)) {
return true;
}else {
return false;
}
}
}
4.提取follow集
public class FollowSet {
//终结符
static String finalSign="i+*()#";
//非终结符
static String nFinalSign="EeTtF";
//存储每个非终结符的first集
static String[] firstSet=new String[finalSign.length()];
//存储每个非终结符的follow集
static String[] followdSET=new String[finalSign.length()];
//相关非终结符候选产生式所对应的表
static String[][] NfinalP_table=new String[nFinalSign.length()][finalSign.length()];
//首符集对应产生式的表
static String[][] firstSetp=new String[nFinalSign.length()][finalSign.length()];
//右递归标志
//static Boolean rightb=false;//默认无右递归
// //follow添加状态表
// static String[][] followState=new String[3][nFinalSign.length()];
public static void main(String[] args) {
//first集进行初始化
firstSet[0]="(i";
firstSet[1]="+@";
firstSet[2]="(i";
firstSet[3]="*@";
firstSet[4]="(i";
//产生式表初始化
NfinalP_table[0]=new String[]{"Te"};
NfinalP_table[1]=new String[]{"+Te","@"};
NfinalP_table[2]=new String[]{"Ft"};
NfinalP_table[3]=new String[]{"*Ft","@"};
NfinalP_table[4]=new String[]{"(E)","i"};
/*
* follow集初始化
*/
for (int i = 0; i < followdSET.length; i++) {
followdSET[i]="";
}
/*
* follow集状态表初始化
*/
// for (int i = 0; i < followState[0].length; i++) {
// followState[0][i]="0";
// }
// for (int i = 0; i < followState[1].length; i++) {
// followState[1][i]="";
// }
// for (int i = 0; i < followState[2].length; i++) {
// followState[2][i]="n";
// }
//在所有产生式中搜索每一个非终结符
//开始符号添加符号‘#’
followdSET[0]="#"; //第-----------------------------------1-------------------条规则
for (int i = 0; i < nFinalSign.length(); i++) { //获取每一个非终结符
/*
* 针对表进行遍历
*/
for (int j = 0; j < nFinalSign.length(); j++) { //遍历其中一个非终结符的产生式
for (int j2 = 0; j2 < NfinalP_table[j].length; j2++) { //在每个产生式中搜索对应的非终结符
//*********获取产生式*********
String temp=NfinalP_table[j][j2];
char[] prochars=temp.toCharArray();
//在字符串中搜索非终结符
for (int k = 0; k <prochars.length; k++) { //当前产生式
//与非终结符进行比较 prochars[k]当前比较元素
if(prochars[k]==nFinalSign.charAt(i)) { //---------------------是否与此非终结符相等
//是否为最后面的元素
if(k==prochars.length-1) { //是最后元素第-----------------------------------3-------------------条规则
//判断是否属于右递归
//进行右推导判断 j--->i
for (int k2 = 0; k2 < followdSET[j].length(); k2++) {
if(!followdSET[i].contains(""+followdSET[j].charAt(k2)))
followdSET[i]+=followdSET[j].charAt(k2);
}
// juageRight(i, j);
// if(nFinalSign.charAt(i)==nFinalSign.charAt(j)||rightb) {//直接右递归或间接右递归
// rightb=false;
// break;
// }else { //非右递归
// int place=nFinalSign.indexOf(prochars[k]);
// //将i的follow集添加到中
// followState[0][place]="1";
// followState[1][place]+=prochars[k];
// }
}else { //非最后元素第----------------------------------2-------------------条规则
//获取后面元素
char back=temp.charAt(k+1);
if(!jugeFinal(back)) { //非终结符
//求取对应first集位置
int place=nFinalSign.indexOf(back);
for (int l = 0; l < firstSet[place].length(); l++) {
if(!followdSET[i].contains(""+firstSet[place].charAt(l))&&firstSet[place].charAt(l)!='@') {
followdSET[i]+=firstSet[place].charAt(l);
}
//-----------第三条特殊规则 A->**Bn n->@----------------//
//截取后续字符串
String subString=temp.substring(k+1);
//判断后续字符串是否都能推出@,也就是所有符号first集都含有@
if(juageStrnull(subString)) {
for (int k2 = 0; k2 < followdSET[j].length(); k2++) {
if(!followdSET[i].contains(""+followdSET[j].charAt(k2)))
followdSET[i]+=followdSET[j].charAt(k2);
}
}
}
}else if(!followdSET[i].contains(""+back)){//终结符
followdSET[i]=back+followdSET[i];
}
}
break;
}
//rightb=false;
}
}
}
}
// for (int j = 0; j < followState.length; j++) {
// for (int j2 = 0; j2 < nFinalSign.length(); j2++) {
// System.out.println(followState[j][j2]);
// }
// }
//-------------------------------------第三条规则的添加-----------------------------//
//--------------------------------------follow集输出操作----------------------------//
for (int i = 0; i < nFinalSign.length(); i++) {
System.out.println(nFinalSign.charAt(i)+":"+followdSET[i]);
}
}
//----------------------------子函数部分---------------------------------------------//
/*
* 判断是否为终结符
*/
public static Boolean jugeFinal(char c) {
String temp=""+c;
if(finalSign.contains(temp)) {
return true;
}else {
return false;
}
}
/*
* 判断后续字符串符号是否都能推出@
*/
public static Boolean juageStrnull(String string) {
for (int i = 0; i < string.length(); i++) {
//获取第i个字符
char c=string.charAt(i);
if(jugeFinal(c)) {
return false;
}else {
//获取其首符集位置
int firstLocation=nFinalSign.indexOf(c);
//判断首符集是否含有@
if(!firstSet[firstLocation].contains("@"))
return false;
}
}
return true;
}
/*
* 判断非终结符是否为右递归
* i对应非终结符
* recursive对应右边的非终结符
*/
// public static void juageRight(int i,int recursive) {
// //recursive对应的非终结符的产生式进行考察
// for (int j = 0; j <NfinalP_table[recursive].length; j++) {
// String prostring=NfinalP_table[recursive][j];
// //获取最右的元素
// int index=prostring.length();
// char rightElement=prostring.charAt(index-1);
// //判断是否为终结符
// if(finalSign.contains(""+rightElement)) { //终结符
// return;
// }else if(rightElement==nFinalSign.charAt(i)){ //非终结符判断是否相等
// rightb=true;
// return;
// }else {
// juageRight(i,rightElement);
// }
// }
// }
}
5.建立预分析表
/*
* 建立预分析表
*/
public class BuildTable {
public static void main(String[] args) {
//非终结符
String nFinalSign="EeTtF";
//终结符
String finalSign="i+*()#";
// //first表
// char[][] first=new char[nFinalSign.length()][finalSign.length()];
// //follow表
// char[][] follow=new char[nFinalSign.length()][finalSign.length()];
//first集
String[] firstset= {"(i","+@","(i","*@","(i"};
//follow集
String[] followset= {")#",")#","+)#","+)#","*+)#"};
//预测分析表
String[][] foreTable=new String[nFinalSign.length()][finalSign.length()];
//firstset对应产生式
String[][] firstSetp=new String[nFinalSign.length()][];
firstSetp[0]=new String[] {"Te","Te"};
firstSetp[1]=new String[] {"+Te"};
firstSetp[2]=new String[] {"Ft","Ft"};
firstSetp[3]=new String[] {"*Ft"};
firstSetp[4]=new String[] {"(E)","i"};
//构建分析表
for (int i = 0; i < foreTable.length; i++) {
for (int j = 0; j < foreTable[i].length; j++) {
String temp=""+finalSign.charAt(j);
if(firstset[i].contains(temp)){//若first及中含有
//字符集的位置
int index=firstset[i].indexOf(temp);
foreTable[i][j]=firstSetp[i][index];
}else if(firstset[i].contains(""+"@")&&followset[i].contains(temp)){
foreTable[i][j]="@";
}else {
foreTable[i][j]="n";
}
}
}
/*
* 将构建的预测分析表输出
*/
System.out.println("非终结符:"+nFinalSign);
System.out.println("终结符:"+finalSign);
for (String[] strings : foreTable) {
for (String string : strings) {
System.out.printf("%s\t",string+" ");
}
System.out.println();
}
}
}
6.总控程序
import java.util.Scanner;
public class TotalControl {
//终结符串
static String final_sign=null;
//非终结符串
static String Nfinal=null;
public static void derive() {
Scanner sc=new Scanner(System.in);
///
/*----------------初始化表---------------------
// ///*/
//接受终结符
System.out.println("请输入终结符号集合:");
final_sign=sc.nextLine();
//接受非终结符
System.out.println("请输入非终结符号集合:");
Nfinal=sc.nextLine();
//根据终结符与非终结符的长度创建一个表
int h=Nfinal.length();
int l=final_sign.length();
String[][] Table=new String[h][l];
//System.out.println(Table.length);
//System.out.println(Table[0].length);
System.out.println("请输入矩阵句型:");
for (int i = 0; i < Table.length; i++) { //行
for (int j = 0; j < Table[0].length; j++) { //列
Table[i][j]=sc.next();
}
}
for (String[] strings : Table) {
for (String string : strings) {
System.out.printf("%s\t",string);
}
System.out.println();
}
//接受输入要扫描的字符串
System.out.println("请输入你所要扫描的字符串:");
String input_str=sc.next();
System.out.println(input_str);
sc.close();
/*/
//--------------------如下进行匹配------------------------/
/*/
//构建栈
char[] sign_stack=new char[10];
//构建指针
int top=1; //指向栈顶
int lr=0; //指向扫描字符
//初始化栈
sign_stack[0]='#';
sign_stack[1]=Nfinal.charAt(0);
//表的行坐标
int hang=0;
int lie=0;
//取得栈顶元素
char stack_top;
while(sign_stack[top]!='#'||input_str.charAt(lr)!='#') {
stack_top=sign_stack[top]; //取出栈顶元素
/*/
*
* 问题存在区域
*
*/
//---------------判断栈顶元素是否为终结符--------------
if(!isNfinal(stack_top)) { //是终结符
//与扫描串当前字符匹配
if(stack_top==input_str.charAt(lr)){ //可以匹配
lr++; //进行下一个字符匹配
System.out.println("lr top:"+lr);
sign_stack[top]='0';
top--; //弹出栈顶元素终结符
if(sign_stack[top]=='#')
break;
stack_top=sign_stack[top];
}else { //句型不匹配推出
System.out.println("GGGG!!!");
break;
}
}
//---------------进行非终结符推导----------------------
hang=Nfinal.indexOf(stack_top); //查找在表中的行位置
lie=final_sign.indexOf(input_str.charAt(lr)); //查找在表中的列位置
//将当前表中符号串与字符进行比较
if(Table[hang][lie].equals("n")) { //1.如果没有匹配的
System.out.println("GG!!");
break;
}else {
if(Table[hang][lie].length()==1&&Table[hang][lie].charAt(0)==input_str.charAt(lr)) { //如果终结符匹配成功将栈顶元素弹出,并且进行下一个字符匹配
sign_stack[top]='0'; //出栈
top--; //栈顶指针变化
lr++; //扫描指针发生变化
System.out.println("lr:"+lr);
}else if(Table[hang][lie].equals("@")){ //如果存在是空@则弹出栈顶元素
sign_stack[top]='0';
top--;
}else { //否则将栈顶元素出栈并将推导式入栈
for(int i=Table[hang][lie].length()-1;i>=0;i--) {
//判断将要插入的字符是否为非终结符
sign_stack[top]=Table[hang][lie].charAt(i);
top++;
}
top--;
}
}
}
/*//
* 判断匹配成功
*//
if(sign_stack[top]=='#'&&input_str.charAt(lr)=='#')
System.out.println("匹配成功!!!"+lr);
else {
System.out.println("出错位置:"+(lr+1));
}
}
/*//
* 判断字符是否为非终结符
*//
private static boolean isNfinal(char temp) {
for (int i = 0; i < Nfinal.length(); i++) {
if(temp==Nfinal.charAt(i)) return true;
}
return false;
}
}
7.主函数
import java.io.IOException;
import java.util.Scanner;
public class Mian {
//--------------------------------定义部分--------------------------//
//非终结符存储
private static String NFinalSign="";
//终结符号
private static String FinalSign;
//非终结符的相关产生式
private static String[][] NFinalTable;
//----------------------------------主函数部分-----------------------//
public static void main(String[] args) throws IOException {
Scanner scan=new Scanner(System.in);
/*
* 文件读取部分
*/
//获取用用程序程序路径
String AppCodeUrl=System.getProperty("user.dir")+"/src/grammerRules";
//进行文件选择
System.out.println("文件标号:1");
System.out.println("文件标号:2");
System.out.println("文件标号:3");
System.out.println("文件标号:4");
System.out.println("文件标号:5");
System.out.println("请选择:");
int selectFileCode=scan.nextInt();
//文件扫描部分
TakeSign takeSign=new TakeSign();
takeSign.selectFile(selectFileCode);
//first集提取部分、
FirstSet firstSet=new FirstSet(NFinalSign,FinalSign,NFinalTable);
}
}