iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 9
0
Software Development

做一個JVM語言系列 第 9

Antlr練習,生成函數呼叫圖(Call Graph)

基本上是把程式呼叫的路線,
用Graphviz畫成圖,
而Graphviz基本上也是一種DSL語言,
為了特定領域所創作的語言。

所以本需求,基本上還是把Cymbol(C語言的子集)語言轉成Graphviz語言

int main() { fact(); a(); }

float fact(int n) {
  print(n);
  
  if ( n==0 ) then return 1;
  return n * fact(n-1);
}

void a() { int x = b(); if false then {c(); d();} }
void b() { c(); }
void c() { b(); }
void d() { }
void e() { }

轉換成

Graphviz語言

digraph G {
ranksep=.25;
edge [arrowsize=.5]
node [shape=circle, fontname="ArialNarrow",
fontsize=12, fixedsize=true, height=.45];
main; fact; a; b; c; d; e;
main -> fact;
main -> a;
fact -> print;
fact -> fact;
a -> b;
a -> c;
a -> d;
b -> c;
c -> b;
}

這兩種語言的差異有山大,
而且用途也不一樣,

可以有初步的想法,就是文法中可以很清楚的把函數的型定義清楚,在ENTER函數時,把函數名稱放進一個資料結構裏,
可以得到所有的函數,而函數中呼叫函數,觸發的時機,找到相對應的事件裏,拉上關係。

以本例而言,是用生成的CODE裏的,

static class FunctionListener extends CymbolBaseListener {
       Graph graph = new Graph();
       String currentFunctionName = null;

       public void enterFunctionDecl(CymbolParser.FunctionDeclContext ctx) {
           currentFunctionName = ctx.ID().getText();
           graph.nodes.add(currentFunctionName);
       }

       public void exitCall(CymbolParser.CallContext ctx) {
           String funcName = ctx.ID().getText();
           // map current function to the callee
           graph.edge(currentFunctionName, funcName);
       }
   }

巧妙的利用enterFunctionDecl,這時抓到所有函數的名稱,放到資料結構裏,達成第一個目的。
接著在exitCall裏,找出呼叫的關係。

當專案的程式高達數萬行時,一些源碼方析的工具,就相形重要了。
而呼叫圖(CALL GRAPH)是其中一個重要的分析手法。


上一篇
Antlr練習,轉換JSON到XML
下一篇
Antlr練習,程式符號的有效性檢查
系列文
做一個JVM語言12
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言