LR1文法分析句子

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#"测试句子

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值