带你走进Cflow (四)·使用 ASCII 码来生成流图

目录

1、运行预处理器

2、使用 ASCII 码来生成流图

3、交叉引用输出


1、运行预处理器

        cflow 可以在分析之前预处理输入文件,与 cc 在编译之前做的工作一样。这样做可以允许 cflow 准确的处理所有的符号声明,这样就避免了使用--symbol 对特使符号做必要的定义。使用--cpp (--preprocess)选项可以使能预处理功能。对我们的样例 d.c,这种模式输出如下:

$ cflow --cpp -n d.c
 1 main() :
 2 fprintf()
 3 atoi()
 4 printdir()  (R):
 5 getcwd()
 6 perror()
 7 chdir()
 8 opendir()
 9 readdir()
 10 printf()
 11 ignorent() :
 12 strcmp()
 13 isdir() :
 14 stat()
 15 perror()
 16 putchar()
 17 printdir()
 
 (recursive: see 4)
 18 closedir()

        对比这个图和第 5 章没有使用--cpp 选项的结果。就像你看到的一样,S_ISDIR 不见了。宏被展开了。现在试着运行 cflow --cpp --number -i x d.c 并比较与之对应的没有使用预处理的图。你将会看到不使用--symbol 选项也能生成正确的结果。默认情况下--cpp 运行/usr/bin/cpp。如果你希望运行其他预处理命令,可以在参数中用后接等号后的符号指定它。比如,cflow --cpp='cc -E'将会运行 C 编译器来作为预处理器。

2、使用 ASCII 码来生成流图

        你可以使用--level-indent 选项来配置 cflow 输出的精确格式。最简单的用法是使用这个选项个边每个嵌套级别的缩进长度,他可以指定一个参数值做为每一个嵌套级别的缩进列数。比如下面的指令设置缩进长度为 2,是默认长度的一般:

cflow --level-indent 2 d.c

        比如,这样可以保证图在页面的边界之内。

        然而--level-indent 能做的不仅仅是这些。每一行都包含下面的图形元素:一个开始标识、一个结束标识和他们之间的几个缩进符。默认情况下,开始标识和结束标识是空的,每个缩进填充包含 4 个空格。

        如果--level-indent 选项的参数有 element=string 的形式,它指定一个字符串来代替输出的指定图元素。元素的命名为:

start 开始标识

0 缩进填充 0

1 缩进填充 1

end0 结束标识 0

end1 结束标识 1

        为审美会有两种类型的缩进填充和结束标识呢?记住这个流图代表了一个调用树,所以它包含终端节点(叶子),比如这是一个调用结束函数。还有非终端结点(这个调用后接另一个嵌套级的调用)。end0 表示非终端结点,end1 表示终端节点。

        对于缩进填充,缩进填充 1 用于代表图的边界,缩进填充 0 用于保持输出图的格式对齐。

        为了论证这个,我们考虑下面的例子程序:

/* foo.c */
 int
 main()
 {
 f();
 g();
 f();
 }
 
 int
 f()
 {
 i = h();
 }

我们用下面的字符串表示行元素:

start ‘::’
0 ‘ ’ (two spaces)
1 ‘| ’ (a vertical bar and a space)
end0 ‘+-’
end1 ‘\-’

这个对应的命令行是:

cflow --level begin=:: --level '0= ' --level '1=| ' --level end0='+-' --level end1='\\-' foo.c

        注意转义处理 end1 的反斜杠:一般来说,在--level-option 选项中的字符串可以包含常用的转义字符序列,所以反斜杠自己必须被转义。另一个捷径是,云溪在字符串中出现 CxN,C 表示一个单字符、N 表示一个十进制数字。这个符号的意思是“重复字符 C N 次”。然而当字符’x’用在字符串的开头时就失去了它的专用意义。这个命令产生下面的结果:

::+-main() :
 :: +-f() :
 :: | \-h()
 :: \-g()

        因此,我们可以用 ASCII 码表来表示调用树。GNU cflow 提供了一个特殊的选项--tree (-T),它是--level '0= ' --level '1=| ' --level end0='+-' --level end1='\\-'参数的快捷方式。下面这个例子是由这个选项生成的流图。源文件 wc.c 是 UNIX的 wc 命令的简单实现,附加在附录中。

 +-main() 
 +-errf() 
 | \-error_print()
 | 
 | +-vfprintf()
 | +-perror()
 | +-fprintf()
 | \-exit()
 +-counter() 
 | +-fopen()
 | +-perrf() 
 | | \-error_print()
 | |  [see 3]
 | +-getword() 
 | | +-feof()
 | | \-isword() 
 | | \-isalpha()
 | +-fclose()
 | \-report()
 | 
 | \-printf()
 \-report()
  [see 17]

3、交叉引用输出

        cflow 也可以生成交叉引用列表。这个模式使用-xref(-x)使能。交叉引用输出在单独的一行列出了每一个符号。每一行显示了标示符和和他出现的源位置。如果这个位置是该符号定义的地方,那么这一行用星号额外标识,并在后面附加它的定义。例如,下面是 d.c 程序的一个交叉引用输出段:

printdir * d.c:42 void printdir (int level,char *name)

printdir d.c:74

printdir d.c:102

        它显示 printdir 函数在第 42 行定义,被引用两次分别在第 74 和 102 行。出现在交叉引用列表中的符号受到--include 选项的控制。除此之外在“控制符号类型”一节中讲述的字符类,可用一个额外的符号类 t 控制背 typedef 关键自定义的类型名。

带你走进Cflow (一)-CSDN博客

带你走进Cflow (二)·输出格式和递归调用-CSDN博客

带你走进Cflow (三)·控制符号类型分析-CSDN博客

带你走进Cflow (四)·使用 ASCII 码来生成流图_第1张图片

你可能感兴趣的:(Cflow,java,前端,linux)