1. 程式人生 > >使用 python指令碼獲取函式呼叫關係

使用 python指令碼獲取函式呼叫關係

        函式關係調用圖可使用TestBed或者Source Insight軟體生成。本文工具所提取的函式呼叫關係,是為了方便編寫詳細設計文件,自動將該函式所有呼叫的函式列舉出來。

首先上傳程式碼流程圖:


程式碼的第一部分是變數定義,

  1. 定義了keyWordList列表,列表中的關鍵字可以根據實際的專案進行調整
  2. 定義了兩個正則表示式,第一個正則表示式用來提取包含括號的語句中,括號前的欄位,這個欄位有可能是函式名,或者是判斷條件,或者是強制轉換
  3. 第二個正則表示式用於判斷語句中是否包含控制語句和判斷條件


__author__ = 'Z'
#coding:utf-8
import os
import re
 
keyWordList = [ 'break','continue', 'else', 'for','include', 'if', 'return', 'while','sizeof','int',
                'float','bool','char','switch']
specialCase = ["("]
commentCase =["/*","//"]
 
p =re.compile('(?P<name>\w+)\s*\(')
pControl =re.compile('\s*(for|if|else|switch|case|default|while|do)\s*\(')
 
methodExtractResult = []


第二部分主函式,執行流程如下:

  1. 判斷輸入的原始碼檔案是否存在,路徑合法則逐行讀取;
  2. 判斷該行是否以“/”開頭,是註釋行則跳過該行;
  3. 如果該行包含關鍵字“(”,且排除控制語句,且不以分號結果,則表明該行為函式定義行,提取函式名;
  4. 如果該行包含關鍵字“(”,提取所用“(”前的欄位,與預先定義的關鍵字列表取差集,剩餘欄位則為被呼叫函式;
  5. 去除儲存在列表中重複的被呼叫函式,並寫入日誌中。

def main():
    funName = "Out Of the Function"
    #輸入檔案判斷
    filePath = input("請輸入原始檔路徑: \n")
    while False == os.path.isfile(filePath):
        print("檔案不存在,請檢查")
        filePath = input("請輸入原始檔路徑: \n")

    fd = open(filePath)
    for line in fd:
        line = line.strip().strip('\n')
        if listInString(line[0:2],commentCase):
            #首先排除註釋行
            pass
        elif listInString(line,specialCase) and (controlCaseInString(line) == False):
            #不含控制語句的關鍵字和和分號,且包含關鍵字“(”,判斷為函式定義行,提取函式名
            mMethod = re.search(p,line)
            if mMethod:
                methodName = mMethod.groups("name")
                funName = methodName[0]
        else:
            #line中包含了關鍵字或者分號
            mLineList = re.findall(p,line)
            #list取差集,排除關鍵字
            methodList = list(set(mLineList).difference(set(keyWordList)))
            if methodList:
                for methodInList in methodList:
                    methodExtractResult.append(funName + ":"+ methodInList)
                    #print (funName + ":"+ methodInList)
    logfile = open(os.getcwd() + r'\\' + 'methodExtract.txt','w')
    try:
        #去除重複行
        methodExtractResultWithNoRepeat = []
        for elem in methodExtractResult:
            if elem not in methodExtractResultWithNoRepeat:
                methodExtractResultWithNoRepeat.append(elem)
                print (elem)
                logfile.write(elem + "\n")
    finally:
        logfile.close()
    fd.close()

第三部分為兩個輔助功能函式:

  1. listInString函式實現了判斷列表中的元素是否存在於string中;
  2. controlCaseInString函式實現利用正則判斷sting中是否包含的關鍵欄位。
def listInString(strLine, listJar):
    result = False
    if isinstance(listJar, list):
        for item in listJar:
            if item in strLine:
                result = True
                break
    else:
        result = False
    return  result

def controlCaseInString(strLine):
    if re.search(pControl,strLine) or ";" in strLine:
        return True
    else:return False

使用限制:

  1. 由於程式碼實現的是逐行讀取處理,對於一條語句程式碼被分行書寫的情況,可能會出現意外的錯誤;
  2. 由於註冊函式的使用與變數使用類似,所以註冊函式會被忽略。