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

依旧是编译的上机作业,第四次的了吧。
做一个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();
    }
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值