如何使用Python libclang获取宏语句的AST节点cursor?
可以实现,Python的libclang提供了完整的宏展开信息查询能力,配合解析选项和cursor属性即可拿到目标宏每次调用对应的所有子cursor。
必要前置配置
解析翻译单元时必须开启两个预处理相关选项,才能获取到完整的宏定义和展开信息:
import clang.cindex from clang.cindex import Index, TranslationUnit # 按需配置本地libclang库路径 clang.cindex.Config.set_library_file("/path/to/your/libclang.so") # 开启必要解析选项 parse_options = ( TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD | TranslationUnit.PARSE_PREPROCESSING_RECORD )
核心实现思路
- 先遍历预处理节点,收集目标宏的定义信息,用于后续过滤非目标宏的展开节点
- 递归遍历AST的所有cursor,判断cursor是否来自宏展开,通过
get_macro_expansion_locs()方法拿到该节点对应的宏定义位置和宏调用位置 - 按宏调用的位置分组,同一调用位置下的所有关联cursor即为该次宏调用对应的所有子cursor
完整代码示例
def collect_macro_call_children(tu, target_macro_name): # 先定位目标宏的定义 target_macro = None for node in tu.cursor.get_children(): if node.kind == clang.cindex.CursorKind.MACRO_DEFINITION \ and node.spelling == target_macro_name: # 可加判断过滤系统头文件宏:and not node.location.is_in_system_header target_macro = node break if not target_macro: return [] # 按宏调用位置分组存储对应子cursor macro_call_map = {} def traverse_ast(cursor): # 检查当前cursor是否来自宏展开 if cursor.location.is_from_macro_expansion: # 获取展开位置、宏定义位置、展开范围 exp_loc, def_loc, _, _ = cursor.location.get_macro_expansion_locs() # 校验是否是目标宏的展开 if def_loc.file == target_macro.location.file \ and def_loc.offset == target_macro.location.offset: # 以调用位置为唯一key分组 call_key = (exp_loc.file.name, exp_loc.line, exp_loc.column) if call_key not in macro_call_map: macro_call_map[call_key] = [] macro_call_map[call_key].append(cursor) # 递归遍历子节点 for child in cursor.get_children(): traverse_ast(child) traverse_ast(tu.cursor) return list(macro_call_map.values()) # 使用示例 index = Index.create() tu = index.parse("你的源文件路径.c", options=parse_options) # 收集maskout_different_softening_flag所有调用对应的子cursor all_macro_calls = collect_macro_call_children(tu, "maskout_different_softening_flag") # 输出验证 for call_idx, children in enumerate(all_macro_calls): print(f"第{call_idx+1}次宏调用的子节点:") for child in children: print(f" 节点类型:{child.kind.name},节点拼写:{child.spelling}")
补充说明
- 如果需要替换原代码中的宏调用,可以通过分组时拿到的调用位置,定位到原文件中宏调用的文本范围,直接修改原文件对应片段即可,不需要操作展开后的AST节点
- 该方案对嵌套宏、多参数宏同样生效,所有从该次宏调用生成的AST节点都会被正确归集
内容的提问来源于stack exchange,提问作者dearn44
相关产品推荐
相关产品推荐

