构建树图

构建树图

假设我在一个目录中有一个程序P11;它调用另外 2 个程序 P21 和 P22。 P21 和 P22 分别调用 2-2 个其他程序。

IE

Level-1:           |--------------P11-------------|
Level-2:  |--------P21----------|    |----------P22----------|...
Level-3:  P31                 P32    P33                   P34...
       .                   .      .                     .
       .                   .      .                     . 

就像一个树形图,有 100 个级别,每个级别有 100 个节点,总共有 1000 个节点。

我需要一个 shell 脚本来给我这样的树结构。

例如shell脚本程序是-' MYPGM.sh'。

它在运行时需要一个参数。我们可以在此处提供程序名称,例如 P11。并且脚本给出了这样一个树形图。

输出结构不必采用上面给出的类似图表的格式。我们可以使用索引或您建议的任何内容。例如输出文件可以是 –

1. P11
1.1 P21 - 1.2 P22
1.1.1 P31 - 1.1.2 P32 – 1.2.1 P33 – 1.2.2 P34

即每个程序的索引=它的父程序的索引+“。” + 它在该父程序中的序列号。

事实是 - 级别数和每个级别中的节点数未知,但非常大。

用于调用另一个程序的程序语法如下:

呼叫“CHILD_PGM_NAME”

在给定程序中查找子程序的命令如下:

 egrep '^CALL| CALL ' $pgm_name > call_output | cut -d'"' -f2 call_output > call_output_cut | cat call_output_cut

我陷入了困境 - 如何循环此命令以获得上述输出文件。

有人可以提出建议吗?

答案1

对于这个问题,我建议 awk、python、perl 或类似的。下面的起点是一个 perl 脚本,如果尚未访问,它将对“程序”进行排队。输出采用图形可视化形式(如@derobert 建议)。

#!/usr/bin/perl

print "digraph{\n rankdir=LR \n";

my %visited = ();
while(<>){                               # for all lines in all files in @ARGV

  $visited{$ARGV}=1;                     # $ARGV = current file

  if(/\bCALL\s*"(.+?)"/) {
      print "$ARGV -> $1;\n" ;
      push @ARGV,$1  unless $visited{$1};
      $visited{$1}=1;
  }
}

print "}\n";

用法:

perl calltree p1 > x.dot
dot -Tpdf -o x.pdf x.dot

或者(谢谢@derobert)

dot -Tx11 x.dot

立即查看图表。

正如@muru 指出的,通常这不是树。

答案2

@JJoao 的方法绝对是最适合使用的方法。但是,我编写了这个非常低效的脚本,可能会引起兴趣:

#! /bin/bash

SRC_DIR="/path/to/programs"
TMP_DIR="/tmp/tree"
declare -A FUNCS

iterate ()
(
    program="$1"
    FUNCS["$program"]="$TMP_DIR/$program"
    mkdir "${FUNCS[$program]}"
    grep -Po '(?<=\bCALL ")[^"]*' "$SRC_DIR/$program" | while read child
    do
        if [[ -n ${FUNCS[$child]} ]]
        then
            ln -s "${FUNCS[$child]}" "${FUNCS[$program]}/$child"
        else
            iterate "$child"
        fi
    done
)

[[ -n $1 ]] && { iterate "$1"; tree -dlo call-graph.html -H "$TMP_DIR" "$TMP_DIR"; }
rm -rf "$TMP_DIR"

它创建一个目录,每个目录代表一个函数,包含指向它调用的其他目录/函数的符号链接。该tree程序天生擅长绘制树(该-l选项遵循符号链接,除非检测到递归,-o生成 HTML 输出)。

当然,理想情况下,您应该查看适合您的语言的调用图生成器。这那么问题列出了一些 C 语言的版本,也许您能够找到支持您的语言的版本。

相关内容