diff --git a/main.py b/main.py index 39bc682..b6c57a7 100644 --- a/main.py +++ b/main.py @@ -3,7 +3,7 @@ """ from lexical.lexical import Lexical from syntax.syntax import Syntax -from syntax.syntax import PredictingAnalysisTable +from syntax.syntax import LL1Generator # print(PredictingAnalysisTable().compile()) diff --git a/syntax/rule.py b/syntax/rule.py index 87220af..8a16efe 100644 --- a/syntax/rule.py +++ b/syntax/rule.py @@ -48,6 +48,7 @@ class Production: """ 产生式 """ + cnt = 0 def __init__(self, left_type, right_types, semantic_start, semantic_children, semantic_end): """ 产生式左边 @@ -57,22 +58,28 @@ class Production: :param semantic_children: 语义操作关键字 - 孩子 :param semantic_end: 语义操作关键字 - 结束 """ + self.cnt = Production.cnt + Production.cnt += 1 self.left = Sign(left_type) self.right = list() for i in right_types: self.right.append(Sign(i)) # 调试用的 - self.str = self.left.type + ' ->' + self.str1 = self.left.type + ' ->' for i in self.right: - self.str += ' ' + i.type - + self.str1 += ' ' + i.type + if len(self.right)==0: + self.str1 += ' empty' + self.str = [self.str1,self.cnt] # 语义操作关键字 self.semantic_start = semantic_start self.semantic_children = list() for c in semantic_children: self.semantic_children.append(c) self.semantic_end = semantic_end + def __str__(self): + return self.str[0] """ diff --git a/syntax/syntax.py b/syntax/syntax.py index 0d39a92..6b9eb9a 100644 --- a/syntax/syntax.py +++ b/syntax/syntax.py @@ -1,515 +1,240 @@ """ 语法分析 """ +import csv from syntax.rule import Sign, Production, terminal_sign_type, non_terminal_sign_type, productions, grammar_start from error import SyntaxRuleError, SyntaxError, SemanticRuleError from semantic.rule import SemanticRule, SemanticError, SemanticRuleFactory - -class PredictingAnalysisTable: - """ - 预测分析表 - """ +class LL1Generator: def __init__(self): - """ - 构造 - """ - # 错误 - self.__error = None - - # 预测分析表 - self.__table = list() - - # 所有的非终结符 - self.__non_terminal_signs = list() - # 所有的终结符 - self.__terminal_signs = list() - - # 载入所有的符号 - for i in non_terminal_sign_type: - self.__non_terminal_signs.append(Sign(i)) - for i in terminal_sign_type: - self.__terminal_signs.append(Sign(i)) - - # 根据非终结符和终结符的数量为预测分析表分配空间,并且为每一个格子预先填上 None - for i in non_terminal_sign_type: - self.__table.append(list()) - for i in range(0, len(non_terminal_sign_type)): - for j in terminal_sign_type: - self.__table[i].append(None) - - # 为每一个非终结符建立 first 集和 follow 集 - self.__firsts = list() - self.__follows = list() - - # 为每一个非终结符的 first 集和 follow 集分配空间 - for i in non_terminal_sign_type: - self.__firsts.append(list()) - self.__follows.append(list()) - + 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): - """ - 编译预测分析表 - """ - # 对每一个文法元素求其 first 集 - self.__calculate_firsts() - # 对每一个文法元素求其 follow 集 - self.__calculate_follows() - # 根据 first 集和 follow 集生成预测分析表 - success = self.__generate_table() + 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 get_production(self, non_terminal_sign, terminal_sign): - """ - 从预测分析表中获取产生式 - :param non_terminal_sign: 非终结符 - :param terminal_sign: 终结符 - :return: 产生式 - """ - x = self.__get_non_terminal_sign_index(non_terminal_sign) - y = self.__get_terminal_sign_index(terminal_sign) - return self.__table[x][y] + def is_TS(self,item): + return self.TSmp.get(item) is not None - @classmethod - def __set_add(cls, container, sign): - """ - 将 sign 添加到 container 中并返回 True,如果其中已经有该元素了则返回 False - :param container: 要添加到的集合 - :param sign: 符号 - :return: 添加是否成功 - """ - exist = False - for elem in container: - if elem.type == sign.type: - exist = True - if not exist: - container.append(sign) - return not exist + def is_NTS(self,item): + return self.NTSmp.get(item) is not None - def __get_terminal_sign_index(self, terminal_sign): - """ - 获取终结符的索引 - :param terminal_sign: 终结符 - :return: 索引(寻找失败返回 -1) - """ - for i in range(0, len(self.__terminal_signs)): - if terminal_sign.type == self.__terminal_signs[i].type: - return i - return -1 + def first_set(self,tp): + return self.firsts[self.NTSmp.get(tp)] - def __get_non_terminal_sign_index(self, non_terminal_sign): - """ - 获取非终结符的索引 - :param non_terminal_sign: 非终结符 - :return: 索引(寻找失败返回 -1) - """ - for i in range(0, len(self.__non_terminal_signs)): - if non_terminal_sign.type == self.__non_terminal_signs[i].type: - return i - return -1 + 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 __get_non_terminal_sign_first(self, non_terminal_sign): - """ - 获取目标非终结符的 first 集的引用 - :param non_terminal_sign: 目标非终结符 - :return: 其 first 集的引用 - """ - return self.__firsts[self.__get_non_terminal_sign_index(non_terminal_sign)] + def follow_set(self,tp): + return self.follows[self.NTSmp.get(tp)] - def __get_non_terminal_sign_first_no_empty(self, non_terminal_sign): - """ - 获取目标非终结符的 first 集的非空拷贝 - :param non_terminal_sign: 目标非终结符 - :return: 其 first 集的非空拷贝 - """ - result = list() - for i in self.__get_non_terminal_sign_first(non_terminal_sign): - if not i.is_empty_sign(): - result.append(i) - return result + 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 __is_empty_in_non_terminal_sign_first(self, non_terminal_sign): - """ - 目标非终结符的 first 集中是否有空字 - :param non_terminal_sign: 目标非终结符 - :return: True/False - """ - for i in self.__get_non_terminal_sign_first(non_terminal_sign): - if i.is_empty_sign(): - return True - return False + def l_r_scan(self,lst): + l = set() + if len(lst) == 0: + l.add('empty') - def __get_non_terminal_sign_follow(self, non_terminal_sign): - """ - 获取非终结符的 follow 集 - :param non_terminal_sign: 非终结符 - :return: 其 follow 集 - """ - return self.__follows[self.__get_non_terminal_sign_index(non_terminal_sign)] + 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): - """ - 求所有的 first 集 - """ - # 立一个 flag,用来标志 firsts 集是否增大 - flag = True - # 开始循环 - while flag: - flag = False - # 在每一次循环之中遍历所有产生式 - for production in productions: - # 如果产生式右边为空 - if len(production.right) == 0: - # 将空字加入其 first 集 - if self.__set_add(self.__get_non_terminal_sign_first(production.left), Sign('empty')): - flag = True - # 如果产生式右边不为空 + 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 集 - if production.right[0].is_terminal_sign(): - if self.__set_add(self.__get_non_terminal_sign_first(production.left), production.right[0]): - flag = True - # 如果是以非终结符开头 - elif production.right[0].is_non_terminal_sign(): - # (1) 将开头非终结符的 first 集中的所有非空元素添加到产生式左边非终结符的 first 集中 - bigger = False - for i in self.__get_non_terminal_sign_first_no_empty(production.right[0]): - if self.__set_add(self.__get_non_terminal_sign_first(production.left), i): - bigger = True - if bigger: - flag = True + # 此时就是非终结符了 + # 将所有该非终结符的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") - # (2) 从第一个非终结符开始循环,如果其 first 集中包含空字,那么将它下一个符号的 first - # 集添加到产生式左边非终结符的 first 集中去 - for i in range(0, len(production.right)): - if production.right[i].is_non_terminal_sign(): - # 如果包含空字 - if self.__is_empty_in_non_terminal_sign_first(production.right[i]): - # 如果它是最后一个,将空字填入 - if i == len(production.right) - 1: - if self.__set_add(self.__get_non_terminal_sign_first(production.left), - Sign('empty')): - flag = True - # 如果不是最后一个 - else: - # 如果它之后是终结符 - if production.right[i + 1].is_terminal_sign(): - if self.__set_add(self.__get_non_terminal_sign_first(production.left), - production.right[i + 1]): - flag = True - # 如果它之后是非终结符 - elif production.right[i + 1].is_non_terminal_sign(): - bigger = False - for j in self.__get_non_terminal_sign_first_no_empty( - production.right[i + 1]): - if self.__set_add( - self.__get_non_terminal_sign_first(production.left), j): - bigger = True - if bigger: - flag = True - else: - self.__error = SyntaxRuleError('终结符或非终结符类型错误') - return False - # 如果不包含空字 + f = True else: - break + # 下一个是终结符 + 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: - self.__error = SyntaxRuleError('终结符或非终结符类型错误') - return False - - def __calculate_follows(self): - """ - 求所有的 follow 集 - """ - first = list() - flag = True - while flag: - flag = False - # 遍历所有产生式 - for production in productions: - # 如果产生式左边是开始符号 - if production.left.type == grammar_start.type: - if self.__set_add(self.__get_non_terminal_sign_follow(production.left), Sign('pound')): - flag = True - - # 遍历产生式右边 - for i in range(0, len(production.right)): - # 如果是非终结符 - if production.right[i].is_non_terminal_sign(): - # 如果它是产生式最后一个符号 - if i == len(production.right) - 1: - # 将产生式左边非终结符的 follow 集添加到这个符号的 follow 集中 - bigger = False - for j in self.__get_non_terminal_sign_follow(production.left): - if self.__set_add(self.__get_non_terminal_sign_follow(production.right[i]), j): - bigger = True - if bigger: - flag = True - # 否则观察其之后的元素 - else: - # 求他之后所有符号集合的 first 集 - first.clear() - first += self.__calculate_set_first(production.right[i + 1:]) - # (1) 将 first 中所有非空元素填入 follow - empty_find = False - for f in first: - if not f.is_empty_sign(): - self.__set_add(self.__get_non_terminal_sign_follow(production.right[i]), f) - else: - empty_find = True - - # (2) 如果 first 中含有空 - if empty_find: - # 将产生式左边非终结符的 follow 集添加到这个符号的 follow 集中 - bigger = False - for j in self.__get_non_terminal_sign_follow(production.left): - if self.__set_add(self.__get_non_terminal_sign_follow(production.right[i]), j): - bigger = True - if bigger: - flag = True - - # # 如果他后面是一个终结符 - # if production.right[i + 1].is_terminal_sign(): - # if self.__set_add(self.__get_non_terminal_sign_follow(production.right[i]), - # production.right[i + 1]): - # flag = True - # # 如果他后面是一个非终结符 - # elif production.right[i + 1].is_non_terminal_sign(): - # # (1) 将后面非终结符的 first 集中的所有非空元素填入 - # bigger = False - # for j in self.__get_non_terminal_sign_first_no_empty(production.right[i + 1]): - # if self.__set_add(self.__get_non_terminal_sign_follow(production.right[i]), j): - # bigger = True - # if bigger: - # flag = True - # - # # (2) 如果后面所有的非终结符 first 集都包含空 - # # 那么,则将产生式左边的 follow 集添加到该非终结符的 follow 集中去 - # all_empty_in_first = True - # for j in range(i + 1, len(production.right)): - # if not self.__is_empty_in_non_terminal_sign_first(production.right[j]): - # all_empty_in_first = False - # break - # if all_empty_in_first: - # bigger = False - # for j in self.__get_non_terminal_sign_follow(production.left): - # if self.__set_add(self.__get_non_terminal_sign_follow(production.right[i]), j): - # bigger = True - # if bigger: - # flag = True - # # 否则报错 - # else: - # self.__error = SyntaxRuleError('终结符或非终结符类型错误') - # return False - # 如果是终结符 - elif production.right[i].is_terminal_sign(): - continue - # 否则报错 - else: - self.__error = SyntaxRuleError('终结符或非终结符类型错误') - return False - - def __calculate_set_first(self, container): - """ - 计算一系列符号的 first 集 - :param container: 符号集合 - :return: first 集 - """ - first = list() - - # 开始求 first 集 - # 如果集合为空 - first = list() - - # 开始求 first 集 - # 如果产生式右边为空 - if len(container) == 0: - # 将空字加入其 first 集 - self.__set_add(first, Sign('empty')) - # 如果产生式右边补位空 - else: - # 如果是以终结符开头,将终结符添加到 first 集 - if container[0].is_terminal_sign(): - self.__set_add(first, container[0]) - # 如果是以非终结符开头 - elif container[0].is_non_terminal_sign(): - # (1) 将开头非终结符的 first 集中的所有非空元素添加到 first 中 - for i in self.__get_non_terminal_sign_first_no_empty(container[0]): - self.__set_add(first, i) - - # (2) 从第一个非终结符开始循环,如果其 first 集中包含空字,那么将它的下一个符号的 first - # 集添加到 first 中 - for i in range(0, len(container)): - if container[i].is_non_terminal_sign(): - # 如果包含空字 - if self.__is_empty_in_non_terminal_sign_first(container[i]): - # 如果它是最后一个,将空字填入 - if i == len(container) - 1: - self.__set_add(first, Sign('empty')) - # 如果不是最后一个 - else: - # 如果它之后是终结符 - if container[i + 1].is_terminal_sign(): - self.__set_add(first, container[i + 1]) - # 如果它之后是非终结符 - elif container[i + 1].is_non_terminal_sign(): - for j in self.__get_non_terminal_sign_first_no_empty(container[i + 1]): - self.__set_add(first, j) - # 否则报错 - else: - self.__error = SyntaxRuleError('终结符或非终结符类型错误') - return False - # 如果不含空字 else: break - else: - break - # 否则报错 - else: - self.__error = SyntaxRuleError('终结符或非终结符类型错误') - return False - return first - - def __insert_to_table(self, production, terminal): - """ - 将产生式插入预测分析表对应位置 - :param production: 产生式 - :param terminal: 终结符 - :return: 是否插入成功 - """ - # 先判断应该插入到的位置 - x = self.__get_non_terminal_sign_index(production.left) - y = self.__get_terminal_sign_index(terminal) - - # 如果那个位置已经有产生式了 - if self.__table[x][y]: - # 判断这个产生式是不是与要插入的产生式一样 - same_left = production.left.type == self.__table[x][y].left.type - if same_left: - same_right = True - if len(production.right) != len(self.__table[x][y].right): - self.__error = SyntaxRuleError("文法非LL(1)" + production.str) - return False - else: - for i in range(0, len(production.right)): - if production.right[i].type != self.__table[x][y].right[i].type: - same_right = False - if same_right: - # 执行插入 - del self.__table[x][y] - self.__table[x].insert(y, production) - return True - else: - self.__error = SyntaxRuleError("文法非LL(1)" + production.str) - return False - else: - self.__error = SyntaxRuleError("文法非LL(1)" + production.str) - return False - # 如果那个位置为空,说明可以填入 + 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: - # 执行插入 - del self.__table[x][y] - self.__table[x].insert(y, production) - return True + return - @classmethod - def __set_have_repeat(cls, set1, set2): - """ - 判断两个集合是否有交集 - :param set1: 集合1 - :param set2: 集合2 - :return: 是否有交集 - """ - for i in set1: - for j in set2: - if i.type == j.type: - return True - return False + 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 __grammar_rule_debug(self): - """ - 调试使用,求一个非终结符对应的所有产生式右边的 first 集中是否有相交元素 - """ - # 一个非终结符对应的所有产生式 - his_productions = list() - # 那些产生式对应的 first 集 - firsts = list() - # 错误 - errors = list() + def gen_tb(self): + for _ in productions: + l = _.left.type + r = [_.type for _ in _.right] - # 对于所有的非终结符 - for non_terminal_sign in self.__non_terminal_signs: - # 寻找他对应的所有产生式 - his_productions.clear() - firsts.clear() - for production in productions: - if non_terminal_sign.type == production.left.type: - his_productions.append(production) - - # 对于那些产生式,分别求 first 集 - for production in his_productions: - firsts.append(self.__calculate_set_first(production.right)) - - - - # 是否有交集 - have_repeat = False - # 查看这些产生式的 first 集两两之间是否有交集 - for i in range(0, len(his_productions) - 1): - for j in range(i + 1, len(his_productions)): - - if self.__set_have_repeat(firsts[i], firsts[j]): - have_repeat = True - break - - - # 如果有交集 - if have_repeat: - errors.append('产生式 First 集重叠 ' + '非终结符: ' + non_terminal_sign.type) - - # 如果非终结符的 First 集中包含空字 - if self.__is_empty_in_non_terminal_sign_first(non_terminal_sign): - # 如果他的 First 集和 Follow 集有交集 - if self.__set_have_repeat(self.__get_non_terminal_sign_first(non_terminal_sign), - self.__get_non_terminal_sign_follow(non_terminal_sign)): - errors.append('产生式 First 集和 Follow 集重叠 ' + '非终结符: ' + non_terminal_sign.type) - return - - def __generate_table(self): - """ - 根据 first 集和 follow 集生成预测分析表 - :return: 是否生成成功 - """ - # 调试 - self.__grammar_rule_debug() - - # 对每一条产生式应用规则 - for production in productions: - # 先求出该产生式右边部分的 first 集 - first = self.__calculate_set_first(production.right) - - # 对每一个 first 集中的每一个终结符执行操作 empty_find = False - for i in list(first): - if i.type == 'empty': + for __ in self.l_r_scan(r): + if __ =='empty': empty_find = True else: - if not self.__insert_to_table(production, i): - return False - - # 如果其 first 集中有空字,则对 follow 集中的每一个终结符执行操作 + self.insert_tb(_,__) if empty_find: - for i in self.__get_non_terminal_sign_follow(production.left): - if not self.__insert_to_table(production, i): - return False + for __ in self.follow_set(l): + self.insert_tb(_,__) + def get_production(self,row,col): + return self.tb[self.NTSmp[row]][self.TSmp[col]] - return True + 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) class Node: """ @@ -619,7 +344,7 @@ class Syntax: # 准备存放错误 self.__error = list() # 预测分析表的构建 - self.__pa_table = PredictingAnalysisTable() + self.__pa_table = LL1Generator() # 编译预测分析表 if self.__pa_table.compile(): self.__error.append(SyntaxRuleError('预测分析表编译失败')) @@ -699,7 +424,8 @@ class Syntax: # 如果 top 是非终结符 if stack.top().data.is_non_terminal_sign(): # 查看分析表 - production = self.__pa_table.get_production(stack.top().data, inputs[input_index]) + print(stack.top().data.type,inputs[input_index].type) + production = self.__pa_table.get_production(stack.top().data.type, inputs[input_index].type) # 如果分析表对应位置存有产生式 if production: # 判断语义规则是否合法 diff --git a/syntax/wan.py b/syntax/wan.py new file mode 100644 index 0000000..7d60939 --- /dev/null +++ b/syntax/wan.py @@ -0,0 +1,237 @@ +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) diff --git a/test.py b/test.py index 9e0d1a7..e321c5d 100644 --- a/test.py +++ b/test.py @@ -1,5 +1,5 @@ -from syntax.syntax import PredictingAnalysisTable +from syntax.syntax import LL1Generator -pa_table = PredictingAnalysisTable() +pa_table = LL1Generator() pa_table.compile() diff --git a/test9.c b/test9.c index 1b36325..80860fc 100644 --- a/test9.c +++ b/test9.c @@ -1,7 +1,7 @@ -fn main(a:i32[], b:i32, c:f32[], d:i32) -> f32 { - i32 d; -} +fn main(a:i32,c:f32[])->f32{ + i32[2] b; -fn demo() { - i32 fs; } +fn gcd(a:i32,b:i32)->i32{ + +} \ No newline at end of file