编译原理:正规式转变成NFA算法

import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;

class Edge{
    private int u, v;
    private char key;
    public Edge(int u, int v, char key) {
        super();
        this.u = u;
        this.v = v;
        this.key = key;
    }
    @Override
    public String toString() {
        return u + "->" + v + " " + key;
    }
}

class NFA{
    private String formal_ceremony;//正规式字符串
    private int cnt_node=1;//记录节点的个数
    private Map<Integer, Integer> endNode = new TreeMap<Integer, Integer>();//每一个开始节点对应的终端节点
    ArrayList<Edge> nodeAl = new ArrayList<Edge>();
    public NFA(String formal_ceremony) {
        super();
        this.formal_ceremony = formal_ceremony;
    }

    public boolean    kernel_way(int fa, int ld, int rd, boolean isClosure){//fa表示区间的开始点,正规式的区间[ld, rd], isClosure表示这段区间查是否存在闭包
        if(ld < 0 || rd >= formal_ceremony.length()){
            System.out.println("正规式不正确---发生数组越界!");
            return false;
        }
        int pre_node = fa;
        int inBracket = 0;//判断‘|‘是否在括弧内
        for(int i=ld; i<=rd; ++i){
            if(formal_ceremony.charAt(i)==‘(‘) ++inBracket;
            else if(formal_ceremony.charAt(i)==‘)‘) --inBracket;
            else if(formal_ceremony.charAt(i)==‘|‘ && 0==inBracket){
                if(!kernel_way(fa, ld, i-1, isClosure)) return false;
                if(!kernel_way(fa, i+1, rd, isClosure)) return false;
                return true;
            }
        }
        for(int i=ld; i<=rd; ++i){
            if(formal_ceremony.charAt(i)==‘(‘){//又是一个子区间
                //寻找和 该 ‘(‘相匹配的‘)‘
                int cntLeftBracket = 0;//统计遍历过程中‘(‘出现的次数,遇到‘)‘减去1
                int posRightBracket = -1;//记录相匹配的‘)‘的位置
                int posLeftBracket = i;
                for(int j=i+1; j<=rd; ++j){
                    if(formal_ceremony.charAt(j)==‘(‘)
                        ++cntLeftBracket;
                    else if(formal_ceremony.charAt(j)==‘)‘){
                        if(cntLeftBracket == 0){
                            posRightBracket = j;
                            break;
                        }
                        --cntLeftBracket;
                    }
                }
                if(posRightBracket == -1){//出错
                    System.out.println("正规式出错----括弧不匹配!");
                    return false;
                }
                int nodeFather = 0;//括弧内正则式的开始节点
                if(posRightBracket+1 <= rd && formal_ceremony.charAt(posRightBracket+1)==‘*‘){
                    i = posRightBracket+1;//过滤掉"()*"
                    nodeAl.add(new Edge(pre_node, ++cnt_node, ‘$‘));//表示这一条边为空
                    pre_node = cnt_node;
                    nodeFather = cnt_node;
                    nodeAl.add(new Edge(pre_node, ++cnt_node, ‘$‘));//表示这一条边为空
                    pre_node = cnt_node;
                    //处理()*括弧内的正规式
                    if(!kernel_way(nodeFather, posLeftBracket+1, posRightBracket-1, true)) return false;
                } else {
                    nodeFather = pre_node;
                    if(!kernel_way(nodeFather, posLeftBracket+1, posRightBracket-1, false))//对于"(101)", 看成101
                        return false;
                    i = posRightBracket;
                }

            } else {//单个字符
                if(formal_ceremony.charAt(i)==‘)‘) continue;
                if(i+1 <= rd && formal_ceremony.charAt(i+1)==‘*‘){
                    nodeAl.add(new Edge(pre_node, ++cnt_node, ‘$‘));//表示这一条边为空
                    pre_node = cnt_node;
                    nodeAl.add(new Edge(pre_node, pre_node, formal_ceremony.charAt(i)));//自身到自身一条边
                    if(i+1==rd  && isClosure)
                        nodeAl.add(new Edge(pre_node, fa, ‘$‘));//表示这一条边为空并且是连接到父亲节点
                    else{
                        if(endNode.containsKey(fa))
                            nodeAl.add(new Edge(pre_node, endNode.get(fa), ‘$‘));
                        else{
                            nodeAl.add(new Edge(pre_node, ++cnt_node, ‘$‘));//表示这一条边为空
                            if(i==rd) endNode.put(fa, cnt_node);//记录非闭包状态下 第一个节点对应的最后一个节点
                        }
                    }
                    pre_node = cnt_node;
                    ++i;//过滤*
                } else {
                    if(i==rd && isClosure){//是闭包的情况
                        nodeAl.add(new Edge(pre_node, fa, formal_ceremony.charAt(i)));
                    } else{
                        if(endNode.containsKey(fa))
                            nodeAl.add(new Edge(pre_node, endNode.get(fa), formal_ceremony.charAt(i)));
                        else{
                            nodeAl.add(new Edge(pre_node, ++cnt_node, formal_ceremony.charAt(i)));
                            if(i==rd) endNode.put(fa, cnt_node);//记录非闭包状态下 第一个节点对应的最后一个节点
                        }
                    }
                    pre_node = cnt_node;
                }
            }
        }
        return true;
    }

    public void outputNFA(){
        for(Edge e : nodeAl)
            System.out.println(e);
    }
}

/*
 * 将正规式转换成NFA
 * */
public class ToNFA {

    public static void main(String[] args){
//        String formal_ceremony = "1(1010*|1(010)*1)*0";
//        String formal_ceremony = "1(0|1)*101";
//        String formal_ceremony = "0*1*(010)0*1*";
//        String formal_ceremony = "(0|1|2)*";
//        String formal_ceremony = "0|1";
//        String formal_ceremony = "0|1|2|3";
//        String formal_ceremony = "(0|1|6)|(2|3)|(4|5)";
//        String formal_ceremony = "(0|1)*|(2|3)*";
        String formal_ceremony = "((10)|(01)*|(0|1))";
        NFA nfa = new NFA(formal_ceremony);
        if(nfa.kernel_way(1, 0, formal_ceremony.length()-1, false))
            nfa.outputNFA();
    }
}
时间: 2024-08-06 11:31:52

编译原理:正规式转变成NFA算法的相关文章

编译原理——正规式转DFA算法概述

一.概念概述 给定一个单词,判断该单词是否满足我们给定的单词描述规则,需要用到编译原理中词法分析的相关知识,其中涉及到的两个很重要的概念就是正规式(Regular Expression)和有穷自动机(Finite Automata).正规式是描述单词规则的工具,首先要明确的一点是所有单词组成的是一个无穷的集合,而正规式正是描述这种无穷集合的一个工具:有穷自动机则是识别正规式的一个有效的工具,它分为确定的有穷自动机(Deterministic Finite Automata,DFA)和不确定的有穷

编译原理-正规式和正规集

2正规式和正规文法之间转换规则 规则2看不懂 http://blog.csdn.net/yuyunli1989/article/details/7524701

编译原理知识汇总

转自:https://www.jianshu.com/p/eb63d31ad638 编译原理 第一章 引言 1.从面向机器的语言到面向人类的语言 汇编指令:用符号表示的指令被称为汇编指令 汇编语言:汇编指令的集合称为汇编语言 2.语言之间的翻译 转换(也被称为预处理):高级语言之间的翻译,如FORTRAN到ADA的转换 编译:高级语言可以直接翻译成机器语言,也可以翻译成汇编语言,这两个翻译过程称为编译 汇编:从汇编语言到机器语言的翻译被称为汇编 交叉汇编:将一个汇编语言程序汇编成为可在另一机器上

编译原理简单介绍

编译原理学习导论 大学课程为什么要开设编译原理呢?这门课程关注的是编译器方面的产生原理和技术问题,似乎和计算机的基础领域不沾边,可是编译原理却一直作为大学本科的必修课程,同时也成为了研究生入学考试的必考内容.编译原理及技术从本质上来讲就是一个算法问题而已,当然由于这个问题十分复杂,其解决算法也相对复杂.我们学的数据结构与算法分析也是讲算法的,不过讲的基础算法,换句话说讲的是算法导论,而编译原理这门课程讲的就是比较专注解决一种的算法了.在20世纪50年代,编译器的编写一直被认为是十分困难的事情,第

编译原理学习导论

编译原理学习导论 大学课程为什么要开设编译原理呢?这门课程关注的是编译器方面的产生原理和技术问题,似乎和计算机的基础领域不沾边,但是编译原理却一直作为大学本科的必修课程,同一时候也成为了研究生入学考试的必考内容.编译原理及技术从本质上来讲就是一个算法问题而已,当然因为这个问题十分复杂,其解决算法也相对复杂.我们学的数据结构与算法分析也是讲算法的,只是讲的基础算法,换句话说讲的是算法导论,而编译原理这门课程讲的就是比較专注解决一种的算法了.在20世纪50年代,编译器的编写一直被觉得是十分困难的事情

转载 为什么要学习编译原理

转载 为什么要学习编译原理 学课程为什么要开设编译原理呢?这门课程关注的是编译器方面的产生原理和技术问题,似乎和计算机的基础领域不沾边,可是编译原理却一直作为大学本科的必修课程,同时也成为了研究生入学考试的必考内容.编译原理及技术从本质上来讲就是一个算法问题而已,当然由于这个问题十分复杂,其解决算法也相对复杂.我们学的数据结构与算法分析也是讲算法的,不过讲的基础算法,换句话说讲的是算法导论,而编译原理这门课程讲的就是比较专注解决一种的算法了.在20世纪50年代,编译器的编写一直被认为是十分困难的

编译原理书籍推荐

大学课程为什么要开设编译原理呢?这门课程关注的是编译器方面的产生原理和技术问题,似乎和计算机的基础领域不沾边,可是编译原理却一直作为大学本科的必修课程,同时也成为了研究生入学考试的必考内容.编译原理及技术从本质上来讲就是一个算法问题而已,当然由于这个问题十分复杂,其解决算法也相对复杂.我们学的数据结构与算法分析也是讲算法的,不过讲的基础算法,换句话说讲的是算法导论,而编译原理这门课程讲的就是比较专注解决一种的算法了.在20世纪50年代,编译器的编写一直被认为是十分困难的事情,第一Fortran的

编译原理:正规式、正规文法与自动机

1.正规式转换到正规文法 对任意正规式R选择一个非终结符Z生成规则Z→R 1.对形如A→ab的规则,转换成A→aB,B→b 2.将形如A→a|b的规则,转换成A→a,A→b(A→a|b) 3.将形如A→a*b的规则,转换成A→aA,A→b 将形如A→ba*的规则,转换成A→Aa,A→b 不断利用上述规则进行转换,直到每条规则最多含有一个终结符为止. 1(0|1)*101 解析: S-> A1 A-> B0 B-> C1 C-> 1(0|1)* -> 1|C0|C1 (a|b)

编译原理:正规文法与正规式

1.分别写出描述以下语言的正规文法和正规式: L1={abna|n≥0}. L2={ambn|n≥1,m ≥1} L3={(ab)n|n≥1} 解析: (1)设文法G(S)={abna|n≥0} 正规文法: S → aA A → Ba B → bn B → bB|ε 正规式: B = ε + bB = b* A = Ba = b*a S = ab*a (2)设文法G(S)={ambn|n≥1,m ≥1} 正规文法: S → AB A → aA|a B → bB|b 正规式: A = aA + a