import csv from rule import * class LL1Generator: def __init__(self): self.NTS = [_ for _ in non_terminal_sign_type] self.NTS_sz = len(self.NTS) self.NTSmp = {_:idx for idx,_ in enumerate(self.NTS)} self.TS = [_ for _ in terminal_sign_type] self.TS_sz = len(self.TS) self.TSmp = {_:idx for idx,_ in enumerate(self.TS)} self.tb = [[None for __ in range(self.TS_sz)] for _ in range(self.NTS_sz)] self.firsts = [set() for _ in range(self.NTS_sz)] self.follows = [set() for _ in range(self.NTS_sz)] self.first_debug = False self.first_debug_cnt = 0 self.follow_debug = False self.follow_debug_cnt = 0 def compile(self): self.calculate_firsts() self.calculate_follows() success = self.gen_tb() return success def print_firsts(self): for idx,_ in enumerate(self.firsts): print(f"{self.NTS[idx]}:") print(self.firsts[idx]) def print_follows(self): for idx,_ in enumerate(self.follows): print(f"{self.NTS[idx]}:") print(self.follows[idx]) def is_TS(self,item): return self.TSmp.get(item) is not None def is_NTS(self,item): return self.NTSmp.get(item) is not None def first_set(self,tp): return self.firsts[self.NTSmp.get(tp)] def first_insert(self,l,item): or_sz = len(self.first_set(l)) self.first_set(l).add(item) return or_sz < len(self.first_set(l)) def follow_set(self,tp): return self.follows[self.NTSmp.get(tp)] def follow_insert(self,l,item): or_sz = len(self.follow_set(l)) self.follow_set(l).add(item) return or_sz < len(self.follow_set(l)) def l_r_scan(self,lst): l = set() if len(lst) == 0: l.add('empty') for idx,_ in enumerate(lst): f = False if self.is_TS(_): l.add(_) else: for __ in self.first_set(_): if __ =='empty': f =True if __ != 'empty' or (__ =='empty' and idx==len(lst)-1): l.add(__) if not f: break return l def calculate_firsts(self): f = True while f: f = False for _ in productions: l = _.left.type r = [__.type for __ in _.right] if len(r)==0: if self.first_insert(l,'empty'): if self.first_debug: self.first_debug_cnt+=1 print(f"第{self.first_debug_cnt}次推导: {l}->{' '.join(r)} : 添加empty") f = True elif self.is_TS(r[0]): if self.first_insert(l,r[0]): if self.first_debug: self.first_debug_cnt+=1 print(f"第{self.first_debug_cnt}次推导: {l}->{' '.join(r)} : 添加{r[0]}") f = True else: # 此时就是非终结符了 # 将所有该非终结符的first集元素加入到左部的first集 for _ in self.first_set(r[0]): if self.first_insert(l,_): if self.first_debug: self.first_debug_cnt += 1 print(f"第{self.first_debug_cnt}次推导 : {l}->{' '.join(r)} : 添加{_}") f = True for i in range(0,len(r)): # 如果是非终结符 if self.is_NTS(r[i]): # 如果该非终结符的first里有空 if 'empty' in self.first_set(r[i]): # 如果是最后一个 if i == len(r)-1: if self.first_insert(l,'empty'): if self.first_debug: self.first_debug_cnt += 1 print(f"第{self.first_debug_cnt}次推导 : {l}->{' '.join(r)} : 添加empty") f = True else: # 下一个是终结符 if self.is_TS(r[i+1]): if self.first_insert(l,r[i+1]): if self.first_debug: self.first_debug_cnt += 1 print(f"第{self.first_debug_cnt}次推导 : {l}->{' '.join(r)} : 添加{r[i+1]}") f = True # 下一个为非终结符 elif self.is_NTS(r[i+1]): for _ in self.first_set(r[i+1]): if self.first_insert(l,_): if self.first_debug: self.first_debug_cnt += 1 print( f"第{self.first_debug_cnt}次推导 : {l}->{' '.join(r)} : 添加{_}") f = True else: print("error: TS/NTS type.") else: break else: break def calculate_follows(self): f = True while f: f = False for _ in productions: l = _.left.type r= [__.type for __ in _.right] if l == 'program': if self.follow_insert(l,'pound'): if self.follow_debug: self.follow_debug_cnt +=1 print(f"第{self.follow_debug_cnt}次推导:{l} -> {' '.join(r)} , {l} add pound") f = True for i in range(0,len(r)): if self.is_NTS(r[i]): if i == len(r)-1: for _ in self.follow_set(l): if self.follow_insert(r[i],_): if self.follow_debug: self.follow_debug_cnt += 1 print(f"第{self.follow_debug_cnt}次推导:{l} -> {' '.join(r)} , {r[i]} add {_}") f = True else: empty_find = False for __ in self.l_r_scan(r[i+1:]): if __=='empty': empty_find = True elif self.follow_insert(r[i],__): if self.follow_debug: self.follow_debug_cnt += 1 print(f"第{self.follow_debug_cnt}次推导:{l} -> {' '.join(r)} , {r[i]} add {__}") f = True if empty_find: for _ in self.follow_set(l): if self.follow_insert(r[i],_): if self.follow_debug: self.follow_debug_cnt += 1 print( f"第{self.follow_debug_cnt}次推导:{l} -> {' '.join(r)} , {r[i]} add {l}") f = True def select(self,l): f = False for _ in self.l_r_scan(l): if _ =='empty': f= True break if f: return else: return def insert_tb(self,_,r): if self.tb[self.NTSmp[_.left.type]][self.TSmp[r]] != None and self.tb[self.NTSmp[_.left.type]][self.TSmp[r]] != _: print(f"wa :{_.l.type}->{[__.type for __ in _.r]} : {r}") self.tb[self.NTSmp[_.left.type]][self.TSmp[r]] = _ def gen_tb(self): for _ in productions: l = _.left.type r = [_.type for _ in _.right] empty_find = False for __ in self.l_r_scan(r): if __ =='empty': empty_find = True else: self.insert_tb(_,__) if empty_find: for __ in self.follow_set(l): self.insert_tb(_,__) def get_production(self,row,col): return self.tb[self.NTSmp[row][col]] def show_me_what_you_got(self,file,show_by_id=False): l = ['NTS\\TS'] for _ in self.TS: l.append(_) ll = [l] for idx,_ in enumerate(self.tb): l = [self.NTS[idx]] for __ in _: if __ != None: l.append(__.str[int(show_by_id)]) else: l.append(' ') ll.append(l) with open(file,'w',newline='')as f: writer = csv.writer(f) writer.writerows(ll) obj = LL1Generator() obj.compile() obj.show_me_what_you_got("LL1Table_id.csv",show_by_id=True)