可视化 C 结构依赖项

tho*_*i56 6 c struct dot

在大型 C 项目中,有许多structs 具有其他structs 或指向它们的指针作为字段。我想创建一个有向图来显示“类型”之间的依赖关系。一个例子是

typedef struct javaStat {
    int idNo;
    struct idIdentList *className;
    struct typeModifiers *thisType;
    struct symbol thisClass;
} ...
Run Code Online (Sandbox Code Playgroud)

由此我想生成一个 DOT 结构,它看起来像

digraph {
    javaStat -> idIdentList
    javaStat -> typeModifiers
    javaStat -> symbol
}
Run Code Online (Sandbox Code Playgroud)

或者,使用 DOT 简写:

digraph {
    javaStat -> {idIdentList typeModifiers symbol}
}
Run Code Online (Sandbox Code Playgroud)

当然,可以手动添加第一行和最后一行,因此主要问题是将结构引用转换为图形“指针”行。

在这一点上,我对第一级解决方案感到满意,这意味着可以忽略更深的嵌套。

我首先尝试了一个简单的方法grep struct *.h,它产生了一些可行的方法:

typedef struct javaStat {
    struct idIdentList *className;
    struct typeModifiers *thisType;
    struct symbol thisClass;
typedef struct <next struct> {
Run Code Online (Sandbox Code Playgroud)

这是一个简单的问题,它是由Python的几行就可以解决,但是否有其他方便的解决方案,可能使用sedgrepawk和他的弟兄?

编辑:我已经意识到我想要这样做的原因是因为我需要找到一个或多个位于“结构树”底部的结构。

tho*_*i56 1

在尝试了doxygen@gavinb 的建议、@albert 的增强(这需要对源代码进行一些操作)和 @Renats 的使用Clangs python 绑定的建议(此时这对我来说有点复杂)之后,我尝试使用pycparser.

这是我需要的项目中该脚本的链接。

这是两个重要部分中的第一个:

ast = parse_file(args[-1], use_cpp=True,
                 cpp_args=cpp_args + args[0:-1])
print("digraph {")
for node in (node for node in ast.ext if isinstance(node, c_ast.Typedef)):
    if isinstance(node.type.type, c_ast.Struct):
        node2dot(node)
print("}")
Run Code Online (Sandbox Code Playgroud)

主循环将pycparser文件解析为 AST,然后过滤该 AST,仅获取输入的 typedef,node2dot如下部分所示:

def node2dot(node):
    if isinstance(node.type, c_ast.TypeDecl) and isinstance(node.type.type, c_ast.Struct):
        print("   ", node.type.type.name, "-> {", end="")
        if node.type.type.decls:  # has fields?
            for field in node.type.type.decls:
                if isstruct(field.type):
                    print("", struct_name_of(field.type), end="")
        print(" }")

def struct_name_of(node):
    if isinstance(node, c_ast.Struct):
        return node.name
    elif isinstance(node, c_ast.TypeDecl) or isinstance(node, c_ast.PtrDecl):
        return struct_name_of(node.type)

def isstruct(node):
    if isinstance(node, c_ast.Struct):
        return True
    elif isinstance(node, c_ast.TypeDecl) or isinstance(node, c_ast.PtrDecl):
        return isstruct(node.type)
Run Code Online (Sandbox Code Playgroud)