编译原理文法推导(java实现)

基本原理:

        深度优先算法(DFS)。直接一条路走到黑,不行的话再回头,但是如果真的只是等着DFS的递归返回的话,会慢的吓人,所以里面应该加几个判断,在当前这个阶段就可以判断我们推出来的和目标推导式肯定不一样就可以直接返回,这样会快很多。

代码如下:

import java.io.*;
import java.util.*;
class formulate {
    private String string;  //待推导的字符串
    LinkedList<String> grammar= new LinkedList<>();  //文法
    LinkedList<String> analysis= new LinkedList<>();  //推导式
    formulate(String string) {
        this.string = string;
    }
    String getString(){
        return string;
    }
}
public class Grammar_Analysis {
    private final static int maxlength = 20;  //推导的最长步数
    private static boolean flag;
    private static HashMap<String, LinkedList<String>> list;  //全局文法表
    private static Set<String> set;  //非终结符集
    private static formulate f;
    private static HashMap<String, LinkedList<String>> grammar() throws IOException{  //得到存储文法的结构
        BufferedReader read = new BufferedReader(new InputStreamReader(new FileInputStream(".//data1.txt")));
        String str;  //保存从文件中读取的文法
        LinkedList<String> l;  //存储每条文法
        HashMap<String, LinkedList<String>> list = new HashMap<>();  //保存所有文法
        while((str = read.readLine()) != null) {
            String s = str.charAt(0) + "";  //保留开头
            String ss = str.substring(4);
            String[] str2 = ss.split("\\|");  //每个字符串表示一种文法候选
            l = new LinkedList<>(Arrays.asList(str2));
            list.put(s, l);
        }
        read.close();
        return list;
    }
    private static void grammar_Analysis(String string) {  //分析推导过程
        if (f.analysis.size() >= maxlength)  //推导步数过多返回
            return;
        if (!f.analysis.isEmpty()) {  //推导出的长度大于目的推导式或者推导式第一位是终结符但是与目的推导式不等返回
            int index = f.analysis.getLast().indexOf(">");
            String sss = f.analysis.getLast().substring(index+1);
            if ((sss.length()>f.getString().length()) || ((!set.contains(sss.charAt(0)+"")) && f.getString().charAt(0) != sss.charAt(0)))
                return;
        }
        if (string.equals(f.getString())) {  //推导成功
            flag = true;
            return;
        }
        for (int i = 0; i < string.length(); i++)
            if (set.contains(string.charAt(i) + "")) {  //是非终结符,可继续推导
                for (String l : list.get(string.charAt(i) + "")) {  //对可推导的每一个候选式进行选择
                    String str = string;
                    str = str.replaceFirst(str.charAt(i) + "", l);
                    f.grammar.addLast(string.charAt(i) + "-->" + l);
                    f.analysis.addLast(string + "-->" + str);
                    grammar_Analysis(str);
                    if (flag)
                        return;
                    else {
                        f.grammar.removeLast();
                        f.analysis.removeLast();
                    }
                }
            }
    }
    private static void print(){  //输出函数
        System.out.println("使用的文法\t\t推导式");
        for (int i = 0; i < f.grammar.size(); i++) {
            System.out.println(f.grammar.get(i) + "\t\t\t" + f.analysis.get(i));
        }
        System.out.println();
    }
    public static void main(String[] args) throws IOException{
        list = grammar();  //文法HashMap<String, LinkedList<String>>
        set = list.keySet();  //非终结符集
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(".//data2.txt")));
        String str;
        while ((str = reader.readLine()) != null) {
            f = new formulate(str);
            flag = false;
            grammar_Analysis("S");
            System.out.println("本次待推导式为:" + f.getString());
            print();
        }
        reader.close();
//        Scanner sc = new Scanner(System.in);
//        System.out.println("请输入待推导式:");
//        String str = sc.nextLine();
//        f = new formulate(str);
//        flag = false;
//        grammar_Analysis("S");
//        System.out.println();
//        print();
//        sc.close();
    }
}

得到的知识点:

1.LinkedList<String> l = new LinkedList<>(Arrays.asList(str))

    可直接将字符串数组转为字符串链表

2.正则表达式中如果含有“|”的话,需要加双斜杠进行转义

3.如果使用类中的成员,在循环中调用了并且改变了值的情况下,每次调用前要重新赋值

4.编译器肯定不会错,肯定是程序错了。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值