LES SOUS-PROGRAMMES USTL Licence S.T.A. S3 A.P.I.2
Intérêts Ne pas réécrire plusieurs la même chose Factoriser le code Rendre le programme plus lisible Gagner de la place en mémoire USTL Licence S.T.A. S3 A.P.I.2
Deux types de sous-programmes : Les fonctions qui calculent une valeur à partir d’autres valeurs, la valeur résultat n’est pas une instruction, elle doit être utilisée dans une instruction Les procédures qui peuvent être considérées comme de nouvelles instructions USTL Licence S.T.A. S3 A.P.I.2
Déclarations Fonction On peut avoir plusieurs instructions fonct := … function <nom> [list_par]:<type_résultat> ; begin ... <nom> := <valeur> ; end (*<nom>*) ; On peut avoir plusieurs instructions fonct := … La liste de paramètres list_par peut être éventuel-lement vide (exemple : fonction Date) USTL Licence S.T.A. S3 A.P.I.2
Déclarations Procédures procedure <nom> [list_par] ; begin ... end (*<nom>*) ; Un programme peut être considéré une procédure sans paramètre. USTL Licence S.T.A. S3 A.P.I.2
Déclarations On peut bien sûr déclarer un sous-programme à l’intérieur d’un autre sous-programme et dans tous ces sous-programmes des variables dites locales. La multi-imbrication possible des sous-programmes entraîne l’existence de problèmes de visibilité. Visibilité des variables locales que l’on peut déclarer dans un sous-programme, mais aussi visibilité des sous-programmes eux-même les uns par rapport aux autres USTL Licence S.T.A. S3 A.P.I.2
Règle de portée des variables locales Il n’y a qu’une seule règle pour les variables locales : Une variable (locale ou non) est visible depuis la fin de sa déclaration jusqu’au « end » du programme ou sous-programme où elle a été déclarée, elle peut cependant être momentanément cachée dans un sous-programme par une autre variable ou un paramètre portant le même nom. USTL Licence S.T.A. S3 A.P.I.2
Un exemple scolaire program programme ; var variable : INTEGER ; // variable globale procedure sous_programme ; var variable : CHAR ; // variable locale begin ... // ICI variable désigne la variable locale end (*sous_programme*) ; function f(variable : BOOLEAN):... ; ... // ICI variable désigne le paramètre end (*f*) ; ... // ICI variable désigne la variable globale end (*programme*). USTL Licence S.T.A. S3 A.P.I.2
Un autre exemple scolaire program p ; var x,y,z : INTEGER ; // variables globales procedure q(x : INTEGER) ; var u,y : INTEGER ; // variables locales begin ... end (*q*) ; procedure r ; var z,u,v : INTEGER ; end (*r*) ; end (*p*). u v? x y z u v x y z u? v? x y z USTL Licence S.T.A. S3 A.P.I.2
Un exemple concret program AfficherFactorielle ; var nbre : CARDINAL ; // variable globale function f(nbre:CARDINAL): CARDINAL ; var i,fact : CARDINAL ; begin i := 2 ; fact := 1 ; // fact = 1! = (i-1)! while i <= nbre do begin // nbre désigne le paramètre fact := fact*i ; i := i+1 ; end (*while*) ; // i=nbre+1 donc fact=nbre ! f := fact ; end (*f*) ; readln(nbre) ; write(f(nbre)); // nbre=variable globale end. USTL Licence S.T.A. S3 A.P.I.2
Un exemple concret (autre version) program AfficherFactorielle ; function f(nbre:CARDINAL):CARDINAL ; var i, fact : CARDINAL ; begin i := 2 ; fact := 1 ; // fact = 1! = (i-1)! while i <= nbre do begin // nbre désigne le paramètre fact := fact*i ; i := i+1 ; end (*while*) ; // i=nbre+1 donc fact=nbre ! f := fact ; end (*f*) ; var nbre : CARDINAL ; // variable globale readln(nbre) ; write(f(nbre)); // nbre=variable globale end. USTL Licence S.T.A. S3 A.P.I.2
Règle de visibilité des sous-programmes Encore une fois il n’y a qu’une seule règle : Un sous-programme est visible depuis la fin de son entête jusqu’au « end » du programme ou sous-programme où il a été déclaré, il peut cependant être momentanément caché dans un sous-programme par une autre sous-programme ayant la même entête (surcharge). USTL Licence S.T.A. S3 A.P.I.2
Un exemple scolaire program programme ; procedure sous_programme_1 ; function fonction(…) : … ; begin … end (*fonction*) ; ... // ICI on peut utiliser fonction end (*sous_programme_1*) ; procedure sous_programme_2 ; ... // ICI on peut utiliser sous_programme_1 mais pas fonction end (*sous_programme_2*) ; ... // ICI on peut utiliser sous_programme_1 et sous_programme_2 ... // mais pas fonction end (*programme*). USTL Licence S.T.A. S3 A.P.I.2
Un autre exemple scolaire program programme ; procedure machin(x : INTEGER) ; overload ; begin ... end (*machin*) ; procedure machin(x,y : INTEGER) ; overload ; procedure truc ; procedure machin(x : INTEGER); ... begin //programme end (*machin*) ; ... begin ... ... end (*programme*). end (*truc*) ; // on peut utiliser machin et machin // on peut utiliser machin //on peut machin et machin machin et machin USTL Licence S.T.A. S3 A.P.I.2
Un exemple concret program AfficherPpcm is function ppcm(x,y : CARDINAL) : CARDINAL ; // on utilise x * y = ppcm(x,y) * pgcd(x,y) function pgcd(x,y : CARDINAL) : CARDINAL ; var a,b : CARDINAL ; begin a := x ; b := y ; while a <> b do begin if a<b then begin b := b-a ; end else begin a := a-b ; end (*if*) ; end (*while*) ; begin // ppcm pgcd := a ; return (x/pgcd(x,y))*y ; end (*pgcd*) ; end (*ppcm*) ; USTL Licence S.T.A. S3 A.P.I.2
Un exemple concret var x,y : CARDINAL ; begin write('tapez deux entiers strictement positifs : ') ; readln(x) ; readln(y) ; write('le ppcm est ') ; writeln(ppcm(x,y)) ; end (*AfficherPpcm*). USTL Licence S.T.A. S3 A.P.I.2
Un exemple concret (autre version) program AfficherPpcmEtPgcd ; function pgcd(x,y : CARDINAL):CARDINAL ; a,b : CARDINAL ; begin a := x ; b := y ; while a /= b do begin if a<b then begin b := b-a ; end else begin a := a-b ; end (*if*) ; end (*while*) ; pgcd := a ; end (*pgcd*) ; USTL Licence S.T.A. S3 A.P.I.2
Un exemple concret (autre version) fonction ppcm(x,y : CARDINAL):CARDINAL ; // utilise x * y = ppcm(x,y) * pgcd(x,y) begin return (x/pgcd(x,y))*y ; end (*ppcm*) ; x,y : CARDINAL ; write('tapez deux entiers strictement positifs : ') ; readln(x) ; readln(y) ; write('le ppcm est ') ; writeln(ppcm(x,y)) ; write(' et le pgcd est ') ; writeln(pgcd(x,y)) ; End. USTL Licence S.T.A. S3 A.P.I.2
Appels récursifs croisés Que faire si on a deux fonctions (ou procédures) faisant chacune appel à l’autre ? La première doit être avant la seconde puisque la seconde fait appel à la première, mais la première doit être après la seconde puisqu’elle fait appel à cette seconde (!!!). Pour cette raison (et d’autres aussi qu’on verra plus tard), il est possible de faire une première déclaration courte d’un sous-programme. Ça consiste à n’écrire que l’entête en la terminant par le mot-clef « forward » et après cette déclaration le sous-programme existe et peut être utilisé (en respectant la règle de visibilité citée auparavant) USTL Licence S.T.A. S3 A.P.I.2
Exemple d’appels récursifs croisés program tester_appels_croises ; function EstImpair(n : CARDINAL):BOOLEAN ; forward ; function EstPair(n : CARDINAL):BOOLEAN ; begin if n=1 then begin EstPair := FALSE ; end else begin EstPair := (n=0) or EstImpair(n-1) ; end (*if*) ; end (*EstPair*) ; function EstImpair(n : CARDINAL):BOOLEAN ; if n=0 then begin EstImpair := FALSE ; EstImpair := (n=1) or EstPair(n-1) ; end (*EstImpair*) ; ………… USTL Licence S.T.A. S3 A.P.I.2