本文章实现内容:
1、设计一个表示文法的数据结构;
2、从文本文件中读入文法,利用定义的数据结构存放文法,并输出
编辑一个文本文文件g.txt,在文件中输入如下内容:
S->Qc;
S->c;
Q->Rb;
Q->b;
R->Sa;
R->a;
上述文法整理后的输出形式:
S->Qc|c;
Q->Rb|b;
R->Sa|a;
同样支持这样的输入:
S->Qc|c|cc|da|Q1
Q->Rb|b|V
R->Sa|a|cV2
Q1->aa|bd
V2->d|Q2
Q2->a
V->V2|e
结果:
S->Qc|c|cc|da|Q1;
Q->Rb|b|V;
R->Sa|a|cV2;
Q1->aa|bd;
V2->d|Q2;
Q2->a;
V->V2|e;
代码如下:
def GetGrammar(grammar): # 输出文法
global non_terminator, production
for i in grammar[non_terminator]: # 遍历非终结符
print(i + '->', end='') # 前部
for j in range(len(grammar[production][i])): # 根据非终结符遍历该终结符的产生式
if j > 0:
print('|', end='')
for k in grammar[production][i][j]:
print(k, end='')
print(';')
def LongStr(sting, list_data): # 从列表中寻找匹配最长的项
maxlen = 0 # 最长的匹配字符串长度
maxstr = -1 # 匹配的最长字符串位置
for i in range(len(list_data)): # 遍历
if sting.startswith(list_data[i]): # 判断字符串是否以list[i]开头
leni = len(list_data[i])
if leni > maxlen: # 如果新匹配字符串比原来长,替换
maxlen = leni
maxstr = i
return maxlen, maxstr
def PrimaryTreatment(grammar): # 初步处理,使得产生式内部分开
global non_terminator, production
for i in grammar[non_terminator]: # 遍历非终结符
for j in range(len(grammar[production][i])): # 根据非终结符遍历该终结符的产生式
k = 0 # 所处位置指针
str_production = grammar[production][i][j][0] # 产生式字符串
new_production = [] # 准备存初步处理后的产生式
while k < len(str_production):
maxlen, maxstr = LongStr(str_production, grammar[non_terminator]) # 寻找匹配最长的终结符
if maxlen == 0: # 没找到
new_production.append(str_production[k]) # 分出一个终结符
k += 1
else: # 找到了
new_production.append(str_production[k:k + maxlen]) # 分出一个非终结符
k += maxlen
grammar[production][i][j] = new_production # 产生式替换
pass
def OpenGrammar(file): # 从文件中打开(读取)文法。并作初级处理(产生式中各个非终结符和终结符分开)
global non_terminator, production
file = open(file) # 读取文件
non_terminator = '非终结符'
production = '产生式'
grammar = {non_terminator: [], production: {}}
while i := file.readline(): # 一行一行的读取,并赋值给i
for j in range(len(i)): # 遍历i中每一个字符
if i[j] == '-' and i[j + 1] == '>': # 分割前面的字符就是非终结符
if not i[0:j] in grammar[non_terminator]: # 该非终结符还没有记录
grammar[non_terminator].append(i[0:j]) # 加入进去
grammar[production][i[0:j]] = []
k = j + 2 # 直达产生式右部第一个字符
for l in range(len(i)+1): # +1是为了处理最后一行又不带分号又不带回车的情况
# 这里由于用了断路特性即l == len(i)成立后不会运行后面的,从而不会产生数组越界报错
if l == len(i) or i[l] == ';' or i[l] == '\n': # 往后找到最后一个,结束
grammar[production][i[0:j]].append([i[k:l]]) # 添加到后面
break
if i[l] == '|': # 遇到了中断
grammar[production][i[0:j]].append([i[k:l]]) # 添加到后面
k = l + 1 # 并且左边标记右移
break
file.close()
PrimaryTreatment(grammar)
return grammar
global non_terminator, production
file = 'g.txt' # 文件位置
grammar = OpenGrammar(file)
GetGrammar(grammar)