LR1.java
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
public class LR1 {
private List<String> nonTerminals=new ArrayList<String>();//非终结符集合
private List<String> terminals=new ArrayList<String>();//终结符集合
private List<ArrayList<String>> productions=new ArrayList<ArrayList<String>>();//产生式集合
private List<ArrayList<String>> pros=new ArrayList<ArrayList<String>>();//产生式集合
List<String> conbine=new ArrayList<String>();//combine存储所有的文法符号(非终结符+终结符)
private String start=null;//开始符号
String[][] a=new String[60][60];//分析表
public LR1() {
// TODO Auto-generated constructor stub
}
public void analyse(String str) {
initAnalysisTable();//先初始化分析表
//输出分析表
System.out.println("*******************分析表************************");
for(int i=0;i<60;i++) {
for(int j=0;j<60;j++) {
if(a[i][j]!=null) {
System.out.println(i+"+"+conbine.get(j)+"->"+a[i][j]);
}
}
}
Stack state=new Stack();//状态栈
Stack analysis =new Stack();//符号栈
state.push("0");
analysis.push("#");
int tt=0,i=0;//tt记录步骤次数,i记录句子指针位置
String firstChar=str.substring(i,i+1);
int m = Integer.parseInt(state.getTopObjcet());
int n = conbine.indexOf(firstChar);
//如果输入符号中含有非法符号,即不属于当前文法的文法符号集合,提示并终止程序
if(n==-1) {
System.out.println("出错了!!!输入符号中含有非法符号");
return;
}
//System.out.println(conbine);
while(a[m][n]!="acc") {
System.out.println("************步骤"+(++tt)+"*************");
System.out.print("状态栈:");
state.output();
System.out.print("符号栈:");
analysis.output();
System.out.print("输入串:");
System.out.println(str.substring(i));
System.out.print("执行动作:");
System.out.print("ACTION["+m+","+firstChar+"]="+a[m][n]+" ");
if(a[m][n]==null) {
System.out.println("出错了!!!该句子语法错误");
break;
}else if(a[m][n].startsWith("S")) {
//System.out.println(a[m][n].substring(1, a[m][n].length()));
state.push(a[m][n].substring(1, a[m][n].length()));
analysis.push(firstChar);
System.out.println("\nACTION["+m+","+firstChar+"]="+a[m][n]+",移进"+firstChar+",状态"+a[m][n].substring(1, a[m][n].length())+"入栈");
firstChar=str.substring(++i,i+1);
}else if(a[m][n].startsWith("r")) {
int loc = Integer.parseInt(a[m][n].substring(1, a[m][n].length()));
ArrayList<String> pp = productions.get(loc);
String mm="";
String nn="";
for(int j=0;j<pp.size()-1;j++) {
mm+=state.pop();
nn+=analysis.pop();
}
analysis.push(pp.get(0));
int x = Integer.parseInt(state.getTopObjcet());
int y = conbine.indexOf(pp.get(0));
System.out.println("GOTO["+x+","+pp.get(0)+"]="+a[x][y]);
System.out.println("ACTION["+m+","+firstChar+"]="+a[m][n]+"按规则"+a[m][n].substring(1, a[m][n].length())+
"将"+mm+"归约到"+pp.get(0)+",弹出栈顶状态"+mm+"、符号"+nn+",且GOTO["+x+","+pp.get(0)+"]="+a[x][y]+
",状态"+a[x][y]+"入栈,符号"+pp.get(0)+"入栈");
state.push(a[x][y]);
}
m = Integer.parseInt(state.getTopObjcet());
n = conbine.indexOf(firstChar);
if(n==-1) {
System.out.println("出错了!!!输入符号中含有非法符号");
return;
}
}
if(a[m][n]=="acc") {
System.out.println("************步骤"+(++tt)+"*************");
System.out.print("状态栈:");
state.output();
System.out.print("符号栈:");
analysis.output();
System.out.print("输入串:");
System.out.println(str.substring(i));
System.out.print("执行动作:");
System.out.println("ACTION["+m+","+firstChar+"]="+a[m][n]+",分析成功");
}
}
//得到分析表
public void initAnalysisTable(){
List<List<String>> originalCollect=new ArrayList<List<String>>();//初态项目集
List<List<List<String>>> collect=new ArrayList<List<List<String>>>();//LR项目集规范族collect
terminals.add("#");
ArrayList<String> pro=new ArrayList<String>();
pro.addAll(productions.get(0));//获取第一个产生式S'→S
pro.add(1,".");//转换为项目
pro.add(",");
pro.add("#");
originalCollect.add(pro);
closure(pro,originalCollect);//求 Closure{S'→·S,#},得初态项目集 originalCollect
//System.out.println(originalCollect);
collect.add(originalCollect);//将初态项目集加入到LR项目集规范族collect
System.out.println("*************GO函数***************");
conbine.addAll(nonTerminals);
conbine.addAll(terminals);
//System.out.println("conbine="+conbine);
int length=-1,t=0;
while(length<collect.size()) {//当项目集规范族collect的大小不再变化时终止
length=collect.size();//记录项目集规范族collect的变化前的大小
for(;t<collect.size();t++) {//遍历collect中的项目集即状态
List<List<String>> mo=collect.get(t);
for(int i=0;i<conbine.size();i++) {
List<List<String>> p=go(t,mo,conbine.get(i));//当状态遇到文法符号conbine.get(i)时采取的动作或者说项目集遇到文法符号得到的项目集
if(p.size()>0) {
System.out.println("+++++++++++++");
System.out.println("GO(I"+t+","+conbine.get(i)+")="+p);
if(!collect.contains(p)) {
collect.add(p);//将go函数得到的项目集加入到collect中
}
if(nonTerminals.contains(conbine.get(i))) {
a[t][i]=""+collect.indexOf(p);//如果当前文法符号是非终结符标记为:应移入的下一状态。GOTO
}else {
a[t][i]="S"+collect.indexOf(p);//如果当前文法符号是终结符标记为:把当前输入符号及下一个状态移入分析栈中。ACTION
}
}
}
}
}
}
//文法文本解析与存储
public void initialize(String filePath) {
try {
BufferedReader br = new BufferedReader(new FileReader(filePath));
String s;
String[] sss=null;
for(s=br.readLine();s!=null;s=br.readLine()) {
if(s.indexOf("{")!=-1) {
int begin=s.indexOf("{");
int end=s.indexOf("}");
sss=s.substring(begin+1, end).split(",");
}
//判断每一行是非终结符、终结符、产生式还是开始符号
if(s.charAt(0)=='V'&&s.charAt(1)=='n') {
//存储非终结符
for(int i=0;i<sss.length;i++) {
nonTerminals.add(sss[i]);
}
}else if(s.charAt(0)=='V'&&s.charAt(1)=='t') {
//存储终结符
for(int i=0;i<sss.length;i++) {
terminals.add(sss[i]);
}
}else if(s.charAt(0)=='P') {
//存储产生式
for(int i=0;i<sss.length;i++) {
String left=sss[i].substring(0, 1);//产生式左部:一个非终结符
String[] right=sss[i].substring(sss[i].indexOf(">")+1).split("\\|");//某个产生式左部对应的产生式右部集合
for(int j=0;j<right.length;j++) {
ArrayList<String> p=new ArrayList<String>();
ArrayList<String> pro=new ArrayList<String>();
p.add(left);
pro.add(left);
p.add(right[j]);
for(int t=0;t<right[j].length();t++) {
pro.add(right[j].substring(t,t+1));
}
productions.add(pro);
pros.add(p);
}
}
}else if(s.charAt(0)=='S') {
//存储开始符号
start=s.substring(2);
ArrayList<String> pro=new ArrayList<String>();
pro.add("S'");
pro.add(start);
productions.add(0, pro);
}
sss=null;
}
br.close();
}catch(Exception e) {
e.printStackTrace();
}
}
//文法输出
public void output() {
System.out.println("非终结符有");
for(int i=0;i<nonTerminals.size();i++) {
System.out.println(nonTerminals.get(i));
}
System.out.println("终结符有");
for(int i=0;i<terminals.size();i++) {
System.out.println(terminals.get(i));
}
System.out.println("产生式有");
for(int i=0;i<productions.size();i++) {
System.out.println(productions.get(i));
}
System.out.println("开始符号有");
System.out.println(start);
}
//定义单个项目item的闭包函数
public void closure(List<String> item,List<List<String>> result) {
//System.out.println("result***"+result);
int loc=item.indexOf(".");
//如果当前项目是A→α·Bβ,a的形式
int dot = item.indexOf(",");
if(loc<dot-1 && nonTerminals.contains(item.get(loc+1))) {
String m=item.get(loc+1);
//如果期待的下一个符号是非终结符,循环遍历productions中的每一条规则
for(int i=0;i<productions.size();i++) {
ArrayList<String> pro=new ArrayList<String>();
pro.addAll(productions.get(i));
//如果产生式是B→γ的形式
if(m.equals(pro.get(0))) {
pro.add(1, ".");
List<String> tem = item.subList(loc+2,item.size());
List<String> right = new ArrayList<String>();
right.addAll(tem);
right.remove(",");//得到βa
List<String> firstSet = new ArrayList<String>();
findFirstSet(right, firstSet);//得到FIRST(βa)
pro.add(",");
pro.addAll(firstSet);//将first集加入到B→.γ对应的项目中用,分隔,
//System.out.print(pro.subList(0, pro.indexOf(",")).toString().equals(item.subList(0, dot).toString()));
//System.out.println(item+"->"+pro);
if(result.contains(pro) || pro.subList(0, pro.indexOf(",")).toString().equals(item.subList(0, dot).toString())) {continue;}
result.add(pro);//将B→.γ,FIRST(βa)对应的项目加入到闭包集合中
if(nonTerminals.contains(pro.get(2))){
closure(pro,result);//如果γ的第一个符号是非终结符,递归查找pro的闭包函数
}
}
}
}
}
//First集
public void findFirstSet(List<String> right,List<String> first){
//System.out.println(right);
String single=right.get(0);
if(terminals.contains(single) && !first.contains(single)) {
first.add(single);
}else if(single.equals("ε")) {
right=right.subList(1, right.size());
findFirstSet(right, first);
}else {
//说明此产生式右部首字符是一个不同于左部的非终结符
for(int i=0;i<productions.size();i++) {
ArrayList<String> pro =new ArrayList<String>();
pro.addAll(productions.get(i));
if(single.equals(pro.get(0)) && !single.equals(pro.get(1))) {
findFirstSet(pro.subList(1, pro.size()), first);
}
}
}
}
//定义当输入文法符号时项目集的GO函数
public List<List<String>> go(int t,List<List<String>> items,String m) {
List<List<String>> resultList = new ArrayList<List<String>>();//存储当输入符号m时items对应的项目集
//循环遍历项目集中的每个项目
for(int i=0;i<items.size();i++) {
List<String> list=new ArrayList<String>();
list.addAll(items.get(i));
int loc=list.indexOf(".");
int dot = list.indexOf(",");
if(loc<dot-1) {
String n=list.get(loc+1);//期待的下一个符号
if(n.equals(m)) {//如果期待的下一个符号与当前文法符号一样
//System.out.println(items+":"+loc);
list.set(loc, n);
list.set(loc+1, ".");
if(!resultList.contains(list))
resultList.add(list);
closure(list,resultList);//求当前项目的闭包集合并加入到re中
}
}else if(loc==(dot-1) ) {//如果当前项目是可归约的
//System.out.println(loc+"*************"+dot);
int o = terminals.indexOf(m);
List<String> searchWord = list.subList(dot+1, list.size());//得到可归约项目的搜索符号
list = list.subList(0, loc);
//如果当前项目是S'->S,# 时,表示此时为可接受状态,记录到分析表中,标记为:可接受
if(list.equals(productions.get(0))) {
//System.out.println(list+","+m);
if(o==terminals.size()-1) {
a[t][o+nonTerminals.size()]="acc";
}
}else {
//查找可归约项目对应的规则
for(int j=1;j<productions.size();j++) {//查找可归约项目对应的规则
if(list.equals(productions.get(j))) {
if(o>=0 && searchWord.contains(m)) {
a[t][o+nonTerminals.size()]="r"+j;//记录到分析表中,标记为:可按第j条规则归约
}
break;
}
}
}
}
}
return resultList;
}
}
辅助类Stack.java
import java.util.ArrayList;
import java.util.List;
import java.util.EmptyStackException;
public class Stack {
private List<String> pool = new ArrayList<String>();
public Stack() {
}
public boolean isEmpty() {
return pool.isEmpty();
}
// 获取栈顶元素
public String getTopObjcet() {
if (isEmpty()) {return null;}
return pool.get(pool.size()-1);
}
//弹出栈操作
public String pop() {
String e=pool.get(pool.size()-1);
pool.remove(pool.size()-1);
return e;
}
//压入栈
public void push(String e) {
pool.add(e);
}
// 获取当前栈大小
public int getStatckSize() {
return pool.size();
}
//输出当前栈
public void output() {
System.out.println(pool);
}
}
测试类Test.java
public class Test {
public Test() {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
String str = "i*i+i#";//测试数据_1对应的句子
//String str = "abbcde#";//测试数据_2对应的句子
//String str = "aacbb#";//测试数据_3对应的句子
LR1 lr=new LR1();
lr.initialize("D:\\Project\\Java\\LR0\\src\\测试数据_4.txt");
lr.output();
lr.analyse(str);
}
}
测试数据_1.txt
G=(Vn,Vt,S,P)
Vn={E,T,F}
Vt={+,*,(,),i}
P={E->E+T,E->T,T->T*F,T->F,F->(E),F->i}
S=E
//"i*i+i#"测试句子
测试数据_2.txt
G=(Vn,Vt,S,P)
Vn={S,A,B}
Vt={a,c,e,b,d}
P={S->aAcBe,A->b,A->Ab,B->d}
S=S
//"abbcde#"测试句子
测试数据_3.txt
G=(Vn,Vt,S,P)
Vn={S,A,B}
Vt={a,b,c,d}
P={S->A,S->B,A->aAb,A->c,B->aBb,B->d}
S=S
//"aacbb#"测试句子