Java实现消除一切左递归(编译原理实验)

说明: 语法分析是编译程序的核心功能之一。语法分析可以通过确定分析或者不确定分析来实现,在实际的编译器构造中,几乎都是采用确定分析方式。本程序的目的就是将包含左递归的产生式(不确定式)转为等价的右递归产生式(确定式)。
简介: 本程序包含两个类,一个类EliminateLeftRecursive(Eliminate----消除,Left----左,Recursive----递归)用于封装数据的存取(成员变量)以及主要函数(成员方法);一个类Test用于测试,对输入、输出的格式进行一定的约束。
主类结构如下:
在这里插入图片描述
源码如下:

package experiment2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class EliminateLeftRecursive {
    //特殊符号
    public static final char SINGLE_ANGLE_QUOTE = ''';

    public static final String RIGHT_INFER_QUOTE = " → ";

    public static final String REGEX = "\\|";

    public static final char EPSILON = 'ε';

    //非终结符
    public char[] Vn;

    //终结符
    public char[] Vt;

    //产生式
    public Map<String,String> P;

    //开始符号
    public char S;

    public EliminateLeftRecursive(){
        super();
    }

    public EliminateLeftRecursive(char[] Vn,char[] Vt,Map<String,String> P,char S){
        this.Vn = Vn;
        this.Vt = Vt;
        this.P = P;
        this.S = S;
    }

    /**
     * 消除直接左递归,把直接左递归改写为右递归
     *
     * @param left 产生式的左部  一个非终结符A
     * @param right 产生式的右部  形如Aa1 | Aa2 | ... |Aam | b1 | b2 | ... |bn
     *              结果会转换为 A → b1A' | b2A'| ... | bnA'
     *                          A'→ a1A' | a2A'| ... | amA'
     */
    private void eliminateDirectLeftRecursive(String left,String right){
        //用于替换的非终结符(如A')
        String repl = left + SINGLE_ANGLE_QUOTE;
        //以"|"为分隔符对产生式右部进行字符串分隔
        String[] strings = right.split(REGEX);
        //用于拼接A的右部
        StringBuilder r1 = new StringBuilder();
        //用户拼接A'的右部
        StringBuilder r2 = new StringBuilder();
        for(String s : strings){
            if (s.indexOf(left) == 0){//形如Aa1
                r2.append(s.substring(1)).append(repl).append("|");
            }else{//形如b1
                r1.append("|").append(s).append(repl);
            }
        }
        //改为右递归后再加入到产生式P中
        P.put(left,r1.substring(1));
        P.put(repl,r2.append(EPSILON).toString());
    }

    /**
     * 消除文法中一切左递归
     */
    private void eliminateAllLeftRecursive(){
        if (P == null || Vn == null)
            throw new RuntimeException("未初始化相关参数,无法执行!");

        //1、将文法的所有非终结符按字典序升序
        Arrays.sort(Vn);

        //2、循环遍历
        for (int i = 0;i<Vn.length;i++){
            //根据非终结符获取产生式的右部
            String Ai = P.get(Vn[i]+"");
            if (Ai == null)
                throw new RuntimeException("产生式有误");
            StringBuilder sb = new StringBuilder();
            //用于标记当前产生式的右部是否包含左递归
            boolean flag = false;
            for (int j = 0;j<i;j++){
                if(Ai.indexOf(Vn[j]) == 0){
                    //即该产生式包含左递归,可以替换
                    flag = true;
                    String Aj = P.get(Vn[j]+"");
                    if (Aj == null)
                        throw new RuntimeException("产生式有误");
                    //以"|"为分隔符对产生式右部进行字符串分隔
                    String[] Si = Ai.split(REGEX);
                    String[] Sj = Aj.split(REGEX);
                    int k = 0;
                    for(;k<Si.length;k++){
                        if (Si[k].indexOf(Vn[j]) == 0){
                            String ts = Si[k].substring(1);
                            for (String sj : Sj){
                                sb.append(sj).append(ts).append("|");
                            }
                        }else {
                            break;
                        }
                    }
                    for(;k<Si.length;k++) sb.append(Si[k]).append("|");
                    Ai = sb.substring(0,sb.length()-1);
                    sb.setLength(0);
                }

            }
            //消除Ai中的一切直接左递归
            if (flag || Ai.indexOf(Vn[i]) == 0) eliminateDirectLeftRecursive(Vn[i]+"",Ai);
        }

        //3、去掉无用产生式

    }

    /**
     * 格式输入并初始化产生式P与非终结符Vn
     */
    public void inputAndInitialize() throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("输入如下文法的产生式:");
        String line = "";
        StringBuilder sb = new StringBuilder();
        P = new HashMap<>();
        while (!"".equals(line = br.readLine())){
            String[] strings = line.trim().split(RIGHT_INFER_QUOTE);
            sb.append(strings[0]);
            if (P.containsKey(strings[0])){
                P.put(strings[0],P.get(strings[0])+"|"+strings[1]);
            }else {
                P.put(strings[0],strings[1]);
            }
        }
        Vn = sb.toString().toCharArray();
    }


    /**
     * 执行消除文法中一切左递归的算法
     */
    public void run(){
        if (P == null || Vn == null) return;
        eliminateAllLeftRecursive();
    }

    /**
     * 输出消除一切左递归后的文法产生式
     */
    public void output(){
        if (P == null) return;
        System.out.println("消除左递归后的文法为:");
        for (Map.Entry<String,String> entry : P.entrySet()){
            System.out.println(entry.getKey()+RIGHT_INFER_QUOTE+entry.getValue());
        }
    }

    /**
     * 测试
     * @param args
     */
    public static void main(String[] args) {
        /*用例1
        S → Qc|c
        Q → Rb|b
        R → Sa|a
        char[] Vn = {'S','Q','R'},Vt = {'a','b','c'};
        Map<String,String> P = new HashMap<>();
        P.put("S","Qc|c");P.put("Q","Rb|b");P.put("R","Sa|a");
        */

        /*用例2
        A → aB
        A → Bb
        B → Ac
        B → d
        char[] Vn = {'A','B'},Vt = {'a','b','c','d'};
        Map<String,String> P = new HashMap<>();
        P.put("A","Bb|aB");P.put("B","Ac|d");
        */

        char[] Vn = {'S'},Vt = {'a','b'};
        Map<String,String> P = new HashMap<>();
        P.put("S","Sa|b");

        EliminateLeftRecursive eliminateLeftRecursive = new EliminateLeftRecursive(Vn, Vt, P,'S');
        eliminateLeftRecursive.eliminateAllLeftRecursive();
        Map<String,String> rs = eliminateLeftRecursive.P;
        for (Map.Entry<String,String> entry : rs.entrySet()){
            System.out.println(entry.getKey()+eliminateLeftRecursive.RIGHT_INFER_QUOTE+entry.getValue());
        }
    }
}

测试类结构如下:
在这里插入图片描述
源码如下:

package experiment2;

import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        EliminateLeftRecursive eliminateLeftRecursive = new EliminateLeftRecursive();
        eliminateLeftRecursive.inputAndInitialize();
        eliminateLeftRecursive.run();
        eliminateLeftRecursive.output();
    }
}

实验结果如下:
在这里插入图片描述

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

b17a

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值