2

我正在为 Python 程序绘制控制流图,并且想影响不应该跨越哪种边缘。有没有办法做到这一点?

考虑这个简单的 Python 程序:

try:
    a += 1
except:
    a += 2
else:
    a = 3

还有一个点程序来表示通过https://github.com/rocky/python-control-flow/生成的控制流

digraph G {
  mclimit=1.5;
  rankdir=TD; ordering=out;
  graph[fontsize=10 fontname="Verdana"];
  color="#efefef";
  node[shape=box style=filled fontsize=8 fontname="Verdana" fillcolor="#efefef"];
  edge[fontsize=8 fontname="Verdana"];

  node_0 [shape = "oval"][label="Basic Block 0\loffsets: 0..12\lflags=entry, block, unconditional, try\ljumps=[34]\l"];
  node_1 [label="Basic Block 1\loffsets: 14..30\lflags=except, unconditional\ljumps=[38]\l"];
  node_2 [label="Basic Block 2\loffsets: 32..32\lflags=end finally\l"];
  node_3 [label="Basic Block 3\loffsets: 34..36\l"];
  node_4 [label="Basic Block 4\loffsets: 38..40\lflags=no fallthrough\l"];

  node_0 -> node_2 [weight=1][color="red"];
  node_3 -> node_4 [weight=10];
  node_0 -> node_1 [weight=1][color="red"];
  node_2 -> node_3 [weight=10];
  node_0 -> node_1 [weight=10][style="invis"];
  node_1 -> node_2 [weight=10][style="invis"];
  node_1 -> node_4 [weight=1];
  node_0 -> node_3 [weight=1];
}

dot 为上面产生的图像是在此处输入图像描述

请注意一条线是如何蜿蜒而下并穿过一个直箭头的。相反,我宁愿没有一个笔直的向下箭头会被越过。花键边缘会形成更好的交叉位置。

如果你看点,我有两个不可见的向下边缘,用于对齐。(在字节码中,这些遵循线性指令序列)。

因此,如果需要越过一条向下的直线(而这里不需要),则不可见的边缘将优于可见的边缘。

想法?

编辑

到目前为止,一个很好的答案建议更改定义边缘的顺序,并在某些情况下指定应该进行边缘连接的位置。

在这个应用程序中,我确实有来自支配树的分层嵌套信息,并且我可以对边缘进行分类:循环的边缘、跳转到复合结构末尾的边缘、打破循环的边缘等等。

所以现在问题变成了如何使用这些信息来避免那些蛇形箭头,并确保循环中断优先于跨越边缘而不是说“if”/“else”跳转边缘。

这感觉就像 VLSI 设计:提出一组适用于每种(控制流)结构的模式,然后这些模式将正确嵌套和排序。

我已经尝试过边缘排序和放置,我只是没有直观的感觉什么时候应该早点或晚点放东西。

非常感谢结构化控制流边缘的指导或更好的设计规则。

4

1 回答 1

3

你需要做两件事来改善这种情况:

  • 比其他边缘更早地绘制(其中一个)您想要控制的边缘,
  • 告诉graphviz您希望它们附着在哪里(北,东......)

我已经相应地编辑了您的代码

digraph G {
  mclimit=1.5;
  rankdir=TD; ordering=out;
  graph[fontsize=10 fontname="Verdana"];
  color="#efefef";
  node[shape=box style=filled fontsize=8 fontname="Verdana" fillcolor="#efefef"];
  edge[fontsize=8 fontname="Verdana"];

  node_0 [shape = "oval"][label="Basic Block 0\loffsets: 0..12\lflags=entry, block, unconditional, try\ljumps=[34]\l"];
  node_1 [label="Basic Block 1\loffsets: 14..30\lflags=except, unconditional\ljumps=[38]\l"];
  node_2 [label="Basic Block 2\loffsets: 32..32\lflags=end finally\l"];
  node_3 [label="Basic Block 3\loffsets: 34..36\l"];
  node_4 [label="Basic Block 4\loffsets: 38..40\lflags=no fallthrough\l"];

  node_0 -> node_3:nw [weight=1];           /* moved up and added directions*/
  node_0 -> node_2 [weight=1][color="red"];
  node_3 -> node_4 [weight=10];
  node_0 -> node_1 [weight=1][color="red"];
  node_2 -> node_3 [weight=10];
  node_0 -> node_1 [weight=10][style="invis"];
  node_1 -> node_2 [weight=10][style="invis"];
  node_1:se -> node_4:ne [weight=1];            /* added directions */
}

这给了你

在此处输入图像描述

这里涉及一些试验和错误,但我相信这应该会有所帮助。

于 2018-11-25T22:59:18.913 回答