代码之家  ›  专栏  ›  技术社区  ›  rocky

我如何影响Graphviz/dot通过消除蛇行和更好的边交叉来生成更好的控制流图?

  •  0
  • rocky  · 技术社区  · 6 年前

    我正在为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];
    }
    

    圆点为上面产生的图像是 enter image description here

    注意一条线是如何蜿蜒而下,穿过一个直箭头的。相反,我更希望没有一个直向下的箭头会被交叉。用花键连接的边缘会使交叉处变得更好。

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

    思想?

    编辑

    怎样

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

    我曾尝试过边缘排序和放置,但我只是没有直觉,不知道什么时候该放东西早一点还是晚一点。

    1 回复  |  直到 6 年前
        1
  •  3
  •   vaettchen    6 年前

    你需要做两件事来改善现状:

    • 比其他边更早地绘制(其中一条)要控制的边,
    • 告诉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 */
    }
    

    这给了你

    enter image description here

    这里有一些尝试和错误,但我相信这会有所帮助。