AST 转 CFG
以 ArrayList 中 remove(int index) 为例(486行)。
函数源代码如下。
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
method[row] node parent height start.x start.y end.x end.y content
remove[486] 0 -1 0 496 8 496 26 first-statement@rangeCheck(index);
remove[486] 1 -1 0 505 8 505 35 after-branch@elementData[--size]=null;
remove[486] 2 -1 0 502 8 504 39 if-statement@if (numMoved > 0) System.arraycopy(elementData,index + 1,elementData,index,numMoved);
remove[486] 3 2 1 503 12 504 39 then-body@System.arraycopy(elementData,index + 1,elementData,index,numMoved);
remove[486] 4 -1 0 507 8 507 24 return@return oldValue;
上述节点信息对应的是函数的抽象语法树(AST),可以形象化展示为下图。
其中 node -1 对应的是函数的函数体,其节点编号为 -1。
在 AST 中,函数的顺序执行语句的父节点为函数体,也就是 node -1;函数中的 if - condition - then 语句中,then-body 的父节点是 if 语句;对应 for,while等语句你可以输出他们的节点信息尝试一下。
现在需要将上面这个 AST 转化为下面这样的 CFG。
转化的思路如下:
- 首先找到所有父节点为 -1 的节点,并依据他们的代码行数(start.x)构建顺序执行的流程图,可以得到 0 ->2 -> 1 -> 4,并得到 AST 中高度为 1 的节点列表A {0, 1, 2, 4}
- 遍历其他的节点,找到父节点在节点列表 A 中的节点,得到 AST 中高度为 2 的节点列表 B {3}。对于每个节点,例如节点 3,将其插入到父节点(2)之后,父节点后的顺序执行节点(1)之前
对于函数中的 for, while 等语句,可以采用类似方法来构建流程图。
同时也可以利用节点的 content信息,例如content信息为then-body的节点会与if-statement和after-branch节点各有一条边。