JAVA语言编写的编译原理FIRST和FOLLOW集.docx
- 文档编号:9677602
- 上传时间:2023-02-05
- 格式:DOCX
- 页数:11
- 大小:19.17KB
JAVA语言编写的编译原理FIRST和FOLLOW集.docx
《JAVA语言编写的编译原理FIRST和FOLLOW集.docx》由会员分享,可在线阅读,更多相关《JAVA语言编写的编译原理FIRST和FOLLOW集.docx(11页珍藏版)》请在冰豆网上搜索。
JAVA语言编写的编译原理FIRST和FOLLOW集
packagecn.spy.action;
importjava.util.ArrayList;
importjava.util.Scanner;
importjava.util.StringTokenizer;
*某一输入实例:
*E->TE'
*E'->+E|ε
*T->FT'
*T'->T|ε
*F->PF'
*F'->*F'|ε
*P->(E)|a|b|^
*end
*/
publicclassFirstFollow3{
publicArrayList
publicArrayList
publicArrayList
publicArrayList
publicFirstFollow3(){
Scannersc=newScanner(System.in);
System.out.println("请分行输入一个完整文法:
(end结束)");
Stringsline="";
sline=sc.nextLine();
while(!
sline.startsWith("end")){
StringBufferbuffer=newStringBuffer(sline);
intl=buffer.indexOf("");
while(l>=0){//去空格
buffer.delete(l,l+1);
l=buffer.indexOf("");
}
sline=buffer.toString();
Strings[]=sline.split("->");//左推导符
if(s.length==1)
s=sline.split("→");//考虑到输入习惯和形式问题
if(s.length==1)
s=sline.split("=>");
if(s.length==1){
System.out.println("文法有误");
System.exit(0);
}
StringTokenizerfx=newStringTokenizer(s[1],"|︱");//按英文隔符拆开产生式或按中文隔符拆开
while(fx.hasMoreTokens()){
String[]one=newString[2];//对于一个语句只需保存两个数据就可以了,语句左部和语句右部的一个简单导出式,假如有或符,就按多条存放
one[0]=s[0];//头不变,0位置放非终结符
one[1]=fx.nextToken();//1位置放导出的产生式,就是产生式右部的一个最简单导出式
in.add(one);
}
sline=sc.nextLine();
}
//求First集过程
this.process("First");
/*
*打印First集算法和First集
*/
System.out.println("\nFirst集算法:
");
this.print(track);//打印First集算法
System.out.println("\nFirst集:
");
for(inti=0;i String[]r=first.get(i); System.out.print("First("+r[0]+")={"); for(intj=1;j System.out.print(r[j]); if(j System.out.print(","); } System.out.println("}"); } track.clear();//因为下面还要用,这里就先清空了 //求Follow集过程 this.process("Follow"); System.out.println("\nFollow集算法: "); for(inti=0;i String[]one=track.get(i); System.out.print("Follow("+follow.get(i)[0]+"): \t"); for(intj=0;j System.out.print(one[j]+"\t"); System.out.println(); } System.out.println("\nFollow集: "); for(inti=0;i String[]r=follow.get(i); System.out.print("Follow("+r[0]+")={"); for(intj=1;j System.out.print(r[j]); if(j System.out.print(","); } System.out.println("}"); } } publicvoidprocess(StringfirstORfollow){ for(inti=0;i booleanbool=true; for(intj=0;j if(in.get(j)[0].equals(in.get(i)[0])) bool=false; if(bool){ ArrayList if(firstORfollow.equals("First")) a=this.getFirst(in.get(i)[0],"First("+in.get(i)[0]+")/"); elseif(firstORfollow.equals("Follow")) a=this.getFollow(in.get(i)[0],in.get(i)[0],""); String[]sf=newString[a.size()/2+1]; String[]st=newString[a.size()/2]; sf[0]=in.get(i)[0]; for(intj=0;j { if(j%2==0) sf[j/2+1]=a.get(j); else st[j/2]=a.get(j); } if(firstORfollow.equals("First")) first.add(sf);//first集 elseif(firstORfollow.equals("Follow")) follow.add(sf); track.add(st);//对应上面求得集的路径,在开始保存该非终结符了,因为已保存了该字符的First或Follow表示法 } } } publicArrayList ArrayList ArrayList if(Character.isUpperCase(s.charAt(0))){//如果是非终结符,大写 for(inti=0;i String[]one=in.get(i); if(s.equals(one[0])){ if(track1.substring(0,track1.length()-9).indexOf("First("+s+")")>=0)//假如在查找过程嵌套了这步,证明进入了无限循环,不需再找,此路径无结果 ;//有点要注意一下,本来一开始就把第一个开始推导符的First路径放进去了的,所以要避开这一次,不然已开始就结束了 elseif(one[1].length()==1||one[1].charAt (1)! ='\''&&one[1].charAt (1)! ='’') result1=getFirst(one[1].charAt(0)+"",track1+"First("+one[1].charAt(0)+")/"); elseif(one[1].length()>1&&one[1].charAt (1)=='\''||one[1].charAt (1)=='’')//假如接下来一个要求First的非终结符带了一撇,那一撇包括英文表示和中文表示 result1=this.getFirst(one[1].substring(0,2),track1+"First("+one[1].substring(0,2)+")/"); result=addArrayString(result,result1); result1.clear(); } } } else{//如果产生式首字符是终结字符 if(s.equals("ε"))//注意: 表示空的字符只能是这种了,其他形式在这个编译器中不能通过,还请原谅 result1.add("#"); else result1.add(s); result1.add(track1);//为了方便,把路径也加入了结果集,不然可能路径不匹配,没办法,因为中间有删去重复项 result=result1; } returnresult; } publicArrayList ArrayList ArrayList if(Character.isUpperCase(s.charAt(0))){ for(inti=0;i String[]one=in.get(i); intslen=s.length(); intolen=one[1].length(); if(element.equals(in.get(0)[0])){//如果是开始符号,或是可以反推到开始符号,证明也可以顺推导开始符号 result1.add("#"); result1.add(in.get(0)[0]+"→"+in.get(0)[0]+"\t"); result=addArrayString(result,result1); result1.clear(); } if(one[1].indexOf(s)>=0&&track1.indexOf((char)('a'+i)+"")>=0)//假如之前走过某一步,就不必再走了,那是死循环,之前在这语句前面加了个else,结果又部分内容显示不出来,总算发现了,就算反推到开始符号,也不一定就到结果了的,开始符号也可以反推,所以要继续 ; elseif(one[1].indexOf(s)>=0&&(olen-slen==one[1].indexOf(s)||slen==2||one[1].charAt(one[1].indexOf(s)+1)! ='’'&&one[1].charAt(one[1].indexOf(s)+1)! ='\'')) {//如果在右产生式中真正存在需要求反推的字符,后面的条件控制它是真正存在,因为里面包含这个字符也不一定是真,就像E’中包含E,但这不是真正的包含 intindex=-1; index=one[1].indexOf(s,0); while(index>=0){//之前这没有用到循环,结果可能少点东西,仔细一想,必须要,就算是一个推导语句,也可能推出多个相同非终结符的组合,其实这也是一种特殊情况了,不考虑也可能正确了,也可能之前在其他地方把这样的结果求出来了,不求也没事,但就像假如要求T的Follow集,假如可以产生出T+a*T*b,这时还是有用的,万一吧 if(olen-slen==index){//如果该非终结符在末尾,那么求导出该产生式的非终结符的倒推 result1=getFollow(one[0],element,track1+(char)('a'+i)); result=addArrayString(result,result1); result1.clear(); }else{//如果后继非终结符在产生式中不是最后 intt=index+slen;//指向在产生式非终结符s的后一个字符位置 result1=returnFirstofFollow(s,element,track1,one[0],one[1],index,t); result=addArrayString(result,result1);//之前也没写这句话,结果把之前的内容覆盖了,就是之前的数据丢失 result1.clear(); } index=one[1].indexOf(s,index+1); }//endwhile } if(one[1].endsWith(element)){//如果最开始要求的Follow集非终结符在末尾 result1.add("#"); result1.add(in.get(0)[0]+"→"+one[1]+"\t"); result=addArrayString(result,result1);//之前也没写这句话,结果把之前的内容覆盖了,就是之前的数据丢失 result1.clear(); } }//endfor } returnresult; } publicArrayList ArrayList ArrayList ArrayList Stringlsh;//记录下一个字符 if(t+1 lsh=one1.substring(t,t+2); else//如果没带一撇,就只要截取一个字母就可以了 lsh=one1.substring(t,t+1); String[]ls=null; intbeflen=2; if(track1.length()>0){//这些都是为了算法输出容易理解点用的,其实要不输出这算法,要省下好多东西 ls=in.get((int)(track1.charAt(track1.length()-1)-'a'));//得到上一步调用的语句 if(Character.isUpperCase(ls[1].charAt(ls[1].length()-1))) beflen=1; } beckFirst=this.getFirst(lsh,"First("+lsh+")/");//相当于得到后继字符的First集 for(intj=0;j Stringlh=""; if(beckFirst.get(j*2).equals("#")){ result1.add(beckFirst.get(j*2));//这个加了是数据,下面一步就是把地址加上,就是一个结果,要两份数据 if(ls==null) lh=in.get(0)[0]+"→"+one1+"→"+one1.substring(0,index)+element+"ε"+one1.substring(t+lsh.length(),one1.length()); else lh=in.get(0)[0]+"→"+one1+"→"+one1.substring(0,index)+ls[1]+one1.substring(index+s.length(),one1.length())+"→."+element+"ε"+one1.substring(t+lsh.length(),one1.length()); result1.add(lh); result=addArrayString(result,result1); result1.clear(); if(1+index+lsh.length() result1=returnFirstofFollow(s,element,track1,one0,one1,index,t+lsh.length()); else//到最后,那么求要求产生式左边的推导非终结符的Follow集了,其实这和上面一种情况都很特殊了,一般用不上了 result1=getFollow(one0,element,track1); } else{//其实下面这一大坨都是为了易懂一点,Follow集算法清晰一点,好苦啊 if(Character.isUpperCase(one1.charAt(t))){//如果是有随后的一个非终结符的First集求出的结果 if(ls==null) lh=in.get(0)[0]+"→"+one1+"→"+one1.substring(0,index)+element+beckFirst.get(j*2)+one1.substring(t+lsh.length(),one1.length()); else lh=in.get(0)[0]+"→"+one1+"→"+one1.substring(0,index)+ls[1]+one1.substring(index+s.length(),one1.length())+"→."+element+beckFirst.get(j*2)+one1.substring(t+lsh.length(),one1.length()); } else{//如果不是大写,就是终结符了,那么用First集求出来的结果连接起来还是一样的,所以不要重复打印两次了 if(ls==null){ if(element==in.get(0)[0]||s.equals(element)) lh=in.get(0)[0]+"→"+one1.substring(0,index)+element+one1.substring(t,one1.length())+"\t"; else lh=in.get(0)[0]+"→"+one1+"→"+one1.substring(0,index)+element+one1.substring(t,one1.length())+"\t"; } else{ if(ls[1].length()==1||ls[1].length()==2&&! ls[1].endsWith("’")&&! ls[1].endsWith("\'")) lh=in.get(0)[0]+"→"+one1+"→"+one1.substring(0,index)+element+one1.substring(t,one1.length()); else lh=in.get(0)[0]+"→"+one1+"→"+one1.substring(0,index)+ls[1]+one1.substring(index+s.length(),one1.length())+"→."+element+one1.substring(t,one1.length())+"! "; } } result1.add(beckFirst.get(j*2));//这个加了是数据,下面一步就是把地址加上,就是一个结果,要两份数据 result1.add(lh); } } result=addArrayString(result,result1);//之前也没写这句话,结果把之前的内容覆盖了,就是之前的数据丢失 result1.clear(); returnresult; } publicArrayList ArrayList for(inti=0;i Strings=a.get(i); if(result.contains(s)||s.equals("")){//如果结果集包含了这个字符串,就不加入结果集了,就是为了去掉重复项 intindex=result.indexOf(s); if(result.get(index+1).length()>a.get(i+1).length()){//如果新来的路径比现有的短 result.set(index,s); result.set(index+1,a.get(i+1)); } continue; } result.add(s); result.add(a.get(i+1));//还是要把路径继续保存在新的结果集中 } for(inti=0;i Strings=b.get(i); if(result.contains(s)||s.equals("")){ intindex=result.in
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- JAVA 语言 编写 编译 原理 FIRST FOLLOW