Mess_ LL(1) First Set——递归实现

// 看了看网上挺多都是非递归,写了很长
// 想要个递归的,短点的
// 到处瞎逛的时候发现了这个,感觉写的很好,我通读了一遍,补了点注释,让大家借鉴下..
// 忘了是从哪里扒来的.. 如果有需要删除请联系我
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.StringTokenizer;

public class Ex3 {
    public List<String[]> in = new ArrayList<String[]>();       // 这存放的是拆分后最简单的生成子式
    public List<String[]> result = new ArrayList<String[]>();   // 包括左推导符和其 First Set

    public void start() {

        this.preprocess();  // 预处理

        this.process();     // 处理逻辑

        this.output();      // 输出

    }

    private void preprocess() {
        Scanner sc = new Scanner(System.in);
        System.out.println("请分行输入一个完整文法:(end结束)");
        String sLine = "";
        sLine = sc.nextLine();
        while (!sLine.startsWith("end")) {
            String[] strings = sLine.split("->");     // 默认的推导符
            if (strings.length == 1)
                strings = sLine.split("→");          // 考虑到推导符不同,再分一次
            if (strings.length == 1) {
                System.out.println("文法有误");
                System.exit(0);
            }


            if (!Character.isUpperCase(strings[0].charAt(0))) {
                System.out.println("文法有误");         // 左推导符号不为终结符
                System.exit(0);
            }


            StringTokenizer fx = new StringTokenizer(strings[1], "|");
            while (fx.hasMoreTokens()) {
                String[] sub = new String[2];   // 将可能的多条分支分解成一条条产生子式(subProduction)
                sub[0] = strings[0];            // 左边依旧放非终结符
                sub[1] = fx.nextToken();        // 右边放多条分支的其中一条
                in.add(sub);
            }
            sLine = sc.nextLine();
        }
    }

    public void process() {
        for (int i = 0; i < in.size(); i++) {
            boolean isFirstSub = true;                        // 是否是该非终结符的第一个产生子式
            for (int j = 0; j < i; j++)
                if (in.get(j)[0].equals(in.get(i)[0]))        // 遍历比较当前i锚点之前的所有产生式的头部
                    isFirstSub = false;                       // 当前i指向的非第一产生子式
            if (isFirstSub) {
                ArrayList<String> firstSet;
                firstSet = this.getFirst(in.get(i)[0]);                 //  求出 First
                firstSet.add(0, in.get(i)[0]);                    // 构造完毕,数组可以随意更改,插入 Vn
                String[] vn_firstSet = firstSet.toArray(new String[0]); // 构造 vn-firstSet
                result.add(vn_firstSet);                                // 放入结果集中
            }
        }
    }

    /*
     *      递归函数
     *  s 可以表示非终结符 或者 终结符
     *  s 为终结符,则返回自身
     *  s 为非终结符,则返回其 First Set
     * */
    public ArrayList<String> getFirst(String s) {
        ArrayList<String> result = new ArrayList<String>();
        ArrayList<String> middle = new ArrayList<String>();
        if (Character.isUpperCase(s.charAt(0))) {                   // 递归时判定是否为非终结符,只看第一位是考虑 E'
            for (int i = 0; i < in.size(); i++) {
                String[] sub = in.get(i);
                if (s.equals(sub[0])) {                             // 确定当前要处理的子式

                    int k = 0;

                    middle = getFirst(sub[1].charAt(k) + "");    // 递归求右式一位的 First

                    for (int j = 0; j < middle.size(); j++) {

                        result.add(middle.get(j));                  // 将右边一位的 First 据为己有

                        while (middle.get(j).equals("ε") && (++k < sub[1].length())) {
                            // 对于可能出现 ε 的情况,就是有可能要往下递归的情况
                            // 判断当前递归是否是最后一轮递归
                            // 不是,则进入循环,继续递归

                            middle = getFirst(sub[1].charAt(k) + "");    // 递归取右边第k+1位的First k>=1
                            for (int l = 0; l < middle.size(); l++) {
                                if (!middle.get(l).equals("ε"))
                                    // 如果为空,说明:1.非空元素已经全部取完 2.需要判断是否往下递归,即跳出循环
                                    result.add(middle.get(l));
                            }
                        }
                    }
                }
            }
        } else {
            result.add(s);
        }
        return result;
    }

    private void output() {
        System.out.println("\nFirst Set:");
        for (int i = 0; i < result.size(); i++) {
            // get non-terminal
            String[] vn_firstSet = result.get(i);
            System.out.print("First(" + vn_firstSet[0] + ")={");

            for (int j = 1; j < vn_firstSet.length; j++) {
                // First Set content
                System.out.print(vn_firstSet[j]);
                if (j < vn_firstSet.length - 1)
                    System.out.print(",");
            }
            System.out.println("}");
        }
    }

    public static void main(String[] args) {
        Ex3 ex3 = new Ex3();
        ex3.start();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值