2

我正在开发一个 python 库,它将 python 源代码转换为控制流图(CFG)。作为中间步骤,我已将源代码转换为 xml 表示形式。

例如下面的源代码:

def bar(): # line 32
    a += 1 # line 33
    for x in [1,2]: # line 34
        print x # line 35
        if x%2: # line 36
            print x**2 # line 37
            break # line 38
        else: # line 39
            print x**3 # line 40
    else: # line 41
        print "wpp" # line 42
    print "done" # line 43

转换成如下xml:

<?xml version="1.0" ?>
<module>
:   0
:   <functiondef>
:   :   32
:   :   <augassign>
:   :   :   33
:   :   :   <name>33</name>
:   :   :   <add>add</add>
:   :   :   <num>33</num>
:   :   </augassign>
:   :   <for>
:   :   :   34
:   :   :   <print>
:   :   :   :   35
:   :   :   :   <name>35</name>
:   :   :   </print>
:   :   :   <if>
:   :   :   :   36
:   :   :   :   <binop>
:   :   :   :   :   36
:   :   :   :   :   <name>36</name>
:   :   :   :   :   <mod>mod</mod>
:   :   :   :   :   <num>36</num>
:   :   :   :   </binop>
:   :   :   :   <print>
:   :   :   :   :   37
:   :   :   :   :   <binop>
:   :   :   :   :   :   37
:   :   :   :   :   :   <name>37</name>
:   :   :   :   :   :   <pow>pow</pow>
:   :   :   :   :   :   <num>37</num>
:   :   :   :   :   </binop>
:   :   :   :   </print>
:   :   :   :   <break>38</break>
:   :   :   :   <else>
:   :   :   :   :   39
:   :   :   :   :   <print>
:   :   :   :   :   :   40
:   :   :   :   :   :   <binop>
:   :   :   :   :   :   :   40
:   :   :   :   :   :   :   <name>40</name>
:   :   :   :   :   :   :   <pow>pow</pow>
:   :   :   :   :   :   :   <num>40</num>
:   :   :   :   :   :   </binop>
:   :   :   :   :   </print>
:   :   :   :   </else>
:   :   :   </if>
:   :   :   <else>
:   :   :   :   41
:   :   :   :   <print>
:   :   :   :   :   42
:   :   :   :   :   <str>42</str>
:   :   :   :   </print>
:   :   :   </else>
:   :   </for>
:   :   <print>
:   :   :   43
:   :   :   <str>43</str>
:   :   </print>
:   </functiondef>
</module>

现在,我需要做的就是把这个xml变成一个CFG,表示如下:

0 [32]
32 [33]
33 [34]
34 [35, 42]
35 [36]
36 [37, 40]
37 [38]
38 [43]
40 [34]
42 [43]
43 []

现在,我已经处理了迄今为止我见过的大多数情况。但是,我在将 for 循环的正确端连接回 for 循环的顶部/定义时遇到了一些问题(第 34 行)

我非常感谢任何能帮助我弄清楚如何找出 for 循环的哪些节点连接回 for 循环顶部的人。在这个例子中,只有一个这样的节点,即第 40 行的那个

4

1 回答 1

0

您可以使用 PIPI 的 pycfg 生成文本和一个名为 cfg.py 的 python 程序(包含在下面)来创建一个漂亮的图形图表。

例如,我将上面的代码转换为:

for x in [1,2]: 
    print(x) 
    if x%2: 
        print(x**2) 
        break 
    else: 
        print(x**3) 
else: 
    print("wpp") 
    print("done") 

并得到了这个结果:

strict digraph "" {
    node [label="\N"];
    0    [label="0: start"];
    1    [label="1: for: (True if [1, 2] else False)"];
    0 -> 1;
    2    [label="1: x = [1, 2].shift()"];
    1 -> 2;
    8    [label="0: stop"];
    1 -> 8;
    7    [label="7: print((x ** 3))"];
    7 -> 1;
    3    [label="2: print(x)"];
    2 -> 3;
    4    [label="3: if: (x % 2)"];
    3 -> 4;
    4 -> 7;
    5    [label="4: print((x ** 2))"];
    4 -> 5;
    6    [label="5: break"];
    5 -> 6;
    6 -> 8;
}

检查员代码的 CFG

这里有一篇关于如何做到这一点的文章:

https://www.geeksforgeeks.org/draw-control-flow-graph-using-pycfg-python/

如果您在运行它时遇到任何问题,请告诉我。这是我的“go”脚本供参考:

python ./cfg.py ./target.py

cfg.py 作为 GeeksforGeeks 文章的一部分提供。这是以防链接最终失效:

from pycfg.pycfg import PyCFG, CFGNode, slurp
import argparse
import tkinter as tk
from PIL import ImageTk, Image
  
if __name__ == '__main__':
    parser = argparse.ArgumentParser()
  
    parser.add_argument('pythonfile', help ='The python file to be analyzed')
    args = parser.parse_args()
    arcs = []
  
    cfg = PyCFG()
    cfg.gen_cfg(slurp(args.pythonfile).strip())
    g = CFGNode.to_graph(arcs)
    g.draw(args.pythonfile + '.png', prog ='dot')
    print(g.string())
    
  
    # Draw using tkinter.
    root = tk.Tk()
    root.title("Control Flow Graph")
    img1 = Image.open(str(args.pythonfile) + ".png")  # PIL solution
    img1 = img1.resize((800, 600), Image.ANTIALIAS)
    img = ImageTk.PhotoImage(img1)
      
    background ="gray"
  
    panel = tk.Label(root, height = 600, image = img)
    panel.pack(side = "top", fill ="both", expand = "yes")
    nodes = g.number_of_nodes()     # no. of nodes.
    edges = g.number_of_edges()     # no. of Edges.
    complexity = edges - nodes + 2         # Cyclomatic complexity
  
    frame = tk.Frame(root, bg = background)
    frame.pack(side ="bottom", fill ="both", expand = "yes")
          
    tk.Label(frame, text ="Nodes\t\t"+str(nodes), bg = background).pack()
    tk.Label(frame, text ="Edges\t\t"+str(edges), bg = background).pack()
    tk.Label(frame, text ="Cyclo Complexity\t"+
             str(complexity), bg = background).pack()
  
    
    root.mainloop()from pycfg.pycfg import PyCFG, CFGNode, slurp
import argparse
import tkinter as tk
from PIL import ImageTk, Image
  
if __name__ == '__main__':
    parser = argparse.ArgumentParser()
  
    parser.add_argument('pythonfile', help ='The python file to be analyzed')
    args = parser.parse_args()
    arcs = []
  
    cfg = PyCFG()
    cfg.gen_cfg(slurp(args.pythonfile).strip())
    g = CFGNode.to_graph(arcs)
    g.draw(args.pythonfile + '.png', prog ='dot')
    print(g.string())
    
  
    # Draw using tkinter.
    root = tk.Tk()
    root.title("Control Flow Graph")
    img1 = Image.open(str(args.pythonfile) + ".png")  # PIL solution
    img1 = img1.resize((800, 600), Image.ANTIALIAS)
    img = ImageTk.PhotoImage(img1)
      
    background ="gray"
  
    panel = tk.Label(root, height = 600, image = img)
    panel.pack(side = "top", fill ="both", expand = "yes")
    nodes = g.number_of_nodes()     # no. of nodes.
    edges = g.number_of_edges()     # no. of Edges.
    complexity = edges - nodes + 2         # Cyclomatic complexity
  
    frame = tk.Frame(root, bg = background)
    frame.pack(side ="bottom", fill ="both", expand = "yes")
          
    tk.Label(frame, text ="Nodes\t\t"+str(nodes), bg = background).pack()
    tk.Label(frame, text ="Edges\t\t"+str(edges), bg = background).pack()
    tk.Label(frame, text ="Cyclo Complexity\t"+
             str(complexity), bg = background).pack()
  
    
    root.mainloop()

文件 target.py 包含此响应顶部的代码版本。让它与 Cygwin 一起工作有点麻烦。依赖项之一是 GraphViz(我认为),并且安装没有正确设置某些路径。如果有人有任何困难,请给我留言,我会指导你完成它。

于 2022-03-05T00:56:32.800 回答