Визуализация C структурных зависимостей - PullRequest
5 голосов
/ 11 марта 2020

В большом C проекте есть много struct с другими struct или указателями на них в качестве полей. Я хочу создать ориентированный граф, чтобы показать зависимости между «типами». Примером может быть

typedef struct javaStat {
    int idNo;
    struct idIdentList *className;
    struct typeModifiers *thisType;
    struct symbol thisClass;
} ...

. Из этого я хотел бы сгенерировать структуру DOT, которая выглядела бы как

digraph {
    javaStat -> idIdentList
    javaStat -> typeModifiers
    javaStat -> symbol
}

или, используя сокращение DOT:

digraph {
    javaStat -> {idIdentList typeModifiers symbol}
}

Конечно, первая и последняя строки могут быть добавлены вручную, поэтому основной проблемой является преобразование структурных ссылок в строки указателя графа.

На данный момент я доволен Решение первого уровня, означающее, что более глубокое вложение может быть проигнорировано.

Сначала я попробовал простой grep struct *.h, который дал что-то выполнимое:

typedef struct javaStat {
    struct idIdentList *className;
    struct typeModifiers *thisType;
    struct symbol thisClass;
typedef struct <next struct> {

Это простая проблема, которая состоит из нескольких строк: Python решил бы, но есть ли другие удобные решения, возможно, с использованием sed, grep, awk и их братьев?

РЕДАКТИРОВАТЬ: я понял, что причина, почему я хочу сделать это потому что мне нужно найти одну или несколько структур, которые лежат в основе "struct tree".

Ответы [ 4 ]

2 голосов
/ 12 марта 2020

Я бы начал с запуска Doxygen поверх кодовой базы. Его можно легко настроить для создания Dot-графиков ваших структур. Для правильного синтаксического анализа всей этой информации и создания правильных выходных данных достаточно ошибок, и вы сэкономите много времени, используя существующее решение.

1 голос
/ 18 марта 2020

Попробовав предложение doxygen от @gavinb, дополненное @albert, которое потребовало некоторых манипуляций с источниками, и предложение @ Renats использовать привязки Clang s 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("}")

Основная l oop, где pycparser анализирует файл в 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)
1 голос
/ 12 марта 2020

Clang 9 допускает JSON представление AST файла c (найдено в этом вопросе ). JSON AST может быть обработан дополнительно для генерации целевого вывода.

Например, скрипт Python:

#clang_ast_to_dot.py
from jsonpath_rw_ext import parse;
import sys, json;

def extract_struct_name(fieldDefinition):
  return fieldDefinition["type"]["qualType"].replace("struct", "").replace("*", "").replace(" ","")

def is_struct_field(fieldDefinition, knownStructs):
  return (fieldDefinition["kind"] == "FieldDecl" and 
          ("struct " in fieldDefinition["type"]["qualType"] or 
           extract_struct_name(fieldDefinition) in knownStructs))


data = json.load(sys.stdin)

allStructs = {}

for structDef in parse('$.inner[?(@.kind=="RecordDecl")]').find(data):
    allStructs[structDef.value["name"]]=structDef.value

print("digraph {")
for name, structDescription in allStructs.items():
    print("    %s -> {%s}"
          % (name, ", ".join(extract_struct_name(field) for field in structDescription["inner"] if is_struct_field(field, allStructs))))
print("}")

называется:

clang -Xclang -ast-dump=json MyCFile.c | python clang_ast_to_dot.py

производит:

digraph {
    javaStat -> {idIdentList, typeModifiers, symbol}
}

Конечно, это Например, я уверен, что это не сработает во всех случаях.

0 голосов
/ 14 марта 2020

Расширение ответа @gavinb с небольшим примером.

Наличие файла конфигурации doxygen с EXTRACT_ALL = YES и HAVE_DOT=YES (а для более сложных ситуаций может быть полезно установить DOT_GRAPH_MAX_NODES = в соответствующее значение и установите DOT_IMAGE_FORMAT = svg; также интересно может быть UML_LOOK = YES).

Я использовал простой пример:

typedef  struct idIdentList {
     int member;
};
typedef  struct typeModifiers {
     int member;
};
typedef  struct symbol {
     int member;
};
typedef  struct s1 {
     struct s2 member;
};
typedef  struct s2 {
     struct s3 member;
};
typedef  struct s3 {
     struct s4 member;
};
typedef  struct s4 {
     struct s5 member;
};
typedef  struct s5 {
     struct s6 member;
};
typedef  struct s6 {
     struct s6 member;
};
typedef struct javaStat {
    int idNo;
    struct idIdentList *className;
    struct typeModifiers *thisType;
    struct symbol thisClass;
    struct s1 member;
};

и из этого я получил:

enter image description here

У Doxygen нет полной обзорной диаграммы, но с помощью небольшого количества сценариев можно создать «суперструктуру» (я также добавил здесь struct not_ref, где нет дополнительной ссылки):

typedef struct super_script
{
  struct idIdentList a1;
  struct typeModifiers a2;
  struct symbol a3;
  struct s1 a4;
  struct s2 a5;
  struct s3 a6;
  struct s4 a7;
  struct s5 a8;
  struct s6 a9;
  struct javaStat a10;
  struct not_ref a11;
};

typedef struct not_ref
{
  int member;
};

В результате:

enter image description here

при установке DOT_CLEANUP = NO используемый dot файл будет доступен в каталоге html

...