Section courante

A propos

Section administrative du site

Procédures et fonctions

Les structures de contrôle de QuickPascal permet de déterminer précisément les instructions que vous souhaitez que votre programme exécute. Ces instructions étaient écrites sous forme de blocs de code apparaissant généralement sous forme d'instructions composées délimitées par les mots clefs BEGIN et END.

Un programme doit souvent exécuter plusieurs fois le même ensemble d'instructions. Plutôt que de vous obliger à répéter ces instructions à plusieurs endroits dans le programme, le QuickPascal vous permet de séparer le code couramment exécuté dans un module autonome. Vous pouvez ensuite exécuter ce code en référençant le nom du module dans le corps du programme. Il existe deux types de modules dans QuickPascal : les procédures et les fonctions. Une procédure est simplement un sous-programme exécutant un ensemble d'instructions. Une fonction est un sous-programme calculant puis renvoie une valeur.

Le QuickPascal contient plus de 300 procédures et fonctions à votre disposition immédiatement. Par exemple, la procédure intégrée WriteLn de QuickPascal contient toutes les instructions pour afficher les données à l'écran. Étant donné que ces instructions sont entreposées sous forme de procédure, il n'est pas nécessaire de les répéter chaque fois que vous souhaitez effectuer une opération d'affichage à l'écran. Au lieu de cela, les instructions de la procédure sont commodément conservées dans l'entreposage, mais restent disponibles chaque fois que le nom WriteLn apparaît dans votre code.

Ces procédures et fonctions intégrées résolvent de nombreux problèmes de programmation. Pourtant, aussi exhaustive que puisse paraître les 300 procédures et fonctions du QuickPascal, il y aura des moments où vous aurez besoin de procédures et de fonctions de votre propre conception.

Procédures

Une procédure est une forme spéciale d'instruction QuickPascal. En d'autres termes, vous pouvez exécuter une procédure (ou plus correctement, vous pouvez exécuter le code dans la procédure) simplement en indiquant le nom de la procédure et en lui fournissant tous les éléments de données - appelés paramètres - dont elle a besoin pour faire son travail. Voici quelques exemples d'appels de procédure proposé par le QuickPascal :

  1. ClrScr;               { Efface l'écran }
  2. Dispose(PVar);        { Efface les données du tas }
  3. Rename(FVar,NewName); { Renomme un fichier disque }
  4. Insert(S1,S2,S3);     { Insère S2 dans S1, en commençant à S3 }

Remarquez comment chacune de ces procédures attend un nombre différent de paramètres. Les procédures ClrScr, Dispose, Rename et Insert nécessitent respectivement zéro, un, deux et trois paramètres. Chacun des paramètres que vous utilisez doit être de type compatible avec les paramètres que la procédure est conçue pour traiter. (Par exemple, vous ne pouvez pas utiliser une valeur réelle dans un paramètre attendant un entier.) La page Référence des procédures et fonctions explique la syntaxe complète de chaque procédure prédéfinie QuickPascal. Consultez-le chaque fois que vous le souhaitez ou utilisez une procédure inconnue.

Certaines des procédures prédéfinies de QuickPascal ont plus d'une forme standard. Par exemple, les procédures RunError et Halt peuvent nécessiter ou non un paramètre. De même, les procédures Inc et Dec peuvent prendre un ou deux paramètres, selon votre application spécifique. Vous avez sans doute remarqué que les procédures Read, ReadLn, Write et WriteLn n'ont aucune restriction sur le nombre de paramètres. Malgré ces exceptions, toutes les procédures que vous définissez doivent avoir un nombre fixe de paramètres.

Un exemple de procédure

Dans sa forme la plus simple, une procédure est une collection d'instructions que vous souhaitez exécuter comme une seule unité. Considérez le code suivant d'un programme d'écriture de rapports :

  1. If CompteurLigne >= MaximumLigne Then Begin
  2.  ClrScr; { Efface l'écran}
  3.  WriteLn('Echantillion Gladir.com');
  4.  WriteLn('Démonstration');
  5.  WriteLn('-----------------------');
  6.  WriteLn;
  7.  CompteurLigne:=4;
  8. End;

Ici, si la variable CompteurLigne atteint MaximumLigne, l'instruction composée suivant le mot clef THEN est exécutée. Étant donné que l'instruction composée est en fait un module de code, vous pouvez réécrire ces instructions sous la forme d'une procédure :

  1. Procedure NouvelleEcran;Begin
  2.  ClrScr; { Efface l'écran}
  3.  WriteLn('Échantillon Gladir.com');
  4.  WriteLn('Démonstration');
  5.  WriteLn('-----------------------');
  6.  WriteLn;
  7.  CompteurLigne:=4; 
  8. ENd;

Ensuite, vous pouvez modifier l'instruction IF elle-même, comme suit :

  1. If CompteurLigne >= MaximumLigne Then NouvelleEcran;

Maintenant si les variables CompteurLigne atteignent MaximumLigne, la procédure NouvelleEcran est exécutée. Le résultat final est le même. Chaque fois que vous appelez une procédure, vous demandez à QuickPascal de modifier le déroulement de votre programme au début de cette sous-routine. Lorsque la sous-routine se termine, le QuickPascal rend le contrôle à la ligne suivante suivant celle qui a appelé la procédure.

Déclarer une procédure

Comme vous venez de le voir, le code contenu dans une procédure est souvent un extrait du corps principal du programme. En fait, les procédures sont presque identiques dans leur structure à un programme QuickPascal complet. (C'est pourquoi les procédures et les fonctions sont souvent appelées sous-programmes.) La syntaxe suivante montre le format général d'une déclaration de procédure QuickPacal :

PROCEDURE NomProcedure(ParameterOptionnel);
LABEL
 (DeclarationOptionnelEtiquetteLocal)
CONST
 (DeclarationOptionnelConstanteLocal)
TYPE
 (DeclarationOptionnelTypeLocal)
VAR
 (DeclarationOptionnelVariableLocal)

( Déclarations de n'importe quel procédure ou fonctions utilisé exclusivement par la procédure courante )

BEGIN
 ( CorpsDeLaProcedure )
END;

Premièrement, le programme commence par le mot clef PROGRAM tandis que la procédure commence par le mot clef PROCEDURE. Deuxièmement, le programme se termine par un point tandis que la procédure se termine par un point-virgule. En fait, les programmes et les procédures doivent avoir des structures similaires. Un programme peut invoquer une procédure ; de plus, toute procédure donnée peut elle-même invoquer d'autres procédures et fonctions.

Une fois qu'une procédure est définie, vous pouvez l'utiliser comme n'importe quelle procédure prédéfinie de QuickPascal. En écrivant la routine, vous avez, en effet, temporairement étendu le langage de programmation QuickPascal.

Fonctions

Comme une procédure, une fonction est une collection d'instructions que vous exécutez comme une seule unité. Cependant, le but d'une fonction est de retourner une valeur. Par conséquent, plutôt que d'écrire le nom d'une fonction dans une instruction séparée, vous pouvez utiliser le nom de la fonction dans une expression comme s'il s'agissait du nom d'une variable. Voici quelques exemples d'appels de fonction de QuickPascal :

  1. Diametre := 2.0 * Radius * Pi; { Pi = 3.14159... }
  2. Racine := Sqrt(2.0);           { Racine carré }
  3. Couleur := GetPixel(X,Y);      { Affiche la couleur }

Là encore, il y a des fonctions attendant un nombre différent de paramètres. Les fonctions Pi, Sqrt et GetPixel nécessitent respectivement zéro, un et deux paramètres. De plus, comme précédemment, chacun des paramètres doit être de type compatible avec les paramètres que la fonction est conçue pour traiter. Pour la syntaxe complète de toutes les fonctions prédéfinies de QuickPascal, reportez-vous à la page Référence des procédures et fonctions.

Certaines des fonctions prédéfinies de QuickPascal ont plus d'une forme standard. En particulier, les fonctions Eof et Random peuvent ou non nécessiter un paramètre, selon votre application spécifique. Malgré ces exceptions, toutes les fonctions que vous définissez doivent avoir un nombre fixe de paramètres.

Déclarer une fonction

La syntaxe suivante illustre le format général d'une déclaration de fonction QuickPascal :

FUNCTION NomFonction(ParameterOptionnel):TypeDonnesFonction;
LABEL
 (DeclarationOptionnelEtiquetteLocal)
CONST
 (DeclarationOptionnelConstanteLocal)
TYPE
 (DeclarationOptionnelTypeLocal)
VAR
 (DeclarationOptionnelVariableLocal)

( Déclarations de n'importe quel procédure ou fonctions utilisé exclusivement pour la fonction courante )

BEGIN
 ( CorpsDeLaFonction )
 NomFonction:=ValeurFonction; { Au moins une affectation doit être faite au nom de la fonction }
END;

Ce format est similaire à celui d'une procédure, mais il existe trois différences majeures. Premièrement, le mot clef FUNCTION est utilisé dans l'entête au lieu du mot clef PROCEDURE. Deuxièmement, le nom de la fonction prend une valeur lorsque la fonction se termine. Afin d'établir cette valeur, vous devez effectuer au moins une affectation au nom de la fonction dans le corps de la fonction elle-même. Si vous effectuez plusieurs affectations, la dernière affectation s'exécutant détermine la valeur de la fonction. Troisièmement, puisque le nom de la fonction suppose une valeur, la fonction elle-même doit avoir un type. Ce type est défini à la fin de l'entête de la fonction.

Un exemple de fonction

La fonction UpCase est l'une des nombreuses fonctions intégrées de QuickPascal. Il prend un caractère comme seul paramètre. Si le paramètre est une lettre minuscule, UpCase convertit le caractère en majuscule ; sinon, il renvoie le paramètre d'origine.

Supposons que vous souhaitiez développer une fonction LowerCase pour renvoyer l'équivalent en minuscule d'une lettre majuscule, mais laissez tout autre paramètre inchangé. Voici une façon d'y parvenir :

  1. Function LowerCase(C:Char):Char;Begin
  2.  If C IN ['A'..'Z']Then LowerCase:=Chr(Ord(C)+32)
  3.                    Else LowerCase:=C;
  4. End;

Vous pouvez maintenant utiliser la fonction LowerCase partout où vous pourriez utiliser une variable du même type. Le programme suivant est un exemple de la fonction :

  1. Program Deflatat;
  2. Var
  3.  Analyse:String;
  4.  I:Byte;
  5.  
  6. Function LowerCase(C:Char):Char;Begin
  7.  If C IN ['A'..'Z']Then LowerCase:=Chr(Ord(C)+32)
  8.                    Else LowerCase:=C;
  9. End;
  10.  
  11. BEGIN
  12.  WriteLN('Entrez quelques textes :');
  13.  ReadLn(Analyse);
  14.  For I:=1 to Length(Analyse)do Write(LowerCase(Analyse[I]));
  15.  WriteLn;
  16. END.

Lorsque le programme Deflatat s'exécute, il vous invite à entrer une ligne de caractères. Votre message est alors renvoyé à l'écran tel qu'il a été saisi - sauf que tous les caractères majuscules seront affichés en minuscules.

Paramètres de passage

La plupart des sous-programmes utilisent des paramètres. Souvent, les paramètres transmettent simplement les informations dont le sous-programme a besoin. Cependant, les paramètres eux-mêmes doivent parfois être modifiés. Le QuickPascal prend en charge ces deux actions.

Passer des paramètres par valeur

Dans le programme suivant, la fonction LargeurDe renvoie (comme vous vous en doutez peut-être) le plus grand de deux entiers positifs :

  1. Program GrosPrem;
  2.  
  3. Var
  4.  V1,V2:Word;
  5.  
  6. Function LargeurDe(Premier,Deuxieme:Word):Word;Begin
  7.  If Premier > Deuxieme Then LargeurDe:=Premier
  8.                        Else LargeurDe:=Deuxieme;
  9. End;
  10.  
  11. BEGIN
  12.  V1:=16;
  13.  V2:=74;
  14.  WriteLn(LargeurDe(V1,V2));
  15. END.

Tous les paramètres déclarés dans un entête de sous-programme sont appelés paramètres formels. Le programme précédent contient deux paramètres formels : Premier et Deuxieme. Les paramètres formels sont locaux au sous-programme. Cela signifie qu'ils définissent simplement le traitement à effectuer. Aucun espace d'entreposage réel ne leur est alloué en mémoire.

Lorsque vous appelez le sous-programme, les paramètres actuels à envoyer au sous-programme (ici, V1 et V2) sont copiés dans une zone spéciale de la mémoire du compatible IBM PC appelée la pile. Lorsque le sous-programme s'exécute, seules les copies des paramètres sont accessibles. Comme les paramètres réels ne peuvent pas être atteints, ils ne peuvent pas non plus être modifiés. Par conséquent, un paramètre de valeur peut être une variable, une constante ou une expression. La seule restriction est que le type de données des paramètres de valeur doit correspondre au type de données du paramètre formel correspondant.

Passage de paramètres par référence

Si vous souhaitez que votre sous-programme accède à un paramètre réel au lieu de sa copie sur la pile, faites simplement précéder sa déclaration formelle du mot clef VAR. Ensuite, lorsque le sous-programme s'exécute, chaque utilisation du paramètre fait automatiquement référence à la variable réel. Voici une procédure modifiant un de ses paramètres :

  1. Procedure MonterEnPuissance(Var ElementDonnee:Real;Elever:Real);Begin
  2.  ElementDonnee:=ElementDonnee+Elever; 
  3. End;

La procédure MonterEnPuissance fonctionne de manière similaire à la procédure Inc, sauf que MonterEnPuissance opère sur des nombres réels au lieu de valeurs ordinales. Remarquez comment le mot clef VAR précède le paramètre ElementDonnee, mais pas le paramètre Elever. De ce fait, toute variable passée en premier paramètre à la procédure sera incrémentée de la valeur du second paramètre. Cependant, le deuxième paramètre lui-même ne sera pas modifié. Une utilisation typique de la procédure MonterEnPuissance est la suivante :

  1. Nombre:=12.0;
  2. MonterEnPuissance(Nombre,5.0);
  3. WriteLn(Nombre);

Après l'exécution de ces instructions, le nombre 18.0 s'affichera à l'écran. Notez que lorsque vous passez un paramètre par référence, vous devez passer une variable plutôt qu'une constante ou une valeur.

Les règles de portée

Comme vous l'avez vu, les programmes peuvent avoir des sous-programmes, et ces sous-programmes, à leur tour, peuvent avoir des sous-programmes. Chaque procédure et fonction est dite imbriquée dans le bloc l'entourant et la définissant. Il n'y a pas de limite supérieure au nombre de niveaux d'imbrication autorisés par le QuickPascal.

Lorsque vous passez des paramètres par valeur, une sous-routine ne peut accéder qu'aux copies des paramètres sur la pile ; les paramètres actuels eux-mêmes ne peuvent pas être touchés.

De même, QuickPascal crée un entreposage temporaire pour toutes les étiquettes, constantes, types et variables que la sous-routine elle-même définit. Étant donné que les données définies par un sous-programme n'existent que lorsque le sous-programme est en cours d'exécution, ces données ne sont accessibles qu'au sein du sous-programme lui-même et sont librement disponibles pour tous les sous-programmes imbriqués. Cependant, aucun sous-programme parent ne peut accéder aux données déclarées par un sous-programme s'y imbriquant. Cette limitation est appelée la portée d'un identificateur. De même, un sous-programme imbriqué ne peut être utilisé que par le parent le définissant. Cette limitation est appelée la portée d'un sous-programme.

Variables globales et locales

Tous les identificateurs définis dans un bloc englobant sont appelés globaux, et tous les identificateurs définis dans le sous-programme englobant sont dits locaux à la procédure ou à la fonction. Le programme suivant utilise trois niveaux d'imbrication :

  1. Program Imbrique;
  2. {**************************************************}
  3. {*** PREMIER NIVEAU *******************************}
  4. {**************************************************}
  5. {:}                                              {:}
  6. {:} Function Sommaire(A,B:Word):Word;            {:}
  7. {:} {*****************************************}  {:}
  8. {:} {*** DEUXIEME NIVEAU *********************}  {:}
  9. {:} {*****************************************}  {:}
  10. {:} {:} Function Un(C,D:Word):Word;         {:}  {:}
  11. {:} {:} {*******************************}   {:}  {:}
  12. {:} {:} {*** TROISIEME NIVEAU **********}   {:}  {:}
  13. {:} {:} {*******************************}   {:}  {:}
  14. {:} {:} {:} Function Deux:Word;Begin  {:}   {:}  {:}
  15. {:} {:} {:} Deux:=C+D;                {:}   {:}  {:}
  16. {:} {:} {:} End;                      {:}   {:}  {:}
  17. {:} {:} {-------------------------------}   {:}  {:}
  18. {:} {:} Begin                               {:}  {:}
  19. {:} {:}  Un:=Deux;                          {:}  {:}
  20. {:} {:} End;                                {:}  {:}
  21. {:} {-----------------------------------------}  {:}
  22. {:}                                              {:}
  23. {:} Begin                                        {:}
  24. {:}  Sommaire:=Un(A,B);                          {:}
  25. {:} End;                                         {:}
  26. {--------------------------------------------------}
  27.  
  28. BEGIN
  29.  WriteLn(Sommaire(12,13));
  30. END.

Dans cet exemple, la fonction Sommaire définit la fonction Un, qui à son tour définit la fonction Deux. Deux n'est disponible que pour Un, et Un n'est disponible que pour Sommaire.

En appliquant les règles de portée, un programme QuickPascal n'utilise la mémoire que tant que l'élément de données est réellement nécessaire. Vous devez exploiter cette fonctionnalité et définir les données au niveau le plus bas possible. Après tout, si un élément de données n'est utilisé que dans un seul sous-programme, il n'est pas nécessaire de définir les données globalement.

Quitter un sous-programme

Vous pouvez utiliser la procédure Exit pour terminer immédiatement la procédure ou la fonction en cours.

  1. Function Ratio(Numerator,Denominator:Real);Begin
  2.  Ratio:=0.0;
  3.  If Denominator=0.0 Then Exit { Termine maintenant }
  4.                     Else Ratio:=Numerator/Denominator;
  5. End;

Notez qu'avant que la routine Exit ne puisse être appelée, une valeur de retour par défaut avait déjà été affectée.

Récursivité

Chaque fois que votre programme appelle une procédure ou une fonction, une zone d'entreposage de mémoire temporaire est créée pour toutes les données déclarées par la sous-routine. Ces données seront conservées tant que le sous-programme continuera à s'exécuter.

Si un sous-programme s'appelle lui-même (c'est-à-dire si un sous-programme utilise son propre nom avec son code), une zone d'entreposage de mémoire entièrement nouvelle est créée, complètement indépendante de l'original. Si la routine appelée s'appelle à nouveau, une troisième zone mémoire est partitionnée.

De toute évidence, un sous-programme continuant à s'appeler finira par consommer toute la mémoire inutilisée du compatible IBM PC, provoquant l'arrêt du programme avec une erreur d'exécution (techniquement appelée débordement de pile). Cependant, vous pouvez concevoir de nombreuses sous-routines auto-invoquantes ou récursives pour résoudre une variété de problèmes pouvant naturellement être exprimés en termes récursifs. En particulier, les sous-programmes récursifs sont souvent utilisés pour résoudre des problèmes impliquant des séquences de nombres, dans lesquels chaque nombre est calculé à partir d'une ou plusieurs valeurs précédentes.

Par exemple, supposons que vous souhaitiez calculer la somme d'une série d'entiers, de Lower à Upper. Algébriquement, vous pouvez exprimer ce total avec la formule suivante :

AddUp(Lower,Upper)=Upper+(Upper-1)+...+Lower

Voici une version récursive de cette formule :

SI Upper EST Lower ALORS
   AddUp(Lower,Upper)=Lower
SINON
   AddUp(Lower,Upper)=Upper+AddUp(Lower,Upper-1)
FIN SI

La version récursive se traduit directement dans la fonction suivante :

  1. Function AddUp(Lower,Upper:Word):Word;Begin
  2.  If Lower=Upper Then AddUp:=Lower
  3.                 Else AddUp:=Upper+AddUp(Lower,Upper-1)
  4. End;

Bien que la récursivité soit autorisée dans QuickPascal, ce n'est pas une technique de programmation structurée valide. C'est tout aussi bien, car pour chaque technique récursive que vous pouvez concevoir, il existe une approche non récursive. Par exemple, vous pouvez réécrire la fonction AddUp sous la forme d'une formule explicite :

  1. Function AddUp(Lower,Upper:Word):Word;Begin
  2.  AddUp:=(Upper*(Upper+1)-Lower*(Lower+1)) div 2;
  3. End;

Comme vous pouvez le voir, l'approche récursive est beaucoup moins efficace. Bien que la récursivité soit une technique de programmation populaire, vous devriez essayer de l'éviter autant que possible.

Déclarations Forward

Dans la dernière section, vous avez appris que vous pouvez écrire une sous-routine récursive s'appellant directement elle-même. Le QuickPascal vous permet également d'appeler un sous-programme indirectement. Dans un appel indirect, un sous-programme en appelle un autre, et le deuxième sous-programme appelle alors le premier.

Cependant, l'une des règles cardinales de QuickPascal est que chaque élément de données - y compris chaque procédure et fonction - doit être déclaré avant de pouvoir y accéder. Dans le cas d'une récursivité mutuelle, l'un des sous-programmes doit référencer l'autre avant que le deuxième sous-programme puisse être déclaré. En fait, même dans le cas d'une récursivité ordinaire, le sous-programme se référence lui-même avant que la définition du sous-programme ne soit complète.

La récursivité est autorisée car seul l'entête de la procédure ou de la fonction doit être déclaré avant le sous-programme et tous les types de paramètres et de fonctions, le cas échéant. Armé de ces informations, le QuickPascal peut déterminer la signification d'un appel de sous-programme et vérifier sa syntaxe.

De la même manière, le QuickPascal prend en charge la récursivité mutuelle avec la déclaration FORWARD, se composant de l'entête du deuxième sous-programme suivi du mot clef FORWARD.

Une déclaration directe permet au compilateur de comprendre comment une sous-routine doit être utilisée, même si le corps de la routine n'a pas encore été défini. Plus tard, lorsque le sous-programme réel apparaît, vous n'avez pas besoin de répéter l'un des paramètres. Le programme suivant montre un exemple de déclaration FORWARD :

  1. Function Deuxieme(A,B,C:Word):Real;Forward;
  2.  
  3. Function Premier(X,Y:Char);
  4. Var
  5.  Temp:Real;
  6. Begin
  7.   { : }
  8.  Temp:=Deuxieme(v1,v2,v3);
  9.   { : }
  10. ENd;
  11.  
  12. Function Deuxieme;Begin
  13.   { : }
  14.  Premier(q1,q2);
  15.   { : }
  16. End;

La fonction Premier appelle la fonction Deuxieme, et la fonction Deuxieme appelle la fonction Premier. Par conséquent, la fonction Deuxieme est déclarée FORWARD avant le début de Premier. Si vous le souhaitez, vous pouvez utiliser une déclaration directe avec n'importe quel sous-programme, que vous l'utilisiez de manière récursive ou non. En fait, de nombreux programmeurs placent des déclarations avancées au début d'un programme pour documenter les sous-programmes qu'il contient.



Dernière mise à jour : Mardi, le 11 janvier 2022