编译作业——LR文法的语法分析器
2016-11-23 12:39
183 查看
依旧是编译的上机作业,第四次的了吧。
做一个LR的语法分析器。
文法是
然后如果用这个文法推LR(1)的状态,状态太多了,所以我换了一个,用
这个有二义性,左递归的文法推,只有10个状态,好手写分析表,同时里面还用了上一次作业的部分代码,以下是代码部分。
做一个LR的语法分析器。
文法是
E->E+T | T T->T*F | F F->(E) | id
然后如果用这个文法推LR(1)的状态,状态太多了,所以我换了一个,用
E->E+E|E*E|(E)|id
这个有二义性,左递归的文法推,只有10个状态,好手写分析表,同时里面还用了上一次作业的部分代码,以下是代码部分。
import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; public class ThirdHW { static String E="E",Ee="E'",T="T",Tt="T'",F="F",//代表各种非终结符 //synch="synch",//同步记号,用于标记错误 id="id";//一个终结符 static Set<String> unLimitedSign=new HashSet<String>(); static{//初始化 非终结符的集合 unLimitedSign.add(E); /* unLimitedSign.add(Ee); unLimitedSign.add(T); unLimitedSign.add(Tt); unLimitedSign.add(F); */ } //下面两个变量有违封装原则,不过东西小,看不出影响 static Integer timeForPutToMap=0;//全局变量用于下面的putToMap方法 static Map<String,Map<String,Action>> table=new HashMap<String,Map<String,Action>>();//全局变量,一个Action表 //用于构建诸如s3,r1,e1这样形式的一个类 static class Action{ String SorR; int state; public Action(String SorR,Integer state){ this.SorR=SorR; this.state=state; } public String getSorR(){ return SorR; } public int getState(){ return state; } @Override public String toString(){ return SorR+" "+state; } } public static Map<Integer,List<String>> produceEquation(){ Map<Integer,List<String>> ProduceEquation=new HashMap<Integer,List<String>>(); List<String> temp=new ArrayList<String>(); temp=fullList(new String[]{E,"+",E}); ProduceEquation.put(1,temp); temp=fullList(new String[]{E,"*",E}); ProduceEquation.put(2,temp); temp=fullList(new String[]{"(",E,")"}); ProduceEquation.put(3,temp); temp=fullList(new String[]{id}); ProduceEquation.put(4,temp); return ProduceEquation; } //goto表,没错,分析表action部分和goto部分是分开的,很奇葩 //原因是这样写方便(个人认为) //Action的对象,不用和数字放在一个map里,泛型用起来舒服了 public static Map<String,Integer> GotoTable(){ Map<String,Integer> gotoTable=new HashMap<String,Integer>(); gotoTable.put("0",1); gotoTable.put("2",6); gotoTable.put("4",7); gotoTable.put("5",8); return gotoTable; } //action表,没错,分析表action部分和goto部分是分开的,很奇葩 public static Map<String,Map<String,Action>> ActionTable(){ Map<String,Action> tempList=null; String s="s",e="e",r="r"; tempList=fullList(new Object[]{s,3,e,1,e,1,s,2,e,2,e,1}); putToMap(tempList); tempList=fullList(new Object[]{e,3,s,4,s,5,e,3,e,2,"a",-1}); putToMap(tempList); tempList=fullList(new Object[]{s,3,e,1,e,1,s,2,e,2,e,1}); putToMap(tempList); tempList=fullList(new Object[]{r,4,r,4,r,4,r,4,r,4,r,4}); putToMap(tempList); tempList=fullList(new Object[]{s,3,e,1,e,1,s,2,e,2,e,1}); putToMap(tempList); putToMap(tempList); tempList=fullList(new Object[]{e,3,s,4,s,5,e,3,s,9,e,4}); putToMap(tempList); tempList=fullList(new Object[]{r,1,r,1,s,5,r,1,r,1,r,1}); putToMap(tempList); tempList=fullList(new Object[]{r,2,r,2,r,2,r,2,r,2,r,2}); putToMap(tempList); tempList=fullList(new Object[]{r,3,r,3,r,3,r,3,r,3,r,3}); putToMap(tempList); return table; } //用于生成分析表的Action部分 //不想很傻地一个一个增添状态对应的条目,每次都写table.put((一个数字),tempList)干脆自动化一点 //缺点是引入了一个全局变量timeForPutToMap public static void putToMap(Map<String,Action> tempList){ table.put(timeForPutToMap.toString(),tempList); timeForPutToMap++; } /** * 传入一个数组,填充成一个List,输入成对的String,int组合,每一对组合成一个Action * @param object []args,注意,是偶数个,成对出现的的String、int * @return List<Action> */ private static Map<String,Action> fullList(Object[] args){ Map<String,Action> temp=new HashMap<String,Action>(); String []SQE=new String[]{id,"+","*","(",")","$"}; for(int i=0;i<args.length;i+=2){ Action a=new Action((String)args[i], (Integer)args[i+1]); temp.put(SQE[i/2],a); } return temp; } /** * 传入一个数组,填充成一个List * @param object []args * @return List<String> */ private static List<String> fullList(String[] args){ List<String> temp=new ArrayList<String>(); for(String s:args){ temp.add(s); } return temp; } public static void main(String []args){ Map<String, Map<String, Action>> actionTable=ActionTable(); Map<String,Integer> gotoTable=GotoTable(); Map<Integer,List<String>> ProduceEquation=produceEquation(); LinkedList<String> stack=new LinkedList<String>(); stack.addFirst("0"); int point=0; boolean successFlag=false; /* Scanner sc=new Scanner(System.in); System.out.println("输入一个记号流的串,注意每个终结符需要以空格隔开 "); String[] test=sc.nextLine().split(" "); sc.close(); */ //输入记号流 //三个测试用例 //String[] test=new String[]{id,"+",id,"*",id,"$"}; String[] test=new String[]{id,id,"$"}; //String[] test=new String[]{"(",")","$"}; //String[] test=new String[]{id,"*",id,"+",")",id,"$"}; //String[] test=new String[]{id,"*","+",")",id,id,"$"}; while(point<test.length){ Action a=actionTable.get(stack.getFirst()).get(test[point]); //出错处理 //没有default处理 if(a.getSorR().equals("e")){ switch(a.getState()){ case 1: System.out.println("缺少运算对象,可能是运算符输入过多,默认做‘移入一个id’处理"); error(test,point); //point++; stack.addFirst(id); stack.addFirst("3"); break; case 2: System.out.println("不匹配的右括号"); error(test,point); point++; break; case 3: System.out.println("缺少算符,可能是运算对象输入过多,默认做‘移入一个+’处理"); error(test,point); //point++; stack.addFirst("+"); stack.addFirst("4"); break; case 4: System.out.println("缺少右括号"); error(test,point); //point++; stack.addFirst(")"); stack.addFirst("9"); break; } }else if(a.getSorR().equals("s")){//移进 System.out.println(stack.toString()); printString(test, point); stack.addFirst(test[point]); System.out.println("移进"+test[point]); System.out.println("==========="); point++; stack.addFirst(((Integer)a.getState()).toString()); }else if(a.getSorR().equals("r")){//归约 System.out.println(stack.toString()); printString(test, point); //规约弹栈的操作 for(int i=0;i<ProduceEquation.get(a.getState()).size();){//缺省一条语句,没错,只有移出非终结符和终结符时i++,其他时候仅仅是移出,i不变 if(!stack.removeFirst().matches("[0-9]+")){ i++; } } //记录栈顶状态的临时量 Integer state=Integer.parseInt(stack.getFirst()); //栈顶压入非终结符 stack.addFirst(E); //通过非终结符和栈顶状态的临时量,定位新的栈顶状态,入栈 stack.addFirst(gotoTable.get(state.toString()).toString()); System.out.println("归约,使用产生式:E->"+ProduceEquation.get(a.getState())); System.out.println("==========="); }else if(a.getSorR().equals("a")){//接受 successFlag=true; System.out.println(stack.toString()+"->acc"); System.out.println("接受,识别结束"); break; } } if(!successFlag){ System.out.println("识别结束,输入串有问题"); } } /** * 用于从指定位置输出一个数组的一部分 * @param args 要输出的数组 * @param index 指定的输出起点 */ public static void printString(String[] args,int index){ for(int i=index;i<args.length;i++){ System.out.print(args[i]); } System.out.println(); } /** * 用于展示输入记号流的出错位置 * @param args 输入的记号流,终结符的数组 * @param index 出错的位置 */ public static void error(String[] args,int index){ for(int i=0;i<args.length;i++){ System.out.print(args[i]+"\t"); } System.out.println(); for(int i=0;i<args.length;i++){ if(i==index){ System.out.print("↑这里有错"); }else System.out.print("\t"); } System.out.println(); } }
相关文章推荐
- 编译作业——LL(1)文法的语法分析器
- 编译原理(九) LR(0)文法分析法(算法描述和C++代码实现)
- 【编译原理】LL1文法语法分析器
- 编译原理 LR文法
- 编译原理(九) LR(0)文法分析法-算法描述
- 编译原理与编译构造 LR文法
- 编译原理之LL(1) 、LR(0)、SLR、LR(1)、LALR文法的对比
- 编译原理(九) LR(0)文法分析法(算法描述和C++代码实现)
- 编译原理_简单优先文法_语法分析器_Java
- 编译原理:LL(1)文法 语法分析器(预测分析表法)
- 编译原理:LL(1)文法 语法分析器(预测分析表法)
- 编译原理上机作业4——LR(0)分析的DFA生成
- 【编译原理】语法分析器
- 武汉大学编译原理第三次作业
- VC++环境下的LR语法分析器实现
- 编译原理之文法一
- 编译原理 之 语法分析器(自上而下分析法)
- OOAD作业--ubuntu 12.04LTS 64bit编译安装Opencv2.4.3
- 实践作业之编译安装LAMP
- 编译技术的作业笔记