编译原理:从正则表达式到NFA,python实现

编译原理:从正则表达式到NFA,python实现

两年前编译原理课的实验一,从正则表达式生成NFA,使用的Thompson算法,具体原理不再阐述(我也不太记得了),不过代码里写了注释~

  • 理论请参考其他大神的博客:https://blog.csdn.net/moodfriend/article/details/106011361
stateNum=0
a=[]

#读入写有re的文本文件,先暂定为
def ReadRe():
    file = open("/home/TerryLee/PycharmProjects/pythonProject1/sample",'r')
    REs=[]

    while 1:
        line = file.readline()
        REs.append(line)
        print(type(REs[0]))
        if not line:
            break

            pass

        # for item in a:
        #     print(item)
    return REs



#Thompson算法的第一步是要将正则表达式(中缀形式)转为后缀形式
def Thompson(re):
    '''用一个字典来表示运算符的优先级'''
    ops={'*':5,'.':4,'|':3}

    postfix=""
    stack=""

    '''将中缀表达式表达式转化为后缀表达式'''
    for a in re:
        '''()的优先级最高,首先讨论'''
        if a=="(":
            stack=stack+a

        elif a==")":
            #print(stack)
            '''读入)以后,就将)之前直到(的所有运算符输出,再让(出栈,不输出括号的原因是后缀表达式不需要括号也能表示优先级'''
            while stack[-1]!="(":
                postfix,stack= postfix+stack[-1],stack[:-1]
            stack=stack[:-1]  #删除")"

        elif a in ops:
            '''新进入栈的运算符优先级如果比栈内的运算符优先级高,直接入栈。否则就把栈内的高优先级的运算符依次出栈,加入后缀表达式中,读入的运算符则是入栈'''
            while stack and ops.get(a,0)<=ops.get(stack[-1],0):
                postfix,stack=postfix+stack[-1],stack[:-1]
            stack=stack+a#新读入的运算符入栈

        else:
            postfix=postfix+a#字符直接进入后缀表达式队列

    '''#读完后,将栈内元素依次出栈'''
    while stack:
        postfix,stack=postfix+stack[-1],stack[:-1]
    return postfix



#创建NFA类,由于我们不生成图片一样的NFA,所以我们用边来指代NFA
class NFA:
    def __init__(self,start,end):
        self.start=start
        self.end=end

#NFA的状态类
class State:
    def __init__(self,isEnd,StateNum):
        self.StateNum=StateNum #属性的State首字母大写与全局变量区分
        self.isEnd=isEnd#
        self.transfunction={} #通过字符能到达的状态,用字典表示,key代表转换条件字符,value代表所对应的状态
        self.epsilon=[] #空字符转换

def createState(isEnd):
    global stateNum
    global a
    stateNum = stateNum + 1
    state=State(isEnd,stateNum)
    a.append(state)

    print("创建%d节点"%stateNum)
    return state

#创建两种比较基础的NFA
def add_Epsilon_for_state(come, to):
    come.epsilon.append(to)

def add_Symbol_for_States(come, to, symbol):
    come.transfunction[symbol]=to


def Epsilon_Transition():
    start=createState(False)
    end=createState(True)
    start.epsilon.append(end)  # 将空转换能达到的状态放置在同一个list中

    return start,end


def Symbol_Transition(symbol):
    start=createState(False)
    end=createState(True)
    start.transfunction[symbol]=end

    return start,end

'''创建某个字符的NFA'''
def createNFA(symbol):
    start,end=Symbol_Transition(symbol)
    return NFA(start,end)


'''创建字符a|b的NFA:NFA(a)|NFA(b)→NFA(a|b)'''
def union(first,second): #这里的first和second分别代表NFA(a)和NFA(b)
    start = createState(False) #这个节点就是两个空跳转的起始节点
    end=createState(True)

    #创建前两个空跳转
    add_Epsilon_for_state(start, first.start)
    add_Epsilon_for_state(start, second.start)

    #创建后两个节点的空跳转
    add_Epsilon_for_state(first.end, end)
    first.end.isEnd=False
    add_Epsilon_for_state(second.end, end)
    first.end.isEnd=False

    return NFA(start,end)

#创建闭包的NFA
def Closure(nfa):
    start=createState(False)
    end=createState(True)

    add_Epsilon_for_state(start, end)
    add_Epsilon_for_state(start, nfa.start)

    add_Epsilon_for_state(nfa.end, end)
    add_Epsilon_for_state(nfa.end, nfa.start)

    nfa.end.isEnd=False

    return NFA(start,end)

#创建a.b类型的NFA
def connect(first,second):
    print("first.start%d"%first.start.StateNum)
    print("first.end%d" % first.end.StateNum)
    print("second.start%d" % second.start.StateNum)
    print("second.end%d" % second.end.StateNum)
    add_Epsilon_for_state(first.end, second.start)
    first.end.isEnd=False

    return NFA(first.start,second.end)


'''   最终NFA的得出
创建一个栈stack,从左往右读取后缀表达式:
    1.若读取的是某个字符a,则创建NFA(a),入栈
    2.若读取的是某个操作符,则弹出栈中的内容,创建相关的NFA,再次入栈!
'''

def FinalNFA(postfix):
    if postfix=='':
        return Epsilon_Transition()
    stack=[]
    for chr in postfix:
        if chr ==".":
            print("读入字符%s" % chr)
            nfa1=stack.pop()
            nfa2=stack.pop()
            new_nfa=connect(nfa2,nfa1)
            stack.append(new_nfa)

        elif chr=="|":
            print("读入字符%s" % chr)
            nfa1 = stack.pop()
            nfa2 = stack.pop()
            new_nfa=union(nfa1,nfa2)
            stack.append(new_nfa)

        elif chr=="*":
            print("读入字符%s" % chr)
            nfa=stack.pop()
            new_nfa=Closure(nfa)
            stack.append(new_nfa)

        else:
            print("读入字符%s"%chr)
            nfa=createNFA(chr)
            stack.append(nfa)

    return stack.pop()

def print_NFA(a):
    #items代表每个状态
    print("-------------------")
    print("得到的NFA如下表示:")
    for items in a:
        #输出每个节点的epsilon变迁,item代表每个当前状态能通过epsilon变迁到达的节点
        for item in items.epsilon:
            #print("%d---epsilon--->%d"%(item.StateNum,items.StateNum))
            print("%d---epsilon--->%d"%(items.StateNum,item.StateNum))
        #输出每个节点的变迁:
        for item in items.transfunction:
            #1---a--->3
            #print(type(items.transfunction))
            print("%d------%s------>%d"%(items.StateNum,item,items.transfunction[item].StateNum))



def main():
    re="a|b"
    #ReadRe(path)

    postfix = Thompson(re)#先转换成为后缀表达式
    print("所求正则表达式的逆波兰式:%s"%postfix)
    nfa=FinalNFA(postfix)
    #print(len(a))
    #print(a[1].epsilon)
    print_NFA(a)



if __name__=="__main__":
    main()

示例输出:
在这里插入图片描述
注:本文中的代码是笔者参考外国一位博主写的伪代码,进而翻译为python代码写成的,但是时间太过久远,我实在找不到原博客了…本文不以盈利为目的,侵权请联系删除

PS:The code in this article was written by me with reference to the pseudo-code written by a foreign blogger, and then I translated it into python code, but it has been so long so I’m not be able to find the original blog… For infringement, please contact me on CSDN to delete

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值