IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

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 :

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 :

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) :

461720

Le module complet comprend également une fonction de sortie StopDebug pour afficher le résultat y compris en cas d'erreur :
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,

Vous avez lu gratuitement 18 897 articles depuis plus d'un an.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.

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