语法分析之自上而下分析:根据文法构造预测分析表环节(用python编写)

根据文法构造预测分析表

  • 自上而下分析:预测分析法的步骤一

实验报告目录

  • 根据文法构造预测分析表
  • 预备介绍
  • 具体分析

预备介绍

语法分析部分的自上而下分析有两个方法,一个是递归分析法,另一个就是预测分析法。预测分析法最重要的一个环节就是构造预测分析表。接下来介绍一下如何用python来构造一个文法的预测分析表。

具体分析

构造过程会用到求文法符号的FIRST集、FOLLOW集,或者求符号串的FIRST集合的算法,可以参考之前发的一篇文章 点击此处跳转

首先介绍一下预测分析表的结构,简单来说他就是一张表,表的两个属性分别是非终结符和终结符(包括‘#’),形如:

a b c ( #
E
E’
F
F’
A

其中对应的内容是产生式的形式,若是没有产生式则可以写入标记来表示其匹配不到具体的产生式,进入报错处理程序。

根据文法构造预测分析表具体条件:
扫描全部产生式.
1.计算产生式的右部的FIRST集合,如果求出来的FIRST集合中包含终结符,那么就把这条产生式放入对应非终结符和终结符的格子中
2.如果ε在FIRST集合中,则计算该非终结符的FOLLOW集合,如果求出来的FOLLOW集合中包含终结符,那么就把这条产生式放入对应的非终结符和终结符的格子中

具体代码分析
接下来将对代码拆分分析,完整代码下载 点击此处跳转

在这里我定义形参lst,存储所有产生式,嵌套列表第一层为产生式,第二层为具体的每一条产生式,例如:

lst_demo = [["E","→","T","E","'"],["E","'","→","+","T","E","'","|","ε"],["T","→","F","T","'"],\
           ["T","'","→","*","F","T","'","|","ε"],["F","→","(","E",")","|","q"]]
# 根据文法构造预测分析表

import syntactic_parser_demo
import string

# 形参lst为文法的所有产生式,返回值为预测分析表table,其中最后两个元素分别为非终结符列表和终结符列表
def get_table(lst):

这里定义返回值为预测分析表table,其结构为一个嵌套列表,外层列表按照非终结符的顺序,内存列表按终结符的顺序。因此配合的,就要提前构造非终结符列表和终结符列表,来作为顺序。

	s = [] # 非终结符列表
    l = [] # 终结符列表
    punc = string.punctuation
    # 获取非终结符和终结符列表
    for i in lst:
        s.append("".join(i[:i.index('→')]))
        for j in i:
            if j.islower() or (j in punc) and (j not in l) and (j != "'") and (j != '|'):
                if j == 'ε':
                    l.append('#')
                else:
                    l.append(j)
    l = list(set(l))
    max_length = max(len(s),len(l))
    # 定义预测分析表,以嵌套列表的形式存储,[[1,2,3],[],[]]外层列表按非终结符的顺序,内层列表按终结符的顺序
    table = [['!' for i in range(max_length)] for i in range(max_length)]

有话说: 这里定义了一个空的嵌套列表,并且全部赋值为 ‘!’

获取接下来要用到的FOLLOW集合

follow = syntactic_parser_demo.get_follow(lst)

接下来判定的逻辑代码挺简单:

for p in lst:
        temp_s = "".join(p[:p.index('→')])
        one = s.index(temp_s) # 获取外层列表索引值
        temp_split = [] # 将每一个产生式分割以便求的长度来进行分类讨论
        # 获取这一条产生式的所有'|'的索引值
        temp_or = []
        temp_push = []
        for k in range(len(p)):
            if p[k] == '|':
                temp_or.append(k)
        # 获取这一条产生式'→'的索引值
        temp_get = p.index('→')
        # 转换成列表方便组合
        temp_push.append(temp_get)
        # 合并查找索引列表
        temp_search =  temp_push + temp_or
        # 把一个产生式以'→'和'|'为分隔符分割,将分割后的数据存储在嵌套列表temp_split里
        for m in range(len(temp_search)):
            if len(temp_search) == 1:
                temp_split = [p[temp_search[m] + 1:]]
            else:
                if m == (len(temp_search) - 1):
                    temp_split.append(p[temp_search[m] + 1:])
                else:
                    temp_split.append(p[temp_search[m] + 1:temp_search[m + 1]])
        for n in temp_split:
            temp_first = syntactic_parser_demo.get_first_bunch("".join(n),lst)
            for q in temp_first:
                if q != 'ε':
                    two = l.index(q) # 获取内层列表索引值
                    table[one][two] = temp_s.split() + ['→'] + n
            if 'ε' in temp_first:
                temp_follow = follow[temp_s]
                for z in temp_follow:
                    two = l.index(z)
                    table[one][two] = temp_s.split() + ['→'] + n
    table.append(s)
    table.append(l)
    return table

可供测试的代码:

if __name__ == '__main__':
    lst_demo = [["E","→","T","E","'"],["E","'","→","+","T","E","'","|","ε"],["T","→","F","T","'"],\
           ["T","'","→","*","F","T","'","|","ε"],["F","→","(","E",")","|","q"]]
    get_table(lst_demo)

你可能感兴趣的:(编译原理)