First, Break All Rules

本文介绍了一种突破常规的方法,强调了在特定情境下打破规则的重要性。
First, Break All Rules.

fj.pngFirst_break_all_the_rules.rar

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/27028038/viewspace-731695/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/27028038/viewspace-731695/

根据如下要求修改代码:二、实验要求 将实验 1-实验 3 的实验内容进行整合设计,实现对指定 C--语言源程序文本文件的读取,并能够对 该源程序中的中间分析结果,即 3 个实验的结果进行逐步展示。 程序实现要求为: 1、输入为 C--程序和对应的文法。 2、系统能够输出经过预处理后的源程序(去掉注释、换行、空格等) 3、能够将该源程序中所有的单词根据其所属类型(整数、保留字、运算符、标识符等。定义的 C-- 语言中的标识符只能以字母或下划线开头)进行归类显示。 4、能够输出文法的非终结符的 FIRST 集和 FOLLOW 集,并以表的形式进行展示。 5、能够输出文法的 LL(1)分析表。 6、分析输入符号串(C—程序)是否为文法的句子,打印分析过程表。 7、设计 GUI 界面或其他可展示方式,完成上述 6 个要求。代码如下:import re from collections import defaultdict, deque import tkinter as tk from tkinter import filedialog, messagebox, ttk class LoginWindow: def __init__(self, root): self.root = root self.root.title("编译原理实验 - 登录") self.root.geometry("400x300") # 创建登录框架 login_frame = tk.Frame(root, padx=20, pady=20) login_frame.pack(expand=True) # 标题 title_label = tk.Label(login_frame, text="编译原理实验系统", font=("Arial", 16)) title_label.grid(row=0, column=0, columnspan=2, pady=10) # 学号输入 tk.Label(login_frame, text="学号:").grid(row=1, column=0, sticky="w", pady=5) self.student_id = tk.Entry(login_frame, width=30) self.student_id.grid(row=1, column=1, pady=5) # 姓名输入 tk.Label(login_frame, text="姓名:").grid(row=2, column=0, sticky="w", pady=5) self.name = tk.Entry(login_frame, width=30) self.name.grid(row=2, column=1, pady=5) # 班级输入 tk.Label(login_frame, text="班级:").grid(row=3, column=0, sticky="w", pady=5) self.class_name = tk.Entry(login_frame, width=30) self.class_name.grid(row=3, column=1, pady=5) # 登录按钮 login_button = tk.Button(login_frame, text="登录", command=self.login, width=10) login_button.grid(row=4, column=0, columnspan=2, pady=20) # 登录状态 self.status_label = tk.Label(login_frame, text="", fg="red") self.status_label.grid(row=5, column=0, columnspan=2) def login(self): # 获取输入 student_id = self.student_id.get().strip() name = self.name.get().strip() class_name = self.class_name.get().strip() # 验证输入 if not student_id or not name or not class_name: self.status_label.config(text="请填写所有信息") return # 关闭登录窗口并启动主程序 self.root.withdraw() main_window = tk.Toplevel(self.root) main_window.protocol("WM_DELETE_WINDOW", lambda: self.on_main_close(main_window)) app = CompilerGUI(main_window, student_id, name, class_name) def on_main_close(self, main_window): main_window.destroy() self.root.destroy() # 词法分析器实现 token_specs = [ ('NUMBER', r'\d+'), ('ID', r'[a-zA-Z_][a-zA-Z0-9_]*'), ('OP', r'[+\-*/]'), ('PAREN', r'[()]'), ('SKIP', r'[ \t\n]+') ] token_re = '|'.join('(?P<%s>%s)' % pair for pair in token_specs) def lex(code): tokens = [] for match in re.finditer(token_re, code): kind = match.lastgroup value = match.group() if kind == 'SKIP': continue tokens.append((kind, value)) return tokens # 文法处理模块 def eliminate_left_recursion(grammar): new_rules = {} for A in list(grammar.keys()): alpha = [rule for rule in grammar[A] if rule and rule[0] == A] if not alpha: continue A_prime = A + "'" new_rules[A] = [rule for rule in grammar[A] if not rule or rule[0] != A] new_rules[A_prime] = [rule[1:] + [A_prime] for rule in alpha] + [['ε']] return {**grammar, **new_rules} # 集合计算模块 def compute_first(grammar): first = defaultdict(set) changed = True while changed: changed = False for nt in grammar: for production in grammar[nt]: for symbol in production: if symbol in grammar: # 非终结符 before = len(first[nt]) first[nt] |= first[symbol] - {'ε'} if 'ε' not in first[symbol]: break if all(s in grammar and 'ε' in first[s] for s in production): first[nt].add('ε') if len(first[nt]) > before: changed = True else: # 终结符 if symbol != 'ε' and symbol not in first[nt]: first[nt].add(symbol) changed = True break return first def compute_follow(grammar, first): follow = defaultdict(set) start_symbol = next(iter(grammar)) follow[start_symbol].add('$') changed = True while changed: changed = False for nt in grammar: for production in grammar[nt]: for i, symbol in enumerate(production): if symbol not in grammar: continue # 终结符不需要 Follow 集 for beta in production[i+1:]: first_beta = compute_production_first([beta], first) follow[symbol] |= first_beta - {'ε'} if 'ε' not in first_beta: break else: if 'ε' in compute_production_first(production[i+1:], first): follow[symbol] |= follow[nt] continue if not production[i+1:] and 'ε' in compute_production_first(production[i+1:], first): follow[symbol] |= follow[nt] before = sum(len(follow[nt]) for nt in follow) changed = False return follow # 辅助函数:计算产生式的 First 集 def compute_production_first(production, first): result = set() for symbol in production: result |= first[symbol] - {'ε'} if 'ε' not in first[symbol]: break else: result.add('ε') return result # LL(1)分析表生成 def build_ll1_table(grammar, first, follow): table = defaultdict(dict) for nt in grammar: for production in grammar[nt]: first_set = compute_production_first(production, first) for term in first_set - {'ε'}: if term in table[nt]: messagebox.showerror("错误", f"LL(1)冲突:{nt} 在终结符 {term} 上有多个产生式") table[nt][term] = production if 'ε' in first_set: for term in follow[nt]: if term in table[nt]: messagebox.showerror("错误", f"LL(1)冲突:{nt} 在终结符 {term} 上有多个产生式") table[nt][term] = production return table # GUI界面设计 class CompilerGUI: def __init__(self, window, student_id, name, class_name): self.window = window self.window.title("编译原理实验") self.grammar = {} self.first = defaultdict(set) self.follow = defaultdict(set) self.ll1_table = defaultdict(dict) # 显示用户信息 self.create_user_info_panel(student_id, name, class_name) self.create_editor_panel() self.create_analysis_panel() self.create_result_view() self.window.protocol("WM_DELETE_WINDOW", self.on_close) def create_user_info_panel(self, student_id, name, class_name): frame = tk.Frame(self.window) frame.pack(fill=tk.X, padx=10, pady=5) info_text = f"学号: {student_id} | 姓名: {name} | 班级: {class_name}" info_label = tk.Label(frame, text=info_text, font=("Arial", 10)) info_label.pack(anchor="w") logout_button = tk.Button(frame, text="退出登录", command=self.logout) logout_button.pack(side="right") def logout(self): self.window.destroy() root = tk.Tk() login = LoginWindow(root) root.mainloop() def on_close(self): self.window.destroy() def create_editor_panel(self): frame = tk.Frame(self.window) frame.pack(fill=tk.BOTH, expand=True) self.editor_label = tk.Label(frame, text="输入源代码") self.editor_label.pack() self.editor = tk.Text(frame, height=15, width=80) self.editor.pack(fill=tk.BOTH, expand=True) self.grammar_label = tk.Label(frame, text="输入文法") self.grammar_label.pack() self.grammar_input = tk.Text(frame, height=10, width=80) self.grammar_input.pack(fill=tk.BOTH, expand=True) self.analyze_btn = tk.Button(frame, text="开始分析", command=self.start_analysis) self.analyze_btn.pack(pady=10) def create_analysis_panel(self): frame = tk.Frame(self.window) frame.pack(fill=tk.BOTH, expand=True) self.tokens_label = tk.Label(frame, text="Token流") self.tokens_label.pack() self.tokens_text = tk.Text(frame, height=10, width=80) self.tokens_text.pack(fill=tk.BOTH, expand=True) def create_result_view(self): frame = tk.Frame(self.window) frame.pack(fill=tk.BOTH, expand=True) # FIRST集和 FOLLOW集表格 self.first_label = tk.Label(frame, text="FIRST集") self.first_label.grid(row=0, column=0) self.first_text = tk.Text(frame, height=10, width=40) self.first_text.grid(row=1, column=0) self.follow_label = tk.Label(frame, text="FOLLOW集") self.follow_label.grid(row=0, column=1) self.follow_text = tk.Text(frame, height=10, width=40) self.follow_text.grid(row=1, column=1) self.ll1_label = tk.Label(frame, text="LL(1)分析表") self.ll1_label.grid(row=0, column=2) self.ll1_text = tk.Text(frame, height=10, width=40) self.ll1_text.grid(row=1, column=2) # 分析过程表 self.analysis_label = tk.Label(frame, text="分析过程") self.analysis_label.grid(row=2, column=0, columnspan=3) self.analysis_table = ttk.Treeview(frame, columns=("步骤", "栈内容", "输入符号", "动作"), show="headings") self.analysis_table.heading("步骤", text="步骤") self.analysis_table.heading("栈内容", text="栈内容") self.analysis_table.heading("输入符号", text="输入符号") self.analysis_table.heading("动作", text="动作") self.analysis_table.grid(row=3, column=0, columnspan=3, sticky="nsew") # 配置列权重,使组件可以扩展 for i in range(3): frame.columnconfigure(i, weight=1) frame.rowconfigure(3, weight=1) def start_analysis(self): code = self.editor.get("1.0", tk.END) grammar_text = self.grammar_input.get("1.0", tk.END) # 解析文法 self.parse_grammar(grammar_text) # 词法分析 tokens = lex(code) self.display_tokens(tokens) # 消除左递归 self.grammar = eliminate_left_recursion(self.grammar) # 计算 FIRST 和 FOLLOW 集 self.first = compute_first(self.grammar) self.follow = compute_follow(self.grammar, self.first) self.display_first_follow() # 生成 LL(1) 分析表 self.ll1_table = build_ll1_table(self.grammar, self.first, self.follow) self.display_ll1_table() # 分析输⼊符号串 self.analyze_input(tokens) def parse_grammar(self, grammar_text): self.grammar = {} for line in grammar_text.splitlines(): if '->' in line: lhs, rhs = line.split('->') lhs = lhs.strip() rhs = [r.strip().split() for r in rhs.split('|')] self.grammar[lhs] = rhs def display_tokens(self, tokens): self.tokens_text.delete("1.0", tk.END) for token in tokens: self.tokens_text.insert(tk.END, f"{token[0]}\t{token[1]}\n") def display_first_follow(self): self.first_text.delete("1.0", tk.END) self.follow_text.delete("1.0", tk.END) for nt in self.first: self.first_text.insert(tk.END, f"{nt}: {', '.join(self.first[nt])}\n") for nt in self.follow: self.follow_text.insert(tk.END, f"{nt}: {', '.join(self.follow[nt])}\n") def display_ll1_table(self): self.ll1_text.delete("1.0", tk.END) for nt in self.ll1_table: for term in self.ll1_table[nt]: self.ll1_text.insert(tk.END, f"{nt} -> {term}: {self.ll1_table[nt][term]}\n") def analyze_input(self, tokens): stack = ['$', list(self.grammar.keys())[0]] input_tokens = deque(tokens + [('$', '$')]) self.analysis_table.delete(*self.analysis_table.get_children()) step = 1 while stack: current_nt = stack[-1] current_token = input_tokens[0][0] if current_nt == current_token: stack.pop() input_tokens.popleft() self.analysis_table.insert("", tk.END, values=(step, stack.copy(), input_tokens.copy(), f"匹配 {current_token}")) step += 1 if not stack: self.analysis_table.insert("", tk.END, values=(step, stack.copy(), input_tokens.copy(), "分析成功!")) break else: if current_nt in self.ll1_table and current_token in self.ll1_table[current_nt]: production = self.ll1_table[current_nt][current_token] stack.pop() for symbol in reversed(production): if symbol != 'ε': stack.append(symbol) self.analysis_table.insert("", tk.END, values=(step, stack.copy(), input_tokens.copy(), f"{current_nt} → {' '.join(production)}")) step += 1 else: self.analysis_table.insert("", tk.END, values=(step, stack.copy(), input_tokens.copy(), "分析失败!")) break if __name__ == "__main__": root = tk.Tk() login = LoginWindow(root) root.mainloop()
05-30
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值