如何通过Python的libclang获取全局单行多变量声明的所有变量?
解决libclang遍历C代码AST无法捕获多变量声明后续变量的问题
问题说明
使用Python的libclang遍历C代码AST时,遇到同一行多变量声明(如bool a0,a1,a2;),仅能识别第一个变量a0,无法获取a1和a2的声明信息。
目标C代码(simple.c)
/* simple.c */ bool LED0 = 0; /* state0 */ bool LED1 = 0; /* state1 */ bool LED2 = 1; /* state2 */ /* inputs */ bool a0,a1,a2;
原Python解析代码
import sys import clang.cindex var_decls = [] function_decls = [] def printnode(node): print(f"Found : {node.displayname} type: {node.kind} [line={node.location.line}]") def traverse(node): for child in node.get_children(): traverse(child) if node.kind == clang.cindex.CursorKind.DECL_STMT: print("DECL_STMT") printnode(node) if node.kind == clang.cindex.CursorKind.VAR_DECL: var_decls.append(node) printnode(node) if node.kind == clang.cindex.CursorKind.FUNCTION_DECL: function_decls.append(node) index = clang.cindex.Index.create() translation_unit = index.parse("simple.c") traverse(translation_unit.cursor)
运行输出
Found : LED0 type: CursorKind.VAR_DECL [line=2] Found : LED1 type: CursorKind.VAR_DECL [line=3] Found : LED2 type: CursorKind.VAR_DECL [line=4] Found : a0 type: CursorKind.VAR_DECL [line=7]
解决步骤
1. 指定C99标准解析代码
bool是C99引入的关键字,若解析时未指定标准,clang会默认使用C89,将bool视为普通标识符,导致多变量声明解析异常。修改解析代码,添加-std=c99参数:
translation_unit = index.parse("simple.c", args=["-std=c99"])
2. 调整遍历逻辑,覆盖兄弟节点
部分版本的libclang中,同一行的多变量声明会以兄弟节点形式存在,而非子节点。修改遍历函数,同时遍历子节点和兄弟节点,确保不遗漏任何VAR_DECL:
def traverse(node): current_node = node while current_node is not None: # 处理当前节点 if current_node.kind == clang.cindex.CursorKind.DECL_STMT: print("DECL_STMT") printnode(current_node) if current_node.kind == clang.cindex.CursorKind.VAR_DECL: var_decls.append(current_node) printnode(current_node) if current_node.kind == clang.cindex.CursorKind.FUNCTION_DECL: function_decls.append(current_node) # 递归处理子节点 for child in current_node.get_children(): traverse(child) # 移动到下一个兄弟节点 current_node = current_node.next_sibling
最终修改后的完整代码
import sys import clang.cindex var_decls = [] function_decls = [] def printnode(node): print(f"Found : {node.displayname} type: {node.kind} [line={node.location.line}]") def traverse(node): current_node = node while current_node is not None: if current_node.kind == clang.cindex.CursorKind.DECL_STMT: print("DECL_STMT") printnode(current_node) if current_node.kind == clang.cindex.CursorKind.VAR_DECL: var_decls.append(current_node) printnode(current_node) if current_node.kind == clang.cindex.CursorKind.FUNCTION_DECL: function_decls.append(current_node) # 递归处理子节点 for child in current_node.get_children(): traverse(child) current_node = current_node.next_sibling index = clang.cindex.Index.create() # 添加C99标准参数 translation_unit = index.parse("simple.c", args=["-std=c99"]) traverse(translation_unit.cursor)
运行后预期输出
Found : LED0 type: CursorKind.VAR_DECL [line=2] Found : LED1 type: CursorKind.VAR_DECL [line=3] Found : LED2 type: CursorKind.VAR_DECL [line=4] Found : a0 type: CursorKind.VAR_DECL [line=7] Found : a1 type: CursorKind.VAR_DECL [line=7] Found : a2 type: CursorKind.VAR_DECL [line=7]
内容的提问来源于stack exchange,提问作者aneccodeal
相关产品推荐
相关产品推荐

