2016-11-05 40 views
2

考慮到一些VBA代碼(存儲在文本文件中)根據條件調用規則,我想解析代碼並創建所有代碼的小代碼片段需要知道生成該規則(以更容易理解規則的本質)。使用Python將VBA代碼解析爲較小的代碼片段

我開始嘗試在Python中將一些規則正則表達,但如果它存在,不想重新創建輪子。我知道像Retrieving JSON objects from a text file (using Python)這樣的例子來覆蓋基類來創建客戶解析器。我不確定是否有最適合這種情況的包,並且沒有找到任何運氣。

背景是,有〜5000分的規則,我要「縮水」這樣的,更簡單地說明圍繞規則的邏輯,看東西有多少規則由某個變量的影響等

輸入:

Sub One(position As Long)  
    Dim y As Long  
    With TEMP_ARRAY(position) 
     'Comments 
     If .VAR_A = "A" And .VAR_B = "B" And .VAR_C = "C" Then 
      Call Some_Rule("Rule 1") 
     End If 

     'More Comments 
     If IsEmpty(.SUB_ARRAY) Then 
      Call Some_Rule("Rule 2") 
     Else 
      If .VAR_A = 2 Then 
       If .VAR_B <> "" Then 
        'Some more comments 
        For y = 0 To UBound(.SUB_ARRAY) 
         If .SUB_ARRAY(y, 2) = 1 Or .SUB_ARRAY(y, 2) = 2 Then Exit For 
        Next y 
        If y = UBound(.SUB_ARRAY, 1) + 1 Then 
         Call Some_Rule("Rule 3") 
        End If 
       Else 
        'Still more comments 
        Select Case .SUB_ARRAY(0, 2) 
         Case 3 
          Call Some_Rule("Rule 4") 
         Case 4 
          Call Some_Rule("Rule 5") 
        End Select 
       End If 
      End If 
     End If 
    End With 
End Sub 

所需的輸出:

## RULE 1 
Sub One(position As Long) 
    With TEMP_ARRAY(position) 
     'Comments 
     If .VAR_A = "A" And .VAR_B = "B" And .VAR_C = "C" Then 
      Call Some_Rule("Rule 1") 
     End If 
    End With 
End Sub 

## RULE 2 
Sub One(position As Long) 
    With TEMP_ARRAY(position) 
     'More Comments 
     If IsEmpty(.SUB_ARRAY) Then 
      Call Some_Rule("Rule 2") 
     End If 
    End With 
End Sub 

## RULE 3 
Sub One(position As Long) 
    Dim y As Long 
    With TEMP_ARRAY(position) 
     'More Comments 
     If IsEmpty(.SUB_ARRAY) Then 
     Else 
      If .VAR_A = 2 Then 
       If .VAR_B <> "" Then 
        'Some more comments 
        For y = 0 To UBound(.SUB_ARRAY) 
         If .SUB_ARRAY(y, 2) = 1 Or .SUB_ARRAY(y, 2) = 2 Then Exit For 
        Next y 
        If y = UBound(.SUB_ARRAY, 1) + 1 Then 
         Call Some_Rule("Rule 3") 
        End If 
       End If 
      End If 
     End If 
    End With 
End Sub 

## RULE 4 
Sub One(position As Long) 
    With TEMP_ARRAY(position) 
     'More Comments 
     If IsEmpty(.SUB_ARRAY) Then 
     Else 
      If .VAR_A = 2 Then 
       If .VAR_B <> "" Then 
       Else 
        'Still more comments 
        Select Case .SUB_ARRAY(0, 2) 
         Case 3 
          Call Some_Rule("Rule 4") 
        End Select 
       End If 
      End If 
     End If 
    End With 
End Sub 

## RULE 5 
Sub One(position As Long) 
    With TEMP_ARRAY(position) 
     'More Comments 
     If IsEmpty(.SUB_ARRAY) Then 
     Else 
      If .VAR_A = 2 Then 
       If .VAR_B <> "" Then 
       Else 
        'Still more comments 
        Select Case .SUB_ARRAY(0, 2) 
         Case 4 
          Call Some_Rule("Rule 5") 
        End Select 
       End If 
      End If 
     End If 
    End With 
End Sub 

編輯:這是我迄今爲止所做的(更多代碼,但這是它的核心)。基本上,找到一個以「Some_Rule」開始的行(使用正則表達式),然後從向上的方向調用該函數。當它找到一個開放的標籤時,它會改變方向並開始尋找它的結束標籤,然後選擇它離開的地方再次上升等。我成功地獲得規則1,然後是凌晨4點,所以我去睡覺:) ......我在周圍扔東西在這一點所以還真馬虎,但是想如果你的VBA代碼編寫最Excel的代碼似乎要寫入的方式,例如,快意恩仇我的進步

def compile_rule(lines, j, direction, statement_open=False): 
    """ 
    lines   : total lines in file 
    j    : current position 
    direction  : 1 is up, -1 is down 
    statement_open : vba syntax not yet closed ex: if without end if 
    """ 
    global rule 
    j -= direction 
    if line_type(lines[j]) in [0, 3] and not statement_open: 
     rule.append(lines[j], j, direction) 
    elif line_type(lines[j]) == 1 and not statement_open: 
     rule.append(lines[j], j, direction) 
     rule.start_looking_for(line_check(lines[j])) 
     statement_open = True 
     direction *= -1 
    elif line_type(lines[j]) == 2 and rule.looking_for() == line_check(lines[j]) and statement_open: 
     rule.append(lines[j], j, direction) 
     statement_open = False 
     direction *= -1 
    else: 
     rule.set_position(j, direction) 
    if (j > 0 and j < len(lines) - 1) or (j == 0 and statement_open): 
     compile_rule(lines, rule.get_position(direction), direction, statement_open) 
+0

所以你有1個規則通過黑客工作,與4999去? –

+0

爲什麼「Python」是問題的根本部分? –

+0

沒有理由 - 認爲可能有一些更簡單的Python解析器可用。規則將(可能/最終)從VBA轉移到Python,以便具有Python體驗的數據分析師可以維護規則。認爲如果規則是獨立的,它可能使移動更容易 - 這不是要求,所以不打算花太多時間在它上面。 – NikT

回答

1

更新,您將無法依賴現有的VBA代碼來創建任何漂亮,整潔,易於解碼的結構。如果它不是很一致,那麼你就沒有機會使用基於ad hoc/regex的技術。

在這種情況下,您需要一個完整的VBA解析器,而不是一個不好的近似值。你不能用正則表達式寫一個像樣的解析器(衆所周知的事實)。如果您使用更合理的解析技術,那麼定義語法很困難,因爲文檔記錄很差。

這裏的教訓是你可能不想嘗試編寫你自己的解析器。你最好找到一個有效的,並使用它。我懷疑你會發現很容易找到一個,更不用說碰巧在Python中的一個;但我可能是錯的。

我公司發生在 have such a parser for VB6之間(它本質上是VBA),它建立在我們的DMS Software Reengineering Toolkit之上。此解析器已經在數百萬行代碼中進行了測試。它自動地 構建代表程序的抽象語法樹。

做你想做的事,你必須什麼:

  • 分析源代碼
  • 查找規則調用
  • 發現從功能控制流路開始到規則調用
  • 構成沿着該路徑的條件

鑑於VBA具有goto語句(您的示例代碼沒有,b ut 5000個實例看起來像是一個非常糟糕的賭注),您將需要構建代碼的控制流圖,以便您可以沿其導航以查找從函數輸入到規則調用的路徑。 DMS支持在代碼中查找模式,構建控制和數據流圖,沿着流程圖行走,以及從原始代碼的子樹中編寫有效的程序塊。你很可能需要所有這些。 [根據你的例子,這些例子看起來都是有效的VBA子例程,而不僅僅是條件的一部分,看起來你想從每個規則調用中計算backward slices。這需要我上面描述的所有機器。]

這不是一個心靈的任務,也不是一個週末的練習。但它很可能是可行的。

鑑於您的目標隱約可以「讓它們更具可讀性」,您可能無法證明工程設計的正確性。

如果你堅持臨時性的方法,你可能不會完成,你可能會發現,如果你得到它們,你的「更具可讀性」的規則版本不是真實的事實和你的讀者會起反抗。沒有人想浪費時間閱讀可能錯誤的東西。