<think>我们之前编写的C语言解析器在解析您提供的代码示例时可能无法正常工作,原因可能是:
1. 函数声明和定义的模式匹配问题:您提供的函数是静态函数,模式中没有考虑"static"关键字。
2. 全局变量的识别:您提供的代码中没有全局变量,但函数内部有局部变量,这些不应该被识别为全局变量。
3. 函数解析:函数名是`Diag21_PID_C9`,不符合之前设定的`vd_`或`u1/u2/u4`等前缀,因此会被归类为“普通函数”,但该函数有返回值(void)和参数(U1 u1_a_num)。
我们需要改进代码:
- 在解析函数时,考虑可能的关键字(如static, inline等)。
- 改进全局变量的识别,确保只识别在函数外部的变量。
- 改进函数解析,正确识别返回类型和参数。
另外,您还要求:
2. 增加进度条功能:由于解析通常很快,但为了大型文件,我们可以添加进度条。但请注意,正则表达式操作很快,所以进度条可能只是模拟。
3. 增加日志功能:我们可以将解析过程中的关键步骤记录到日志文件中。
修改计划:
1. 修复函数解析的正则表达式,允许函数类型前的修饰符(如static)。
2. 确保全局变量只匹配不在函数内部的变量(通过排除在{}内部的声明)。
3. 添加进度条:使用tkinter的ttk.Progressbar,由于解析很快,我们可以将解析过程分为几个步骤(解析typedef,全局变量,函数)来更新进度条。
4. 添加日志功能:使用logging模块,将解析过程中的信息记录到文件,同时在界面上也可以显示日志。
由于原代码较长,我将在原代码基础上修改。以下是修改后的代码:
```python
import tkinter as tk
from tkinter import scrolledtext, ttk
import re
import logging
from tkinter import messagebox
import os
class CCodeParserApp:
def __init__(self, root):
self.root = root
self.root.title("C语言代码解析器")
self.root.geometry("800x700")
# 创建输入区域
input_frame = tk.LabelFrame(root, text="输入C语言代码", padx=5, pady=5)
input_frame.pack(fill="both", expand=True, padx=10, pady=5)
self.input_text = scrolledtext.ScrolledText(input_frame, width=80, height=15)
self.input_text.pack(fill="both", expand=True, padx=5, pady=5)
# 添加示例代码按钮
example_btn = tk.Button(root, text="插入示例代码", command=self.insert_example)
example_btn.pack(pady=5)
# 解析按钮
parse_btn_frame = tk.Frame(root)
parse_btn_frame.pack(fill="x", padx=10, pady=5)
parse_btn = tk.Button(parse_btn_frame, text="解析代码", command=self.parse_code, bg="#4CAF50", fg="white")
parse_btn.pack(side="left")
# 进度条
self.progress = ttk.Progressbar(parse_btn_frame, orient="horizontal", length=200, mode="determinate")
self.progress.pack(side="right", padx=10)
# 创建输出区域
output_frame = tk.LabelFrame(root, text="解析结果", padx=5, pady=5)
output_frame.pack(fill="both", expand=True, padx=10, pady=5)
self.output_text = scrolledtext.ScrolledText(output_frame, width=80, height=15)
self.output_text.pack(fill="both", expand=True, padx=5, pady=5)
self.output_text.config(state=tk.DISABLED)
# 日志区域
log_frame = tk.LabelFrame(root, text="日志", padx=5, pady=5)
log_frame.pack(fill="both", expand=True, padx=10, pady=5)
self.log_text = scrolledtext.ScrolledText(log_frame, width=80, height=5)
self.log_text.pack(fill="both", expand=True, padx=5, pady=5)
self.log_text.config(state=tk.DISABLED)
# 配置日志
self.setup_logging()
def setup_logging(self):
# 创建日志目录
if not os.path.exists("logs"):
os.makedirs("logs")
# 配置logging模块
logging.basicConfig(
filename="logs/parser.log",
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)
# 添加一个用于在界面上显示日志的handler
self.log_handler = TextHandler(self.log_text)
self.log_handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
self.log_handler.setFormatter(formatter)
logging.getLogger().addHandler(self.log_handler)
logging.info("应用程序启动")
def insert_example(self):
example_code = """static void Diag21_PID_C9(U1 u1_a_num)
{
U1 u1_t_data[PID21_DL_C9];
U1 u1_t_cmplt;
U1 u1_t_flag;
U1 u1_t_cnt;
U1 u1_t_swrstcnt;
U2 u2_t_buf[DIAG21_PIDC9_FLAG];
U4 u4_t_data;
U4 u4_t_cmd;
U1 u1_t_sndbuf_21[PID21_SENDDL_C9];
vd_g_Diagmgr_Set_Insp_Indx((U1)U1_MAX);
u1_t_flag = (U1)DIAG21_ZERO;
u4_t_data = (U4)DIAG21_ZERO;
u1_t_swrstcnt = u1_g_Diagmgr_Get_SwRst_Cnt();
if((U1)DIAG_CNT_ZERO == u1_t_swrstcnt) /* Determine if a software reset is in progress */
{
for(u1_t_cnt = (U1)DIAG21_ZERO; u1_t_cnt < (U1)DIAG21_PIDC9_FLAG; u1_t_cnt ++)
{
u4_t_cmd = u4_InspIndx_To_InspCMD[DIAG21_C9_INDX] + (U4)((U4)u1_t_cnt << (U4)DIAG21_BIT_SHIFT8);
u1_t_cmplt = u1_g_InspSoftwareVersion(u4_t_cmd, &u4_t_data, (U1)TRUE);
if((U1)INSPECT_SRV_CMPLT == u1_t_cmplt)
{
u1_t_flag = u1_t_flag + (U1)DIAG21_CNTONE;
}
else
{
/* Do Nothing */
}
u2_t_buf[u1_t_cnt] = (U2)u4_t_data;
}
vd_s_Diag21_U2ToU1(u2_t_buf, u1_t_data, (U1)DIAG21_PIDC9_FLAG);
vd_DG_COPY_U1(&u1_t_sndbuf_21[SND21_DATA1], &u1_t_data[0], (U1)PID21_DL_C9);
if((U1)DIAG21_PIDC9_FLAG == u1_t_flag)
{
u1_t_sndbuf_21[SND21_PID] = (U1)DIAG21_ID_C9;
DiagmgrSendResponse((U1)ID_MODE21, (U1)PID21_SENDDL_C9, u1_t_sndbuf_21, (U1)FALSE);
}
else
{
/* Do Nothing */
}
}
else
{
/* Do Nothing */
}
}"""
self.input_text.delete(1.0, tk.END)
self.input_text.insert(tk.END, example_code)
logging.info("已插入示例代码")
def update_progress(self, value):
self.progress['value'] = value
self.root.update_idletasks()
def parse_code(self):
try:
code = self.input_text.get(1.0, tk.END)
self.output_text.config(state=tk.NORMAL)
self.output_text.delete(1.0, tk.END)
self.update_progress(0)
# 解析typedef
logging.info("开始解析类型定义...")
typedef_map = self.parse_typedefs(code)
self.update_progress(20)
# 解析全局变量
logging.info("开始解析全局变量...")
self.parse_global_variables(code, typedef_map)
self.update_progress(50)
# 解析函数
logging.info("开始解析函数...")
self.parse_functions(code, typedef_map)
self.update_progress(100)
logging.info("解析完成")
self.output_text.config(state=tk.DISABLED)
except Exception as e:
logging.error(f"解析过程中发生错误: {str(e)}")
messagebox.showerror("错误", f"解析失败: {str(e)}")
def parse_typedefs(self, code):
typedef_pattern = r"typedef\s+(unsigned|signed)?\s*(char|short|long|int)\s+(\w+);"
matches = re.findall(typedef_pattern, code)
typedef_map = {}
for match in matches:
sign, base_type, alias = match
typedef_map[alias] = f"{sign} {base_type}".strip() if sign else base_type
if typedef_map:
self.output_text.insert(tk.END, "=== 类型定义 ===\n")
for alias, base_type in typedef_map.items():
self.output_text.insert(tk.END, f"{alias} -> {base_type}\n")
self.output_text.insert(tk.END, "\n")
logging.info(f"找到{len(typedef_map)}个类型定义")
else:
logging.info("未找到类型定义")
return typedef_map
def parse_global_variables(self, code, typedef_map):
# 首先移除函数体内的内容,以确保只匹配全局变量
# 简单的做法:移除所有在{}内的代码
# 注意:这个简单的移除可能不适用于嵌套{},但考虑到全局变量不会在函数内部,我们可以移除所有{}之间的内容
# 使用正则表达式移除函数体
code_no_funcs = re.sub(r'\{[^{}]*\}', '', code, flags=re.DOTALL)
# 构建类型匹配模式
base_types = r"\b(int|char|short|long|float|double|void)\b"
alias_types = "|".join(typedef_map.keys())
all_types = f"({base_types}|{alias_types})" if alias_types else f"({base_types})"
# 全局变量模式:类型后跟变量名,可能包含数组、初始化等
# 注意:我们只匹配不在函数内部的变量,所以已经移除了函数体
var_pattern = rf"{all_types}\s+(\w+)\s*(?:\[[^\]]*\])?\s*(?:=\s*[^;]+)?\s*;"
matches = re.findall(var_pattern, code_no_funcs)
if matches:
self.output_text.insert(tk.END, "=== 全局变量 ===\n")
for match in matches:
# 如果all_types是多个分组,match可能是元组,取第一个非空
if isinstance(match, tuple):
var_type = next(item for item in match if item)
else:
var_type = match
# 变量名是最后一个元素
var_name = match[-1] if isinstance(match, tuple) else match
self.output_text.insert(tk.END, f"{var_type} {var_name}\n")
self.output_text.insert(tk.END, "\n")
logging.info(f"找到{len(matches)}个全局变量")
else:
logging.info("未找到全局变量")
def parse_functions(self, code, typedef_map):
# 构建类型匹配模式
base_types = r"\b(int|char|short|long|float|double|void)\b"
alias_types = "|".join(typedef_map.keys())
all_types = f"({base_types}|{alias_types})" if alias_types else f"({base_types})"
# 函数模式:可能包含static等修饰符,函数名,参数列表,然后{
# 注意:允许函数名前有多个修饰符(如static, inline等)
func_pattern = rf"(\b\w+\b\s+)*({all_types})\s+(\w+)\s*\(([^)]*)\)\s*{{"
matches = re.finditer(func_pattern, code)
func_list = []
for match in matches:
# 整个匹配的字符串
full_match = match.group(0)
# 修饰符部分(可能有多个)
modifiers = match.group(1) # 注意:group1是第一个括号,但可能为None
return_type = match.group(2) # 返回类型
func_name = match.group(3) # 函数名
params = match.group(4).strip() # 参数部分
# 确定函数类型
if func_name.startswith("vd_"):
func_type = "无返回值函数"
elif re.match(r"^(u1|u2|u4|s1|s2|s4)_", func_name):
func_type = "有返回值函数"
else:
func_type = "普通函数"
# 解析参数
param_list = []
if params:
# 参数可能由逗号分隔,每个参数是类型+名称
# 注意:参数可能有空格,也可能有指针、数组等,我们简化处理:只考虑基本类型和别名,以及变量名
param_pattern = rf"({all_types})\s+(\w+)\s*(?:\[[^\]]*\])?\s*"
param_matches = re.findall(param_pattern, params)
for p_match in param_matches:
# 同样,类型可能是多个分组中的非空
p_type = next(item for item in p_match[0] if item) if isinstance(p_match[0], tuple) else p_match[0]
param_list.append(f"{p_type} {p_match[-1]}")
func_list.append((func_name, return_type, func_type, param_list))
if func_list:
self.output_text.insert(tk.END, "=== 函数定义 ===\n")
for func in func_list:
func_name, return_type, func_type, param_list = func
self.output_text.insert(tk.END, f"函数名: {func_name}\n")
self.output_text.insert(tk.END, f"返回类型: {return_type}\n")
self.output_text.insert(tk.END, f"函数类型: {func_type}\n")
self.output_text.insert(tk.END, f"参数个数: {len(param_list)}\n")
if param_list:
self.output_text.insert(tk.END, "参数列表:\n")
for i, param in enumerate(param_list, 1):
self.output_text.insert(tk.END, f" {i}. {param}\n")
self.output_text.insert(tk.END, "-" * 40 + "\n")
logging.info(f"找到{len(func_list)}个函数")
else:
logging.info("未找到函数定义")
# 自定义日志处理程序,用于将日志输出到文本框
class TextHandler(logging.Handler):
def __init__(self, text_widget):
super().__init__()
self.text_widget = text_widget
def emit(self, record):
msg = self.format(record)
self.text_widget.config(state=tk.NORMAL)
self.text_widget.insert(tk.END, msg + "\n")
self.text_widget.see(tk.END) # 自动滚动到底部
self.text_widget.config(state=tk.DISABLED)
if __name__ == "__main__":
root = tk.Tk()
app = CCodeParserApp(root)
root.mainloop()
```
### 主要改进:
1. **修复函数解析问题**:
- 允许函数前有`static`等修饰符
- 改进函数匹配模式,使用`re.finditer`遍历所有函数
- 正确处理参数列表中的复杂情况(如数组、指针未处理,但基础类型和变量名已处理)
2. **全局变量识别优化**:
- 通过移除函数体(用正则表达式删除`{...}`内的内容)来避免将局部变量识别为全局变量
3. **添加进度条**:
- 使用`ttk.Progressbar`在解析的每个步骤更新进度(20%, 50%, 100%)
4. **添加日志功能**:
- 使用`logging`模块记录解析过程
- 创建自定义Handler(`TextHandler`)将日志实时显示在界面文本框中
- 日志同时写入文件(`logs/parser.log`)
### 注意事项:
1. 由于C语言的复杂性,正则表达式可能无法覆盖所有情况(如函数指针、宏定义等)。对于更复杂的代码,可能需要使用专门的解析工具(如pycparser)。
2. 进度条是模拟的,实际解析非常快。如果解析大文件,可以考虑更细粒度的进度更新。
3. 日志文件会保存在`logs`目录下,每次运行会追加。
### 使用示例:
1. 运行程序,在输入框中粘贴您的C语言代码。
2. 点击“解析代码”,观察进度条和日志输出。
3. 解析结果将显示在输出区域。
### 相关问题
§§相关问题§§:
1. 如何扩展这个解析器以支持C++的类定义?
2. 正则表达式在处理嵌套括号时有什么局限性?
3. 如何修改代码以支持函数指针类型的解析?
4. 在解析大型代码文件时,如何优化正则表达式的性能?</think>我将为您解决C语言代码解析器的问题,并添加进度条和日志功能。以下是完整的解决方案:
```python
import tkinter as tk
from tkinter import scrolledtext, ttk, messagebox
import re
import logging
import os
from datetime import datetime
class CCodeParserApp:
def __init__(self, root):
self.root = root
self.root.title("C语言代码解析器")
self.root.geometry("900x800")
self.setup_logging()
# 创建输入区域
input_frame = tk.LabelFrame(root, text="输入C语言代码", padx=5, pady=5)
input_frame.pack(fill="both", expand=True, padx=10, pady=5)
self.input_text = scrolledtext.ScrolledText(input_frame, width=100, height=20)
self.input_text.pack(fill="both", expand=True, padx=5, pady=5)
# 按钮区域
btn_frame = tk.Frame(root)
btn_frame.pack(fill="x", padx=10, pady=5)
# 添加示例代码按钮
example_btn = tk.Button(btn_frame, text="插入示例代码", command=self.insert_example)
example_btn.pack(side="left", padx=5)
# 解析按钮
parse_btn = tk.Button(btn_frame, text="解析代码", command=self.parse_code, bg="#4CAF50", fg="white")
parse_btn.pack(side="left", padx=5)
# 保存日志按钮
save_log_btn = tk.Button(btn_frame, text="保存日志", command=self.save_logs)
save_log_btn.pack(side="right", padx=5)
# 进度条
self.progress = ttk.Progressbar(btn_frame, orient="horizontal", length=300, mode="determinate")
self.progress.pack(side="left", padx=10, fill="x", expand=True)
# 创建输出区域
output_frame = tk.LabelFrame(root, text="解析结果", padx=5, pady=5)
output_frame.pack(fill="both", expand=True, padx=10, pady=5)
self.output_text = scrolledtext.ScrolledText(output_frame, width=100, height=15)
self.output_text.pack(fill="both", expand=True, padx=5, pady=5)
self.output_text.config(state=tk.DISABLED)
# 日志区域
log_frame = tk.LabelFrame(root, text="日志信息", padx=5, pady=5)
log_frame.pack(fill="both", expand=True, padx=10, pady=5)
self.log_text = scrolledtext.ScrolledText(log_frame, width=100, height=8)
self.log_text.pack(fill="both", expand=True, padx=5, pady=5)
self.log_text.config(state=tk.DISABLED)
def setup_logging(self):
"""配置日志系统"""
if not os.path.exists("logs"):
os.makedirs("logs")
log_filename = f"logs/parser_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
logging.basicConfig(
filename=log_filename,
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)
logging.info("应用程序启动")
def log_to_gui(self, message, level="info"):
"""将日志信息显示在GUI中"""
self.log_text.config(state=tk.NORMAL)
timestamp = datetime.now().strftime("%H:%M:%S")
self.log_text.insert(tk.END, f"[{timestamp}] {message}\n")
self.log_text.see(tk.END) # 自动滚动到底部
self.log_text.config(state=tk.DISABLED)
# 记录到文件日志
if level == "info":
logging.info(message)
elif level == "warning":
logging.warning(message)
elif level == "error":
logging.error(message)
def save_logs(self):
"""保存日志到文件"""
try:
log_content = self.log_text.get("1.0", tk.END)
filename = f"logs/saved_log_{datetime.now().strftime('%H%M%S')}.txt"
with open(filename, "w") as f:
f.write(log_content)
self.log_to_gui(f"日志已保存到: {filename}", "info")
messagebox.showinfo("保存成功", f"日志已保存到:\n{filename}")
except Exception as e:
self.log_to_gui(f"保存日志失败: {str(e)}", "error")
messagebox.showerror("保存失败", f"无法保存日志:\n{str(e)}")
def update_progress(self, value):
"""更新进度条"""
self.progress['value'] = value
self.root.update_idletasks()
def insert_example(self):
"""插入示例代码"""
example_code = """static void Diag21_PID_C9(U1 u1_a_num)
{
U1 u1_t_data[PID21_DL_C9];
U1 u1_t_cmplt;
U1 u1_t_flag;
U1 u1_t_cnt;
U1 u1_t_swrstcnt;
U2 u2_t_buf[DIAG21_PIDC9_FLAG];
U4 u4_t_data;
U4 u4_t_cmd;
U1 u1_t_sndbuf_21[PID21_SENDDL_C9];
vd_g_Diagmgr_Set_Insp_Indx((U1)U1_MAX);
u1_t_flag = (U1)DIAG21_ZERO;
u4_t_data = (U4)DIAG21_ZERO;
u1_t_swrstcnt = u1_g_Diagmgr_Get_SwRst_Cnt();
if((U1)DIAG_CNT_ZERO == u1_t_swrstcnt) /* Determine if a software reset is in progress */
{
for(u1_t_cnt = (U1)DIAG21_ZERO; u1_t_cnt < (U1)DIAG21_PIDC9_FLAG; u1_t_cnt ++)
{
u4_t_cmd = u4_InspIndx_To_InspCMD[DIAG21_C9_INDX] + (U4)((U4)u1_t_cnt << (U4)DIAG21_BIT_SHIFT8);
u1_t_cmplt = u1_g_InspSoftwareVersion(u4_t_cmd, &u4_t_data, (U1)TRUE);
if((U1)INSPECT_SRV_CMPLT == u1_t_cmplt)
{
u1_t_flag = u1_t_flag + (U1)DIAG21_CNTONE;
}
else
{
/* Do Nothing */
}
u2_t_buf[u1_t_cnt] = (U2)u4_t_data;
}
vd_s_Diag21_U2ToU1(u2_t_buf, u1_t_data, (U1)DIAG21_PIDC9_FLAG);
vd_DG_COPY_U1(&u1_t_sndbuf_21[SND21_DATA1], &u1_t_data[0], (U1)PID21_DL_C9);
if((U1)DIAG21_PIDC9_FLAG == u1_t_flag)
{
u1_t_sndbuf_21[SND21_PID] = (U1)DIAG21_ID_C9;
DiagmgrSendResponse((U1)ID_MODE21, (U1)PID21_SENDDL_C9, u1_t_sndbuf_21, (U1)FALSE);
}
else
{
/* Do Nothing */
}
}
else
{
/* Do Nothing */
}
}"""
self.input_text.delete(1.0, tk.END)
self.input_text.insert(tk.END, example_code)
self.log_to_gui("已插入示例代码")
def parse_code(self):
"""解析C语言代码"""
try:
code = self.input_text.get(1.0, tk.END)
if not code.strip():
self.log_to_gui("错误: 没有输入代码", "error")
messagebox.showerror("错误", "请输入要解析的C语言代码")
return
self.log_to_gui("开始解析代码...")
self.output_text.config(state=tk.NORMAL)
self.output_text.delete(1.0, tk.END)
self.update_progress(0)
# 1. 解析typedef
self.log_to_gui("解析类型定义...")
typedef_map = self.parse_typedefs(code)
self.update_progress(20)
# 2. 解析全局变量
self.log_to_gui("解析全局变量...")
self.parse_global_variables(code, typedef_map)
self.update_progress(40)
# 3. 解析函数
self.log_to_gui("解析函数定义...")
self.parse_functions(code, typedef_map)
self.update_progress(80)
# 4. 显示统计信息
self.log_to_gui("生成统计报告...")
self.show_statistics(code)
self.update_progress(100)
self.output_text.config(state=tk.DISABLED)
self.log_to_gui("解析完成!")
messagebox.showinfo("完成", "代码解析成功完成!")
except Exception as e:
self.log_to_gui(f"解析错误: {str(e)}", "error")
messagebox.showerror("解析错误", f"发生错误:\n{str(e)}")
self.update_progress(0)
def parse_typedefs(self, code):
"""解析类型定义"""
typedef_pattern = r"typedef\s+(unsigned|signed)?\s*(char|short|long|int)\s+(\w+);"
matches = re.findall(typedef_pattern, code)
typedef_map = {}
for match in matches:
sign, base_type, alias = match
typedef_map[alias] = f"{sign} {base_type}".strip() if sign else base_type
self.log_to_gui(f"找到类型定义: {alias} -> {typedef_map[alias]}")
if typedef_map:
self.output_text.insert(tk.END, "=== 类型定义 ===\n")
for alias, base_type in typedef_map.items():
self.output_text.insert(tk.END, f"{alias} -> {base_type}\n")
self.output_text.insert(tk.END, "\n")
else:
self.output_text.insert(tk.END, "未找到类型定义\n\n")
self.log_to_gui("未找到类型定义", "warning")
return typedef_map
def parse_global_variables(self, code, typedef_map):
"""解析全局变量"""
# 移除函数体内容,只保留全局区域
code_no_funcs = re.sub(r'\{[^{}]*\}', '', code, flags=re.DOTALL)
# 构建类型匹配模式
base_types = r"\b(int|char|short|long|float|double|void)\b"
alias_types = "|".join(typedef_map.keys())
all_types = f"({base_types}|{alias_types})" if alias_types else f"({base_types})"
# 全局变量模式
var_pattern = rf"{all_types}\s+(\w+)\s*(?:\[[^\]]*\])?\s*(?:=\s*[^;]+)?\s*;"
matches = re.findall(var_pattern, code_no_funcs)
if matches:
self.output_text.insert(tk.END, "=== 全局变量 ===\n")
for match in matches:
if isinstance(match, tuple):
var_type = next(item for item in match if item)
var_name = match[-1]
else:
var_type = match
var_name = match
self.output_text.insert(tk.END, f"{var_type} {var_name}\n")
self.log_to_gui(f"找到全局变量: {var_type} {var_name}")
self.output_text.insert(tk.END, "\n")
else:
self.output_text.insert(tk.END, "未找到全局变量\n\n")
self.log_to_gui("未找到全局变量", "warning")
def parse_functions(self, code, typedef_map):
"""解析函数定义"""
# 构建类型匹配模式
base_types = r"\b(int|char|short|long|float|double|void)\b"
alias_types = "|".join(typedef_map.keys())
all_types = f"({base_types}|{alias_types})" if alias_types else f"({base_types})"
# 函数模式:支持static等修饰符
func_pattern = rf"(\b\w+\b\s+)*({all_types})\s+(\w+)\s*\(([^)]*)\)\s*{{"
matches = re.finditer(func_pattern, code)
func_list = []
for match in matches:
return_type = match.group(2)
func_name = match.group(3)
params = match.group(4).strip()
# 确定函数类型
if func_name.startswith("vd_"):
func_type = "无返回值函数"
elif re.match(r"^(u1|u2|u4|s1|s2|s4)_", func_name):
func_type = "有返回值函数"
else:
func_type = "普通函数"
# 解析参数
param_list = []
if params:
param_pattern = rf"({all_types})\s+(\w+)\s*(?:\[[^\]]*\])?"
param_matches = re.findall(param_pattern, params)
for p_match in param_matches:
if isinstance(p_match, tuple):
p_type = next(item for item in p_match if item)
p_name = p_match[-1]
else:
p_type = p_match
p_name = p_match
param_list.append(f"{p_type} {p_name}")
func_list.append((func_name, return_type, func_type, param_list))
self.log_to_gui(f"找到函数: {return_type} {func_name}(...)")
if func_list:
self.output_text.insert(tk.END, "=== 函数定义 ===\n")
for func in func_list:
func_name, return_type, func_type, param_list = func
self.output_text.insert(tk.END, f"函数名: {func_name}\n")
self.output_text.insert(tk.END, f"返回类型: {return_type}\n")
self.output_text.insert(tk.END, f"函数类型: {func_type}\n")
self.output_text.insert(tk.END, f"参数个数: {len(param_list)}\n")
if param_list:
self.output_text.insert(tk.END, "参数列表:\n")
for i, param in enumerate(param_list, 1):
self.output_text.insert(tk.END, f" {i}. {param}\n")
self.output_text.insert(tk.END, "-" * 50 + "\n")
else:
self.output_text.insert(tk.END, "未找到函数定义\n\n")
self.log_to_gui("未找到函数定义", "warning")
def show_statistics(self, code):
"""显示代码统计信息"""
lines = code.split('\n')
total_lines = len(lines)
code_lines = sum(1 for line in lines if line.strip() and not line.strip().startswith('//') and not line.strip().startswith('/*'))
# 统计函数数量
func_count = len(re.findall(r"\b\w+\s+\w+\s*\([^)]*\)\s*{", code))
# 统计全局变量数量
global_vars = len(re.findall(r"^\s*[a-zA-Z_][\w\s*]+\s+[a-zA-Z_]\w*\s*[;=]", code, re.MULTILINE))
self.output_text.insert(tk.END, "=== 代码统计 ===\n")
self.output_text.insert(tk.END, f"总行数: {total_lines}\n")
self.output_text.insert(tk.END, f"代码行数: {code_lines}\n")
self.output_text.insert(tk.END, f"函数数量: {func_count}\n")
self.output_text.insert(tk.END, f"全局变量数量: {global_vars}\n")
self.output_text.insert(tk.END, "\n")
if __name__ == "__main__":
root = tk.Tk()
app = CCodeParserApp(root)
root.mainloop()
```
### 问题分析与解决方案
1. **解析无响应问题**:
- **原因**:原始代码中的正则表达式模式无法匹配您提供的函数定义(包含`static`关键字)
- **修复**:
- 修改函数匹配模式为:`(\b\w+\b\s+)*({all_types})\s+(\w+)\s*\(([^)]*)\)\s*{{`
- 支持函数前的修饰符(如`static`)
- 使用`re.finditer`遍历所有匹配项
2. **进度条功能**:
- 添加`ttk.Progressbar`组件
- 在解析的各个阶段调用`update_progress()`方法
- 将解析过程分为4个阶段(类型定义、全局变量、函数、统计信息)
3. **日志功能**:
- 使用Python的`logging`模块记录到文件
- 添加GUI日志显示区域
- 实现`log_to_gui()`方法在界面显示日志
- 添加日志级别(info/warning/error)
- 添加"保存日志"按钮功能
### 功能增强
1. **代码统计功能**:
- 添加`show_statistics()`方法
- 统计代码行数、函数数量、全局变量数量
2. **错误处理**:
- 添加全面的异常处理
- 使用`messagebox`显示错误信息
- 日志记录所有错误
3. **界面优化**:
- 增大窗口尺寸(900x800)
- 添加更多视觉分隔
- 改进组件布局
4. **代码预处理**:
- 使用`re.sub`移除函数体内容,避免局部变量被误识别为全局变量
- 处理typedef类型的优先级
### 使用说明
1. **输入代码**:
- 在顶部文本框中输入C语言代码
- 或点击"插入示例代码"加载示例
2. **解析代码**:
- 点击"解析代码"按钮
- 观察进度条和日志信息
- 查看解析结果
3. **日志功能**:
- 所有操作都会记录在日志区域
- 点击"保存日志"将当前日志保存到文件
- 所有日志同时保存到`logs/`目录下的文件
### 相关问题