find_next_zero_bit 函数

本文介绍了一种用于查找内存中下一个零位(bit)位置的高效算法。通过位运算和循环处理,该算法能够快速定位到指定偏移量之后的第一个零位,适用于多种应用场景,如位图(bitmap)管理和内存分配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
        unsigned long offset)
{
    const unsigned long *p = addr + BITOP_WORD(offset); // offset位于p指向的long地址32位空间
    unsigned long result = offset & ~(BITS_PER_LONG-1); // offset是第result个4字节
    unsigned long tmp;

    if (offset >= size)
        return size;
    size -= result;                                     // 调整32位整倍数上
    offset %= BITS_PER_LONG;                            // offset位于32位的第几位
    if (offset) {                                       // offset不在一个long数据的第0位上,在1-31位中[luther.gliethttp]
        tmp = *(p++);
        tmp |= ~0UL >> (BITS_PER_LONG - offset);        // 将0-offset数据填充上1.
        if (size < BITS_PER_LONG)                       // 不足32bits
            goto found_first;
        if (~tmp)                                       // 取非非0说明含有0值
            goto found_middle;
        size -= BITS_PER_LONG;                          // 如果上面~tmp等于0,那么说明该*p数据为32位全1.[luther.gliethttp]
        result += BITS_PER_LONG;
    }
    while (size & ~(BITS_PER_LONG-1)) {                 // 好了,执行到这里,我们的offset已经处在4字节的第0位上,下面进行
        if (~(tmp = *(p++)))                            // 4字节快速查询.如果~tmp非0,说明该32位数据中含有0数据,找到.[luther.gliethttp]
            goto found_middle;
        result += BITS_PER_LONG;                        // 到下一个4字节空间
        size -= BITS_PER_LONG;                          // 减少4字节数据
    }
    if (!size)                                          // size等于0,说明首先size等于4字节整倍数,其次所有数据已经查完,
        return result;                                  // 所有数据全部为1,没有发现0位,result等于size.[luther.gliethttp]
    tmp = *p;                                           // size不是32位整倍数,还剩几个bit没有检查,继续执行下面检查工作.[luther.gliethtp]

found_first:
    tmp |= ~0UL << size;                                // 现在0-size为有效数据,size-31为未使用空间,所以先将size-31置成全1.
    if (tmp == ~0UL)    /* Are any bits zero? */        // 如果tmp全1,那么说明就没找找1个
        return result + size;    /* Nope. */             // result+size就等于函数传入的参数size大小.[luther.gliethttp]
found_middle:
    return result + ffz(tmp);                           // 我们在32位数据的0-31中发现必定存在0位值,计算他是第几位.[luther.gliethttp]
}

#define ffz(x)  __ffs(~(x))                             // __ffs找到第一次出现1值的偏移值,从bit0开始到bit31依次找[luther.gliethttp]
/**
 * __ffs - find first bit in word.
 * @word: The word to search
 *
 * Undefined if no bit exists, so code should check against 0 first.
 */
static inline unsigned long __ffs(unsigned long word)
{
    int num = 0;

#if BITS_PER_LONG == 64
    if ((word & 0xffffffff) == 0) {
        num += 32;
        word >>= 32;
    }
#endif
    if ((word & 0xffff) == 0) {                         // 低16位没有1值,那么num加16,同时高16位移动到低16位
        num += 16;                                      // 这样低16位永远都是去掉根本不存在的那种必然情况后的数据.
        word >>= 16;
    }
    if ((word & 0xff) == 0) {                           // 低8位是否有
        num += 8;
        word >>= 8;
    }
    if ((word & 0xf) == 0) {
        num += 4;
        word >>= 4;
    }
    if ((word & 0x3) == 0) {
        num += 2;
        word >>= 2;
    }
    if ((word & 0x1) == 0)
        num += 1;
    return num;                                         // 这样num就是出现1的偏移值了.[luther.gliethttp]
}
1、我输入C语言代码后无法解析,也就是点击解析代码没有反映,而且typedef unsigned char U1; typedef unsigned short U2; typedef unsigned long U4; typedef signed char S1; typedef signed short S2; typedef signed long S4;这些是已经定义好的,我在输入代码时只会输入一段代码比如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 */ } } 2、增加进度条的功能 3、增加日志功能
最新发布
07-17
<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/`目录下的文件 ### 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值