Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Déboguer les procédures récursives dans Access ou Excel : apprendre à tracer des appels récursifs en VBA
Par User

Le , par User

0PARTAGES

Il est souvent compliqué de déboguer les procédures récursives, c'est pourquoi je vous propose un jeu de procédures permettant de tracer les différents appels récursifs sous la forme d'une structure d'arbre.

Ce traçage des différents appels numérotés et regroupés par niveau, permet ainsi de mieux visualiser le déroulé de la procédure.
Ce résultat peut être affiché dans la fenêtre d'exécution ou dans un fichier de sortie au format texte.

  • Deux procédures balises BeginSub et EndSub, permettant de délimiter le début et la fin de la procédure.
  • Une procédure PrintDebug pour afficher un message associé à chaque appel, à positionner au bon endroit dans le code de la procédure entre les 2 balises.


Exemple d'écriture dans la fonction récursive Combinaisons :

Code VBA : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Function Combinaisons(x As Long, y As Long) As Long 
    ' Code de la fonction Combinaisons avec les différentes balises 
    On Error GoTo erreur_Combinaisons 
  
    BeginSub 
  
    ' On imprime du texte sur le traçage 
    PrintDebug "(" & x & "," & y & ")" 
  
    If (x = y) Or (y = 0) Then 
        Combinaisons = 1 
    Else 
        If (y = 1) Then 
            Combinaisons = x 
        Else 
            Combinaisons = Combinaisons(x - 1, y - 1) + Combinaisons(x - 1, y) 
        End If 
    End If 
  
    ' On imprime du texte sur le traçage 
    PrintDebug "(Combin(" & x & "," & y & ")=" & Combinaisons & ")" 
  
    EndSub 
  
erreur_Combinaisons: 
  
    If Err.Number <> 0 Then 
        StopDebug ' Gestion de l'erreur : arrêt du traçage 
        On Error GoTo 0 ' Annule la gestion d'erreur 
        Resume ' Retourne sur la ligne qui a déclenché l'erreur 
    End If 
  
End Function


Une procédure InitDebug pour initialiser les paramètres de traçage avant de lancer la procédure à déboguer.

Elle peut prendre en option les arguments :

  • nbCalls : Nombre d'appels total à afficher en sortie ;
  • lgColumn : largeur des colonnes en nombre de caractères ;
  • tpOut : type de sortie (Fenêtre_Execution ou Fichier_Texte).


Exemple de test pour la fonction Combinaisons :

Code VBA : Sélectionner tout
1
2
3
4
5
6
7
Public Function TestCombinaisons(x As Long, y As Long) 
    ' Exemple de test pour la fonction Combinaisons 
  
    InitDebug ' Initialisation des paramètres par défaut 
    Call Combinaisons(x, y) ' Exécution de la fonction 
  
End Function

Résultat pour TestCombinaisons(5,3) :



Le module complet comprend également une fonction de sortie StopDebug pour afficher le résultat y compris en cas d'erreur :
Code VBA : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
Option Explicit 
  
' Module pour tracer les appels récursifs 
' User - 20/03/2019 
  
' Type énumératif pour le type de sortie 
Public Enum TypeSortie 
    Fenetre_Execution = 1 
    Fichier_texte = 2 
End Enum 
  
' Chaîne de caractères contenant le résultat en sortie 
Dim stSortie As String 
  
' Indice de colonne 
Dim idColonne As Long 
Dim flag As Boolean 
  
' Type de sortie 
Dim tpSortie As TypeSortie 
  
Dim nbAppels As Long ' Nombre total d'appels du traçage, si 0 alors on va à la fin de la procédure 
Dim idAppel As Long ' Indice d'appel 
  
' Largeur des colonnes en sortie 
Dim lgColonne As Long 
  
Public Function InitDebug(Optional nbCalls As Long = 0, Optional lgColumn As Long = 15, Optional tpOut As TypeSortie = 1) 
    ' Initialisation des paramètres de traçage ; nbCalls : nombre d'appels ; lgColumn : largeur des colonnes du tableau; 
    ' tpOut : Type de sortie (fenêtre d'exécution, fichier texte) 
  
    idColonne = 0 ' Indice de colonne 
  
    idAppel = 0 ' On inilialise le compteur d'appels 
  
    lgColonne = lgColumn ' Largeur des colonnes en nombre de caractères 
    tpSortie = tpOut ' Type de sortie (fenêtre d'exécution ou fichier texte) 
  
    stSortie = vbNullString ' Chaîne contenant le résultat en sortie 
    nbAppels = nbCalls ' On initialise le nombre d'appels maxi 
    flag = True ' le flag permet de marquer le début et la fin du traçage 
  
End Function 
  
Public Sub BeginSub() 
    ' Marqueur du début dans le code de la procédure 
    idAppel = idAppel + 1 ' On incrémente le compteur d'appels 
  
        ' On affiche en sortie un appel de procédure 
    If idAppel = 1 Then ' Si 1er appel 
        stSortie = String(idColonne * lgColonne, " ") & "Apple n°" & idAppel & "->"  ' On imprime Appel n°1 
    Else ' sinon on imprime Appel n°_ avec un décallage de idColonne 
        stSortie = stSortie & vbNewLine & String(idColonne * lgColonne, " ") & "Apple n°" & idAppel & "->" 
    End If 
  
    idColonne = idColonne + 1 ' On incrémente l'indice de colonne 
  
End Sub 
  
Public Sub EndSub() 
    ' Marqueur de fin dans le code de la procédure 
  
    idColonne = idColonne - 1 ' On remonte les appels 
  
    If flag Then 
  
        If (idColonne = 0) Then   ' si traçage complet terminé 
            flag = False ' indicateur de fin de traçage 
            StopDebug ' procédure d'arrêt du traçage 
        Else 
            If ((idAppel >= nbAppels) And (nbAppels > 0)) Then ' si nombre d'appels demandés dépassé 
                flag = False ' indicateur de fin de traçage 
                StopDebug ' procédure d'arrêt du traçage 
            End If 
        End If 
  
    End If 
  
End Sub 
  
Sub PrintDebug(s As String) 
    'Ajoute dans la chaîne de sortie le contenu du texte à afficher sur la bonne colonne 
    stSortie = stSortie & vbNewLine & String(idColonne * lgColonne, " ") & s ' La fonction String permet de décaller le texte 
  
End Sub 
  
  
Public Function Factorielle(n As Long) As Long 
    On Error GoTo erreur_Factorielle 
    BeginSub ' Marqueur de début de procédure 
  
    ' On imprime du texte sur le traçage 
    PrintDebug "(n=" & n & ")" 
  
    If n = 0 Then 
        Factorielle = 1 
    Else 
        Factorielle = n * Factorielle(n - 1) 
    End If 
  
    ' On imprime du texte sur le traçage 
    PrintDebug "(Fact(" & n & ")=" & CStr(Factorielle) & ")" 
  
    EndSub ' Marqueur de fin de procédure 
  
erreur_Factorielle: 
  
    If Err.Number <> 0 Then 
        StopDebug ' Gestion de l'erreur : arrêt du traçage 
        On Error GoTo 0 ' Annule la gestion d'erreur 
        Resume ' Retourne sur la ligne qui a déclenché l'erreur 
    End If 
  
End Function 
  
Function Fibonacci(n As Long) As Long 
    ' Code de la fonction Fibonacci avec les différentes balises 
    On Error GoTo erreur_Fibonacci 
  
    BeginSub 
  
    ' On imprime du texte sur le traçage 
    PrintDebug "(n=" & n & ")" 
  
    If (n = 0) Then 
            Fibonacci = 0 
    Else 
        If (n = 1) Then 
            Fibonacci = 1 
        Else 
            Fibonacci = Fibonacci(n - 2) + Fibonacci(n - 1) 
        End If 
    End If 
  
    ' On imprime du texte sur le traçage 
    PrintDebug "(Fibo(" & n & ")=" & Fibonacci & ")" 
  
    EndSub ' Marquage de fin de la procédure 
  
erreur_Fibonacci: 
  
    If Err.Number <> 0 Then 
        StopDebug ' Gestion de l'erreur : arrêt du traçage 
        On Error GoTo 0 ' Annule la gestion d'erreur 
        Resume ' Retourne sur la ligne qui a déclenché l'erreur 
    End If 
  
End Function 
  
Function Combinaisons(x As Long, y As Long) As Long 
    ' Code de la fonction Combinaisons avec les différentes balises 
    On Error GoTo erreur_Combinaisons 
  
    BeginSub 
  
    ' On imprime du texte sur le traçage 
    PrintDebug "(" & x & "," & y & ")" 
  
    If (x = y) Or (y = 0) Then 
        Combinaisons = 1 
    Else 
        If (y = 1) Then 
            Combinaisons = x 
        Else 
            Combinaisons = Combinaisons(x - 1, y - 1) + Combinaisons(x - 1, y) 
        End If 
    End If 
  
    ' On imprime du texte sur le traçage 
    PrintDebug "(Combin(" & x & "," & y & ")=" & Combinaisons & ")" 
  
    EndSub 
  
erreur_Combinaisons: 
  
    If Err.Number <> 0 Then 
        StopDebug ' Gestion de l'erreur : arrêt du traçage 
        On Error GoTo 0 ' Annule la gestion d'erreur 
        Resume ' Retourne sur la ligne qui a déclenché l'erreur 
    End If 
  
End Function 
  
Public Function TestFactorielle(n As Long) 
    ' Exemple de test pour la fonction Factorielle 
  
    InitDebug ' Initialisation des paramètres par défaut 
    Call Factorielle(n) ' Exécution de la fonction 
  
End Function 
  
Public Function TestFibonacci(n As Long) 
    ' Exemple de test pour la fonction de Fibonacci 
  
    InitDebug , 20, Fichier_texte ' Initialisation des paramètres 
    Call Fibonacci(n) ' Exécution de la fonction 
  
End Function 
  
Public Function TestCombinaisons(x As Long, y As Long) 
    ' Exemple de test pour la fonction Combinaisons 
  
    InitDebug , , Fichier_texte ' Initialisation des paramètres par défaut 
    Call Combinaisons(x, y) ' Exécution de la fonction 
  
End Function 
  
Public Sub CreateTextFile(chemin, s As String) 
    ' Procédure de création du fichier texte 
    Open chemin For Output As #1 
    Print #1, s 
    Close #1 
End Sub 
  
Public Sub StopDebug() 
    ' Procédure d'arrêt du traçage 
    Dim chemin As String 
  
    If (tpSortie = Fenetre_Execution) Then ' Si la sortie se fait dans la fenête d'exécution 
        Debug.Print stSortie 
    Else 
        If (tpSortie = Fichier_texte) Then 
            chemin = CurDir & "\Sortie.txt" 
            CreateTextFile chemin, stSortie ' Création du fichier Texte 
            Call Shell("notepad.exe """ & chemin & """", vbNormalFocus) ' Ouverture du fichier avec notepad 
        End If 
    End If 
  
    if (nbAppels > 0) And Not (flag) Then ' Si un nombre appels limité a été demandé ou si on est pas sorti sur une erreur 
        End ' stop la procédure principale et initialise les variables 
    End If 
  
End Sub

Il peut-être copié puis collé dans un fichier Excel ou Access. Il ne contient pas de référence externe, la structure d'arbre étant simplement copiée dans une chaîne de caractères ou dans un fichier texte.
Attention à ne pas passer un argument trop élevé pour les fonctions récursives qui pourrait provoquer des empilements d'appels trop importants en mémoire.


Voilà, j'ai trouvé l'idée intéressante

Bons tests,
Cordialement,

Une erreur dans cette actualité ? Signalez-le nous !