算符优先分析法实现给定表达式的分析识别(Python)

给定类C语言中简单算术表达式文法G[E]:
    E→E+T | E-T | T
    T→T*F | T/F | F
    F→(E) | id
根据该文法,编写算符优先分析器。

1)输入:任意字符串。(文法中id即对应词法分析中识别出的标识符,+-*/分别对应词法分析得到的运算符);

2)输出:判定输入串是否为该文法定义的合法算术表达式;

实验步骤

1)对上述文法补充新的开始符号E’和新的产生式(E’→ #E#),并判定给定的文法是否是OPG文法;

2)构造Firstvt和Lastvt集合算法,针对文法中所有的非终结符求解;

3)按照算符优先分析法的思路,构造所有终结符的优先关系表;

4)利用栈,对输入的测试用例进行分析识别,并给出相应的结果;

5)对程序进行分析研究,画出相应的流程图。

七. 实验结果(画出流程图、给出运行结果截图、错误发现的方法描述)

一、手动分析过程

1)对上述文法补充新的开始符号E’和新的产生式(E’→ #E#),并判定给定的文法是否是OPG文法;

补充完整后,该文法为:

S→#E#

E→E+T

E→E-T

E→T

T→T*F

T→T/F

T→F

F→(E)

F→i该文法没有E→FT的形式,没有空产生式,而且两俩终结符间至多含有一种优先关系,所以该文法为算符优先文法。

2)构造Firstvt和Lastvt集合算法,针对文法中所有的非终结符求解;

求出该文法每个终结符的FIRSTVT和LASTVT集:

FIRSTVT(E’)={#}
FIRSTVT(E)={+,-,*,/,(,i}

FIRSTVT(T)={*,/,(,i }

FIRSTVT(F)={(,i }

LASTVT(E’)={#}
LASTVT(E)={+,-,*,/,) ,i}

LASTVT(T)={*,/,) ,i }

LASTVT(F)={) ,i }

3)按照算符优先分析法的思路,构造所有终结符的优先关系表;

1.求<关系

#E有# < FIRSTVT(E)

+T有+ < FIRSTVT(T)

-T有- < FIRSTVT(T)

*F有* < FIRSTVT(F)

/F有/ < FIRSTVT(F)

(E有(< FIRSTVT(E)

2.求>关系

E#有# > LASTVT(E)

E+有+ > LASTVT(E)

E-有- > LASTVT(E)

T*有* > LASTVT(T)

T/有/ > LASTVT(T)

E)有) > LASTVT(E)

3.求=关系

E’→ #E#得到 # = #

F→(E)得到 ( = )

根据以上分析得到优先关系表如下:

表一 优先关系表

+

-

*

/

i

#

+

>

>

<

<

<

>

<

>

-

>

>

<

<

<

>

<

>

*

>

>

>

>

<

>

<

>

/

>

>

>

>

<

>

<

>

<

<

<

<

<

=

<

>

>

>

>

>

>

i

>

>

>

>

>

>

#

<

<

<

<

<

<

=

rule.txt输入如下:

S→#E#
E→E+T
E→E-T
E→T
T→T*F
T→T/F
T→F
F→(E)
F→i
stop

保存

在程序内输入对应的算式可以看到规约栈和结果

代码如下:

from collections import deque
first=[[] for i in range(10)]
last=[[] for i in range(10)]
dfirst = {}
dvt={}
stack = deque()
satck_int = deque()
mode=1
def findfirst(l,r):
    for i in range(time+1):
        if left[i] == r:
             for x in range(len(right[i])):
                 if right[i][x] in vt:
                     if right[i][x] not in first[dfirst[l]]:
                        first[dfirst[l]].append(right[i][x])
                        break
                 elif right[i][x] in vn and right[i][x] != left[i]and x==0:
                     findfirst(l, right[i][x])
                     continue
def findlast(l,r):
    for i in range(time+1):
        if left[i] == r:
             for x in range(len(right[i])):
                 if right[i][x] in vt:
                     if right[i][x] not in last[dfirst[l]]:
                        last[dfirst[l]].append(right[i][x])
                     break
                 if right[i][x] in vn and right[i][x] != left[i]and x==0:
                     findlast(l, right[i][x])
                     continue
def getfirstvt(mode):
    for i in range(time+1):
        if left[i] in vn:
            for x in range(len(right[i])):
                if mode==1:
                    if right[i][x] in vt :#非终结符
                        if right[i][x]  not in first[dfirst[left[i]]]:
                            first[dfirst[left[i]]].append(right[i][x])
                            break
                    elif right[i][x] in vn and right[i][x] != left[i] and x==0:#终结符
                        findfirst(left[i],right[i][x])
                        continue
                elif mode==2:
                    if right[i][x] in vt :#非终结符
                        if right[i][x]  not in last[dfirst[left[i]]]:
                            last[dfirst[left[i]]].append(right[i][x])
                        break
                    if right[i][x] in vn and right[i][x] != left[i] and x==0:#终结符
                        findlast(left[i],right[i][x])
                        continue
def getchar():
    input("scan your rules(change id to i and end with stop)")
    global vt, vn, left, right, time
    vt = set()
    vn = set()
    k = 1
    time = -1
    left = []
    right = [[0 for i in range(10)] for i in range(10)]
    f = open("D:\\桌面\\rule.txt",encoding='utf-8')
    while True:
        rule = f.readline().strip('\n')
        if rule == 'stop':
            break
        case = 0
        time += 1
        y = 0
        for index in range(len(rule)):
            if case == 0 and rule[index] != '→' and rule[index] != '’':
                left.append(rule[index])
            if case == 1:
                right[time][y] = rule[index]
                y += 1
            if rule[index] > "A" and rule[index] < "Z":
                vn.add(rule[index])
            elif not (rule[index] == "→" or rule[index] == "’"):
                vt.add(rule[index])

            if rule[index] == '→':
                case = 1
                index += 1
def creat_flvt():
    l_vn=list(vn)
    for i in range(len(l_vn)):
         dfirst[l_vn[i]] = i

    l_vt=list(vt)
    for i in range(len(l_vt)):
         dvt[l_vt[i]] = i
    global lenth_vt
    lenth_vt=len(l_vt)

    for x in range(len(right)):
        while 0 in right[x]:
            right[x].remove(0)
def printvnvt():#对需要查看的内容取消标注
    print('VT and VN:')
    print(vt)
    print(vn)
    print('left and right:')
    print(right)
    print(left)
    #print(time + 1)
    print('VN')
    print(dfirst.keys())
    print('firstvt and lastvt')
    print(first)
    print(last)
    print('VT')
    print(dvt.keys())
    print('TABLE')
    for i in range(len(table)):
        print(table[i])
def gettable():
    global  table
    table = [[0 for i in range(lenth_vt)] for i in range(lenth_vt)]
    for i in range(time+1):
        for x in range(len(right[i])-1):
             rig = right[i][x]
             riger = right[i][x+1]
             if rig in vt and riger in vn:
                  for s in first[dfirst[riger]]:
                      table[dvt[rig]][dvt[s]] = '<'
             if rig in vn and riger in vt:
                  for f in last[dfirst[rig]]:
                      table[dvt[f]][dvt[riger]] = '>'
             if rig in vt and riger in vt:
                 table[dvt[rig]][dvt[riger]] = '='
        for x in range(len(right[i])-2):
            if right[i][x] in vt and right[i][x+1] in vn and right[i][x+2] in vt:
                 if right[i][x]== right[i][x+2]:
                    table[dvt[right[i][x]]][dvt[right[i][x+2]]] = '='
                    table[dvt[right[i][x+2]]][dvt[right[i][x]]] = '='
                 else:
                    table[dvt[right[i][x]]][dvt[right[i][x + 2]]] = '='
def turndown():
    for i in range(time + 1):
        right[i].reverse()  # 反转右侧二维数组
def simplify():
    sentence=input("input your sentence:")
    sentence=list(sentence)
    sentence.append('#')
    stack.append('#')
    x=0
    y=0
    while(len(stack)):
        print()
        print(satck_int)
        print(stack)
        if(sentence[y]>'0'and sentence[y]<'9'):
            num=int(ord(sentence[y])-ord('0'))
            y+=1
            while(sentence[y]>'0'and sentence[y]<'9'):
                num=num*10+int(ord(sentence[y])-ord('0'))
                y+=1
            satck_int.append(num)
        if sentence[y] in {'+','-','*','/','#','(',')'}:
            t1=stack[len(stack)-1]
            t2=sentence[y]
            z1=dvt[t1]
            z2=dvt[t2]
            if table[z1][z2]=="0":
                print("Error!")
                return
            if table[z1][z2]=="<":
                stack.append(t2)
                x+=1
                y+=1
                continue
            elif table[z1][z2] == "=":
                stack.pop()
                x-=1
                y+=1
            else:#if table[z1][z2]==">"
                calculate(t1)
                continue
        else:
            print("Error!")
            return
    out=satck_int.pop()
    print(out)
def count(a,b,c):
    if c=='+':
        return a+b
    elif c=='-':
        return a-b
    elif c=='*':
        return a*b
    elif c=='/':
        return b/a
def calculate(t1):
    d1=satck_int[len(satck_int)-1]
    satck_int.pop()
    d2=satck_int[len(satck_int)-1]
    satck_int.pop()
    satck_int.append(count(d1,d2,t1))
    stack.pop()
def main():
    getchar()
    creat_flvt()
    getfirstvt(1)#mode1下的,正序寻找
    turndown()
    getfirstvt(2)#mode2下的,逆序寻找
    turndown()
    gettable()
    #printvnvt()
    simplify()
    return
main()
'''rule.txt的内容
S→#E#
E→E+T
E→E-T
E→T
T→T*F
T→T/F
T→F
F→(E)
F→i
stop
'''

期末作业太多了,实际上还有很大的优化空间,等寒假再补吧。

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值