ExcludeFunc - Abhängigkeitsprüfung von verschachtelten Funktionen

  • Hallo Community,

    ich möchte ein kleines Skript mit euch teilen welches mir schon oft beim Debuggen von unübersichtlichen Programmcode geholfen hat. Auch lässt es sich wunderbar auf einen >4000 Zeiler anwenden, um dort einfacher abhängige Variablen und Funktionen auslesen zu können.

    Wer kennt das nicht, da schaust dir ein altes Skript an oder Fremdsource und willst wissen wie eine einzelne Funktion aufgebaut ist. Aber durch den ganzen Code Wirr-Warr mußt du dir erstmal einen Überblick über den gesammten Source verschaffen, und das kostet eben Zeit...

    Da kommt die ExcludeFunc() Funktion zur Hilfe, du musst diese Funktion einfach in dem Skript Includen wo sich auch die zu prüfende Funktion befindet - In diesem Beispiel nennen wir diese einfach _BigFunc().
    Jetzt fügst du einfach in deinem Skript einen Befehl zu worin sich die Aufgerufene Funktion befindet: ExcludeFunc("_BigFunc").
    Sobald du dein Skript startest, wird eine neue Datei in @ScriptDir mit dem Funktionsnamen erstellt @Scriptdir & "\_BigFunc.au3".
    Dieses erstellte Skript enthällt die gewünschte Funktion mit allen Includes (C&P aus dem Main-Skript) und allen verwendten globalen Variablen (mit Werten) sowie aufgerufene Funktionen.

    Oft kann dieser Source nicht ausgeführt werden - soll er auch gar nicht! Es ist zum Debuggen einzelner Funktionen gedacht und/oder um sich durch die Abhängikeitsprüfung eine bessere Übersicht verschaffen zu können. Wenn aufgerufene Funktionen oder Variablen aus dem Main-Skript fehlen dann weil sich diese nicht in dessen Datei befinden - Includierte Quellcodes werden nicht ausgewertet sondern einfach eingebunden.

    In Zeile 241 und 242 befinden sich einfache Anwendungsbeispiele, müssen nur De-Kommentiert werden.

    Spoiler anzeigen
    [autoit]

    #Region - Includes -----------------------------------------------------------------------------------------------------------------
    #AutoIt3Wrapper_UseX64=n
    #AutoIt3Wrapper_UseUPX=n

    [/autoit] [autoit][/autoit] [autoit]

    #RequireAdmin
    #include-once
    #include <Array.au3>
    #include <String.au3>

    [/autoit] [autoit][/autoit] [autoit]

    #EndRegion -------------------------------------------------------------------------------------------------------------------------

    [/autoit] [autoit][/autoit] [autoit]

    #cs - ReadMe -----------------------------------------------------------------------------------------------------------------------

    [/autoit] [autoit][/autoit] [autoit]

    AutoIt Version: 3.3.12.0
    Script: ExcludeFunc.au3
    Progammversion: 0.12
    Author: Techmix

    [/autoit] [autoit][/autoit] [autoit]

    Programm Funktion:
    Ich verwende dieses Script um Funktionen aus z.B. unübersichtlichen Skripten incl.
    aller Funktions- und Variablen- Abhängikeiten in ein einzelnes Script zu übertragen.
    Damit lässt sich prima Debuggen und auch der Fokus auf eine Funktion lenken.

    [/autoit] [autoit][/autoit] [autoit]

    Update auf V0.12:
    Tiefenanalyse auch auf verwendete Unterfunktionen ausgedehnt
    Variablenerkennung verbessert

    [/autoit] [autoit][/autoit] [autoit]

    #ce --------------------------------------------------------------------------------------------------------------------------------

    [/autoit] [autoit][/autoit] [autoit]

    Func _ExcludeFunc($sFuncName)
    Local _
    $sFile = @ScriptFullPath, _
    $sFunc = "Func " & $sFuncName&"(" & _StringBetween(FileRead(@ScriptFullPath), "Func " & $sFuncName&"(", "EndFunc"&@CRLF)[0] & @CRLF&"EndFunc", _
    $sSource, _
    $aSourceCode, _
    $sSourceCode, _
    $aFunctions, $aTemp, $aArray, $sTemp, $sChr, $sGlobal, $iSkipFunc, _
    $aIncludes[100], $aIncludedFuncs[100], $aInternFuncs[100], _
    $aVariables[1000], $aGlobalVariables[1000], $iCount=0

    [/autoit] [autoit][/autoit] [autoit]

    ; Includes auslesen
    ; Einfacherweise werden einfach alle #includes ausgelesen
    $sSourceCode = FileRead($sFile)
    $aSourceCode = StringSplit($sSourceCode, @CRLF, 3)
    $aFunctions = StringSplit($sFunc, @CRLF, 3)
    for $i = 0 to UBound($aSourceCode) -1
    if StringLeft(StringLower($aSourceCode[$i]), 8) = "#include" then
    $aIncludes[$iCount] = $aSourceCode[$i]
    $iCount += 1
    EndIf
    Next
    ReDim $aIncludes[$iCount]
    ;~ _ArrayDisplay($aIncludes)

    [/autoit] [autoit][/autoit] [autoit]

    ; Alle aufgerufenen Funktionen innerhalb der Hauptfunktion auslesen
    ; Wird benötigt um die genaue Abhängigkeit der Hauptfunktion zu ermitteln
    $iCount=0
    for $i = 1 to UBound($aFunctions) -1
    if StringInStr($aFunctions[$i], "(") then
    if StringInStr(StringLeft($aFunctions[$i], StringInStr($aFunctions[$i], "(")), ";") then ContinueLoop
    $aTemp = StringRegExp($aFunctions[$i], '(?i)(?<=)[0-9a-zA-Z_]+[ ]*(?=\()', 3) ; Stolen from OrganizeIncludes
    if IsArray($aTemp) = 0 then ContinueLoop
    $aIncludedFuncs[$iCount] = $aTemp[0]
    if $aIncludedFuncs[$iCount] = "" Then ContinueLoop
    $aIncludedFuncs[$iCount] = StringStripWS($aIncludedFuncs[$iCount], 8)
    $iCount += 1
    EndIf
    Next
    ;~ ReDim $aIncludedFuncs[$iCount]
    ;~ _ArrayDisplay($aIncludedFuncs)

    [/autoit] [autoit][/autoit] [autoit]

    ; Alle aufgerufenen Funktionen innerhalb aller Unterfunktionen auslesen
    $i = 0
    Do
    $i += 1
    if $i >= UBound($aIncludedFuncs) Then ExitLoop
    if $aIncludedFuncs[$i] = "" then ContinueLoop
    if StringInStr($sSourceCode, "Func " & $aIncludedFuncs[$i]&"(") = 0 then ContinueLoop
    $sSource = StringSplit(_StringBetween($sSourceCode, "Func " & $aIncludedFuncs[$i]&"(", "EndFunc"&@CRLF)[0], @CRLF, 3) ; Interne Funktion mit @CRLF Splitten
    for $j = 0 to UBound($sSource) -1
    if StringInStr($sSource[$j], "(") then
    if StringInStr(StringLeft($sSource[$j], StringInStr($sSource[$j], "(")), ";") then ContinueLoop
    $aTemp = StringRegExp($sSource[$j], '(?i)(?<=)[0-9a-zA-Z_]+[ ]*(?=\()', 3) ; Stolen from OrganizeIncludes
    if IsArray($aTemp) = 0 then ContinueLoop
    $aIncludedFuncs[$iCount] = $aTemp[0]
    if $aIncludedFuncs[$iCount] = "" Then ContinueLoop
    $aIncludedFuncs[$iCount] = StringStripWS($aIncludedFuncs[$iCount], 8)
    $iCount += 1
    EndIf
    Next
    Until $aIncludedFuncs[$i] = ""
    ReDim $aIncludedFuncs[$iCount]
    $aIncludedFuncs = _ArrayUnique($aIncludedFuncs)
    _ArrayDelete($aIncludedFuncs, 0)
    ;~ _ArrayDisplay($aIncludedFuncs)

    [/autoit] [autoit][/autoit] [autoit]

    ; Prüfen ob sich die gefundenen Funktionen in dem Main-Source befinden
    $iCount=0
    for $i = 0 to UBound($aIncludedFuncs) -1
    if StringInStr($sSourceCode, "Func " & $aIncludedFuncs[$i]&"(") = 0 then ContinueLoop
    $sSource = "Func " & $aIncludedFuncs[$i] & "(" & _StringBetween($sSourceCode, "Func " & $aIncludedFuncs[$i] & "(", "EndFunc"&@CRLF)[0] & "EndFunc"&@CRLF
    $aInternFuncs[$iCount] &= $sSource
    $iCount += 1
    Next
    ReDim $aInternFuncs[$iCount]
    ;~ _ArrayDisplay($aInternFuncs)

    [/autoit] [autoit][/autoit] [autoit]

    ; Variablen sammeln
    $sGlobal = "= ,;"&'"'&"'[])&+*/^-" ; Operatoren und so...
    $iCount=0
    for $x = 0 to 2
    if $x = 0 then
    $aArray = $aFunctions
    Elseif $x = 1 then
    $aArray = $aIncludedFuncs
    Elseif $x = 2 then
    $aArray = $aInternFuncs
    EndIf
    for $i = 1 to UBound($aArray) -1
    for $x = 1 to StringLen($aArray[$i])
    $sChr = StringMid($aArray[$i], $x, 1)
    if StringMid($aArray[$i], $x-2, 3) = ", _" or StringMid($aArray[$i], $x-2, 3) = "& _" then ContinueLoop 2 ; Nächste Zeile
    if $sChr = ";" then ContinueLoop 2 ; ...
    if $sChr = "$" then ; Variablenstart
    $sTemp = ""
    for $y = $x to StringLen($aArray[$i])
    $sChr = StringMid($aArray[$i], $y, 1)
    if StringInStr($sGlobal, $sChr) then
    $x = $y-1
    ExitLoop
    EndIf
    $sTemp &= $sChr
    Next
    $sTemp = StringStripWS($sTemp, 2)
    if _ArraySearch($aVariables, $sTemp) = -1 then
    $aVariables[$iCount] = $sTemp ; Zufügen
    $iCount += 1
    EndIf
    EndIf
    Next
    Next
    Next
    ReDim $aVariables[$iCount]
    ;~ _ArrayDisplay($aVariables)

    [/autoit] [autoit][/autoit] [autoit]

    ; Gefundene Variablen im Main-Source suchen und incl. Werte zuweisen
    ; Alle gefundenen Variablen im Main-Source suchen und bei Erfolg Werte übernehmen
    $iCount=0
    $iSkipFunc=0
    for $i = 0 to UBound($aSourceCode) -1
    if StringLeft(StringLower($aSourceCode[$i]), 4) = "func" then $iSkipFunc = 1 ; Innerhalb von Funktionen keine Variablen suchen
    if StringLeft(StringLower($aSourceCode[$i]), 7) = "endfunc" then $iSkipFunc = 0 ; ...
    if $iSkipFunc = 0 then
    $aSourceCode[$i] = StringReplace($aSourceCode[$i], Chr(9), "")
    for $x = 1 to StringLen($aSourceCode[$i])
    $sChr = StringMid($aSourceCode[$i], $x, 1)
    if StringMid($aSourceCode[$i], $x-2, 3) = ", _" or StringMid($aSourceCode[$i], $x-2, 3) = "& _" then ContinueLoop 2 ; Nächste Zeile
    if $sChr = ";" then ContinueLoop 2 ; ...
    if $sChr = "$" then ; Variablenstart
    $sTemp = ""
    for $y = $x to StringLen($aSourceCode[$i])
    $sChr = StringMid($aSourceCode[$i], $y, 1)
    ;~ if $sChr = "," or StringMid($aSourceCode[$i], $y, 1) & $sChr = " _" or $sChr = ";" Then ; evtl. Variablenende
    if $sChr = "," or StringMid($aSourceCode[$i], $y-2, 3) = ", _" or StringMid($aSourceCode[$i], $y-2, 3) = "& _" or $sChr = ";" Then ; evtl. Variablenende
    $x = $y-1
    ExitLoop
    EndIf
    $sTemp &= $sChr ; Gefundenes erweitern
    Next
    $sTemp = StringStripWS($sTemp, 8)
    for $y = UBound($aVariables)-1 to 0 Step -1 ; Variablen-Array prüfen
    if $aVariables[$y] = (StringInStr($sTemp, "=") ? StringSplit($sTemp, "=")[1] : $sTemp) then ; Wenn eine Zuweisung vorhanden ist "=" dann Splitten
    if _ArraySearch($aGlobalVariables, $sTemp) = -1 then
    $aGlobalVariables[$iCount] = $sTemp ; Variable Zufügen
    _ArrayDelete($aVariables, $y)
    $iCount += 1
    ExitLoop
    EndIf
    EndIf
    Next
    EndIf
    Next
    EndIf
    Next
    if $iCount = 0 Then $iCount = 1
    ReDim $aGlobalVariables[$iCount]
    ;~ _ArrayDisplay($aGlobalVariables)

    [/autoit] [autoit][/autoit] [autoit]

    ; Alles dem Neuen-Source zufügen
    ; Erst Includes, globale Variabeln, Haupfunktion, Unter-Funktionen in einem SourceCode hinterlegen
    $sSource = ""
    for $i = 0 to UBound($aIncludes) -1
    if $aIncludes[$i] <> "" then $sSource &= $aIncludes[$i] & @CRLF
    Next
    $aSourceCode = "; Includes" & @CRLF & $sSource & @CRLF
    if $aGlobalVariables[0] <> "" then
    $sSource = "Global _" & @CRLF
    for $i = 0 to UBound($aGlobalVariables) -1
    if $aGlobalVariables[$i] <> "" then $sSource &= Chr(9) & $aGlobalVariables[$i] & ", _" & @CRLF
    Next
    $aSourceCode &= @CRLF & "; Globale Variablen" & @CRLF & StringTrimRight($sSource, 5) & @CRLF & @CRLF
    EndIf
    $sSource = ""
    for $i = 0 to UBound($aFunctions) -1
    $sSource &= $aFunctions[$i] & @CRLF
    Next
    $aSourceCode &= @CRLF & "; Hauptfunktion" & @CRLF & $sSource & @CRLF
    $sSource = ""
    if UBound($aInternFuncs) >0 then
    for $i = 0 to UBound($aInternFuncs) -1
    $sSource &= $aInternFuncs[$i] & @CRLF
    Next
    $aSourceCode &= @CRLF & "; Unterfunktionen" & @CRLF & $sSource
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ; Datei schreiben
    FileDelete(@ScriptDir&"\"&$sFuncName&".au3")
    FileWrite(@ScriptDir&"\"&$sFuncName&".au3", $aSourceCode)

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ;
    ; Testumgebung...
    Global $sTest, _
    $iTestSingle, _
    $iTestDoubleA1, $iTestDoubleA2, _
    $iTestDoubleB1 = 1,$iTestDoubleB2=2, _
    $iTest = 1,$iTestSingle

    [/autoit] [autoit][/autoit] [autoit]

    ;~ _ExcludeFunc("_ExcludeFunc") ; Abhängikeitsprüfung und Export von '_ExcludeFunc'
    ;~ _ExcludeFunc("_GetFunc") ; Abhängikeitsprüfung und Export von '_GetFunc'
    Func _GetFunc($sFuncName)
    Dim $Test ; Test
    $Test = $iTestSingle
    $Test = $iTestDoubleA1
    $Test = $iTestDoubleA2
    $Test = $iTestDoubleB1
    $Test = $iTestDoubleB2
    $Test = $iTest
    $Test = $iTestSingle
    Return "Func " & $sFuncName&"(" & _StringBetween(FileRead(@ScriptFullPath), "Func " & $sFuncName&"(", "EndFunc"&@CRLF)[0] & @CRLF&"EndFunc"
    EndFunc

    [/autoit]

    Viel Spaß beim Debuggen ;)
    Grüsse!

    [Edit]
    Update auf V0.12:
    Verbesserte Tiefenanlyse, wird jetzt auch bei Unterfunktionen angewendet
    Variablenerkennung optimiert, es werden jetzt mehr abhängige Variablen erkannt
    Weniger Au3Check-Error

    Danke für die bisherigen 20 Downloads!

    5 Mal editiert, zuletzt von Techmix (9. Februar 2015 um 17:30)

  • Super, dann kann ich die Funktion gerade mal bei deinen Update testen.
    Lese mich gerade sowieso noch in deine Änderungen ein. Hehe :D
    Mal schaun, Feedback gibt's später.