编译作业——LR文法的语法分析器

来源:互联网 发布:知乎 国开博裕和博裕 编辑:程序博客网 时间:2024/05/19 14:52

依旧是编译的上机作业,第四次的了吧。
做一个LR的语法分析器。
文法是

E->E+T | TT->T*F | FF->(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();    }}
0 0
原创粉丝点击