Section courante

A propos

Section administrative du site

Le concept d'action

L'action est essentielle à un programme informatique. Autrement dit, un programme doit faire quelque chose avec ses données, même si cette action consiste à ne rien faire ! Les instructions décrivent ces actions. Elles sont soit simples (par exemple, l'instruction d'affectation), soit structurées.

L'instruction d'affectation

L'instruction d'affectation est la plus fondamentale. Elle spécifie qu'une valeur nouvellement calculée doit être affectée à une variable. La forme d'une affectation est :

<variable> := <expression>

Où := est l'opérateur d'affectation, à ne pas confondre avec l'opérateur relationnel =. L'instruction «a := 5» se prononce «la valeur courante de a est remplacée par la valeur 5», ou simplement «a devient 5».

La nouvelle valeur est obtenue en évaluant une expression composée d'opérandes, d'opérateurs et de désignateurs de fonction, constants ou variables. (Un désignateur de fonction spécifie l'activation d'une fonction.) Une expression est une règle de calcul d'une valeur où les règles conventionnelles d'évaluation de gauche à droite et de priorité des opérateurs sont respectées. L'opérateur not (appliqué à un opérande booléen) a la priorité la plus élevée, suivi des opérateurs de multiplication (*, /, div, mod, and), puis des opérateurs d'addition (+, -, or) et, en dernier lieu, des opérateurs relationnels (=, <>, <, <=, >=, >, in). Toute expression entre parenthèses est évaluée indépendamment des opérateurs précédents ou suivants.

Exemples :

  1. 2 * 3-4 * 5   = (2*3) - (4*5) = -14
  2. 15 div 4 * 4  = (15 div 4)*4  =  12
  3. 80/5/3        = (80/5)/3      =   5.333
  4. 4/2 *3        = (4/2)*3       =   6.000
  5. sqrt(sqr(3)+11*5)             =   8.000

Les expressions booléennes ont la propriété que leur valeur peut être connue avant même que l'expression entière ne soit évaluée. Supposons par exemple que x=0. Alors :

  1. (x>0) and (x<10)

est déjà connu comme faux après le calcul du premier facteur, et le second n'a pas besoin d'être évalué. Les règles de Pascal n'exigent ni n'interdisent l'évaluation de la seconde partie dans de tels cas. Cela signifie que le programmeur doit s'assurer que le second facteur est bien défini, indépendamment de la valeur du premier. Ainsi, si l'on suppose que le tableau a a un indice compris entre 1 et 10, alors l'exemple suivant est erroné !

  1. x := 0;
  2. repeat x:=x+1 until (x>10) or (a[x]=0)

(Notez que si a[i] n'est pas égal à 0, le programme fera référence à un élément a[11].)

L'affectation directe est possible pour les variables de tout type, à l'exception des fichiers. Cependant, la variable (ou la fonction) et l'expression doivent être de type identique, à l'exception du type réel de la variable, pouvant être entier. (Si un type de sous-intervalle est impliqué, son type scalaire associé détermine la validité de l'affectation)

Exemples d'affectations :

  1. root1  := pi*x/y
  2. root1  := -root1
  3. root3  := (root1 + root2)*(1.0 + y)
  4. found  := y>z
  5. count  := count + 1
  6. degree := degree + 10
  7. sqrpr  := sqr(pr)
  8. y      := sin(x) + cos(y)

L'instruction composée

L'instruction composée spécifie que les instructions la composant doivent être exécutées dans l'ordre où elles sont écrites. Les symboles begin et end servent de crochets. Notez que le «corps» d'un programme a la forme d'une instruction composée.

  1. { Instruction composé }
  2. program beginend(output);
  3.  
  4. var sum : integer;
  5. begin
  6.  sum := 3+5;
  7.  writeln(sum,-sum)
  8. end.

Pascal utilise le point-virgule pour séparer les instructions, et non pour les terminer; autrement dit, le point-virgule ne fait pas partie de l'instruction. Si un point-virgule avait été inséré après la deuxième instruction, une instruction vide (impliquant une absence d'action) aurait été supposée entre le point-virgule et le symbole end. Cela ne pose aucun problème, car une instruction vide est autorisée à ce stade. Des points-virgules mal placés peuvent toutefois poser problème.

Instructions répétitives

Les instructions répétitives spécifient que certaines instructions doivent être exécutées de manière répétée. Si le nombre de répétitions est connu à l'avance (avant le début des répétitions), l'instruction for est généralement la construction appropriée pour exprimer la situation ; sinon, l'instruction repeat ou while doit être utilisée.

L'instruction while

L'instruction while a la forme suivante :

while <expression> do <statement>

L'expression contrôlant la répétition doit être de type Boolean. Elle est évaluée avant chaque itération ; il faut donc veiller à la simplifier au maximum.

  1. { calcul h(n) = 1 + 1/2 + 1/3 + ... + 1/n }
  2.  
  3. program egwhile(input, output);
  4.  
  5. var n : integer; h :real;
  6. begin  read(n); write(n);
  7.    h := 0;
  8.    while n>0 do
  9.      begin  h := h + 1/n; n := n-1;
  10.      end;
  11.    writeln(h)
  12. end.

on obtiendra le résultat suivant :

10   2.928968253968e+00

L'instruction exécutée par l'instruction while (une instruction composée dans le cas précédent) est répétée jusqu'à ce que l'expression devienne fausse. Si sa valeur initiale est fausse, l'instruction n'est pas exécutée.

L'instruction de répétition

L'instruction de répétition a la forme suivante :

repeat <statement> {; <statement>} until <expression>

La séquence d'instructions entre les symboles repeat et until est exécutée au moins une fois. L'exécution répétée est contrôlée par l'expression booléenne, évaluée après chaque itération.

  1. { calcul h(n) = 1 + 1/2 + 1/3 + ... + 1/n }
  2.   
  3. program egrepeat(input, output);
  4.  
  5. var n : integer; h : real;
  6. begin  read(n);  write(n);
  7.   h := 0;
  8.   repeat h := h + 1/n; n := n-1
  9.   until n=0;
  10.   writeln(h)
  11. end.

on obtiendra le résultat suivant :

10   2.928968253968e+00

Le programme ci-dessus fonctionne correctement pour n > 0. Considérez ce qui se passe si n <= 0. La version while du même programme est correcte pour tout n, y compris n = 0.

Notez qu'il s'agit d'une séquence d'instructions exécutée par l'instruction repeat : une paire de crochets begin...end serait redondante (mais pas incorrecte).

L'instruction for

L'instruction for indique qu'une instruction doit être exécutée de manière répétée pendant qu'une série de valeurs est assignée à la variable de contrôle de l'instruction for. Sa forme générale est la suivante :

for <variable de controle> := <valeur initial> to <valeur final>
do <instruction>
for <variable de controle> := <valeur initial> downto <valeur final>
do <instruction>

Exemple :

  1. { calcul h(n) = 1 + 1/2 + 1/3 + ... + 1/n }
  2.  
  3. program egfor(input, output);
  4.  
  5. var i,n : integer; h : real;
  6. begin  read(n);  write(n);
  7.   h := 0;
  8.   for i := n downto 1 do h := h + 1/i;
  9.   writeln(h)
  10. end.

on obtiendra le résultat suivant :

10   2.928968253968e+00

Voici un autre exemple calculant le cosinus :

  1. { calculer le cosinus en utilisant le développement :
  2.      cos(x) = 1 - x**2/(2*1) + x**4/(4*3*2*1) - ... }
  3.  
  4. program cosine(input, output);
  5.  
  6. const   eps = 1e-14;
  7. var     x,sx,s,t:real;
  8.         i,k,n:integer;
  9. begin read(n);
  10.    for i := 1 to n do
  11.    begin read(x); t := 1; k := 0; s := 1; sx := sqr(x);
  12.       while abs(t) > eps*abs(s) do
  13.       begin k := k + 2;  t := -t *sx/(k*(k-1));
  14.          s := s+t
  15.       end;
  16.       writeln(x,s,k div 2)
  17.    end
  18. end.

on obtiendra le résultat suivant :

1.534622222233e-01  9.882477647614e-01               5
3.333333333333e-01  9.449569463147e-01               6
5.000000000000e-01  8.775825618904e-01               7
1.000000000000e+00  5.403023058681e-01               9
3.141592653590e+00 -1.000000000000e+00              14

La variable de contrôle, la valeur initiale et la valeur finale doivent être du même type (à l'exception du type réel) et ne doivent pas être modifiées par l'instruction for. Les valeurs initiale et finale ne sont évaluées qu'une seule fois. Si, dans le cas de to (downto), la valeur initiale est supérieure (inférieure) à la valeur finale, l'instruction for n'est pas exécutée. La valeur finale de la variable de contrôle reste indéfinie à la sortie normale de l'instruction for.

Un instruction for de la forme :

  1. for v:=e1 to e2 do S

est équivalent à la séquence d'instructions :

  1. if e1<=e2 then
  2. begin v := e1; S; v := succ(v); S; ...; v := e2: S
  3. end
  4. {à ce stade. v n'est pas défini}

et une instruction for de la forme :

  1. for v:=e1 downto e2 do S

est équivalent à l'énoncé :

  1. if e1 >= e2 then
  2. begin v := e1: S: v := pred(v); S: ...; v := e2; S
  3. end
  4. {à ce stade. v est indéfini}

À titre d'exemple final, considérons le programme suivant :

  1. { calcule 1 - 1/2 + 1/3 - ... +1/9999 - 1/10000, 4 chemins.
  2.    1) De gauche à droite, successivement
  3.    2) De gauche à droite, tous les termes positifs et négatifs, puis soustraire
  4.    3) De droite à gauche, successivement
  5.    4) De droite à gauche, tous les termes positifs et négatifs, puis soustraire}
  6.  
  7. program summing(output);
  8. var s1,s2p,s2n,s3,s4p,s4n,lrp,lrn,rlp,rln : real;
  9.     i  : integer;
  10. begin s1 := 0; s2p := 0; s2n := 0; s3 := 0; s4p := 0; s4n := 0;
  11.    for i := 1 to 5000 do
  12.    begin
  13.       lrp := 1/(2*i-1);     { termes pos, de gauche à droite }
  14.       lrn := 1/(2*i);       { termes négatifs, de gauche à droite }
  15.       rlp := 1/(10001-2*i); { termes pos, droit à la main }
  16.       rln := 1/(10002-2*i); {termes négatifs, de droite à gauche }
  17.       s1  := s1 + lrp - lrn;
  18.       s2p := s2p + lrp; s2n := s2n + lrn;
  19.       s3  := s3 + rlp - rln;
  20.       s4p := s4p + rlp; s4n := s4n + rln;
  21.    end;
  22.    writeln(s1,s2p-s2n);
  23.    writeln(s3,s4p-s4n);
  24. end.

on obtiendra le résultat suivant :

6.930971830595e-01  6.930971830601e-01
6.930971830599e-01  6.930971830612e-01

Pourquoi les quatre sommes «identiques» diffèrent-elles ?

Instructions conditionnelles

Une instruction conditionnelle, dite «if» ou «else», sélectionne une instruction parmi ses composantes pour exécution. L'instruction «if» spécifie qu'une instruction ne sera exécutée que si une condition (expression booléenne) est vraie. Si elle est fausse, aucune instruction ne sera exécutée, ou l'instruction suivant le symbole <else> sera exécutée.

L'instruction if

Les deux formes d'une instruction if sont :

if <expression> then <instruction>
if <expression> then <instruction> else <instruction>

L'expression entre les symboles «if» et «then» doit être de type booléen. Notez que la première forme peut être considérée comme une abréviation de la seconde lorsque l'instruction alternative est vide. Attention : il n'y a jamais de point-virgule avant «else» ! D'où le texte :

  1. if p then begin S1; S2; S3 end; else S4;

est incorrect. Le texte est peut-être encore plus trompeur :

  1. if p then; begin s1; S2; S3 end;

Ici, l'instruction contrôlée par l'instruction if est l'instruction vide. Entre le then et le point-virgule, l'instruction composée suivant l'instruction if sera donc toujours exécutée. L'ambiguïté syntaxique résultant de la construction :

if <expression-1> then if <expression-2> then <instruction-1>
else <instruction-2>

est résolu en interprétant la construction comme équivalente à :

if <expression-1> then
begin if <expression-2> then <instruction-1>
else <instruction-2>
end

Le lecteur est également averti qu'une formulation imprudente d'une clause «if» peut s'avérer très coûteuse. Prenons l'exemple d'une situation où l'on a n conditions mutuellement exclusives. c1...cn, chacune déclenchant une action distincte, si. Soit P(ci) la probabilité que ci soit vraie. Et disons que P(ci)-P(cj) pour i<j. La séquence de clauses «if» la plus efficace est alors :

  1. if c1 then s1
  2.    else if c2 then s2
  3.       else ...
  4.          else if c(n-1) then s (n-1) else sn

La réalisation d'une condition et l'exécution de son instruction complètent l'instruction if, contournant ainsi les tests restants.

Si «found» est une variable de type booléen, un autre abus fréquent de l'instruction if peut être illustré par :

  1. if a=b then found:=true else found:=false;

Une déclaration beaucoup plus simple est :

  1. found := a=b

Voici un exemple d'un programme écrivant un chiffre romain :

  1. { écrire des chiffres romains }
  2.  
  3. program roman(output);
  4.  
  5. var x,y : integer;
  6. begin  y:= 1; 
  7.    repeat  x := y; write(x,' ');
  8.       while x>=1000 do
  9.          begin write('m'); x := x-1000 end;
  10.       if x>=500 then 
  11.          begin write('d'); x := x-500 end;
  12.       while x>= 100 do
  13.          begin write('c'); x := x-100 end;
  14.       if x>=50 then
  15.          begin write('l'); x := x-50 end;
  16.       if x>=10 then
  17.          begin write('x'); x := x-10 end;
  18.       if x>=5 then 
  19.         begin write('v'); x := x-5 end;
  20.       while x>=1 do
  21.      begin write('i'); x := x-1 end;
  22.       writeln; y := 2*y;
  23.    until y>5000
  24. end.

on obtiendra le résultat suivant :

     1 i
     2 ii
     4 iiii
     8 viii
    16 xvi
    32 xxxii
    64 lxiiii
   128 cxxviii
   256 cclvi
   512 dxii
  1024 mxxiiii
  2048 mmxxxxviii
  4096 mmmmlxxxxvi

Notez qu'une seule instruction est contrôlée par une clause if. Par conséquent, lorsque plusieurs actions sont prévues, une instruction composée est nécessaire.

Le programme suivant élève la valeur réelle x à la puissance y, où y est un entier non négatif. Une version plus simple, et évidemment correcte, est obtenue en omettant l'instruction while interne : le résultat z est alors obtenu par la multiplication de y par x. Notez l'invariant de boucle : z*(u**e)=x**y. L'instruction while interne laisse z et u**e invariants, ce qui améliore évidemment l'efficacité de l'algorithme.

  1. { exponentiation avec exposant naturel }
  2.  
  3. program exponentiation(input, output);
  4.  
  5. var e,y: integer; u,x,z: real;
  6. begin read(x,y);  write(x,y);
  7.    z := 1; u := x; e := y;
  8.    while e>0 do
  9.    begin {z*u**e = x**y, e > 0 }
  10.       while not odd(e) do
  11.          begin e := e div 2; u := sqr(u)
  12.          end;
  13.       e := e-1; z := u*z
  14.    end;
  15.     writeln(z) {z = x **y }
  16. end.

on obtiendra le résultat suivant :

2.000000000000e+00        7  1.2e0000000000e+02

Le programme suivant trace une fonction réelle f(x) en orientant l'axe des X verticalement, puis en imprimant un astérisque aux positions correspondant aux coordonnées. La position de l'astérisque est obtenue en calculant y=f(x), en multipliant par un facteur d'échelle s, en arrondissant le produit à l'entier supérieur, puis en ajoutant une aiguille constante précédant l'astérisque du même nombre d'espaces.

  1. { représentation graphique d'une fonction
  2.    f(x) = exp(-x) * sin(2*pi*x) }
  3.    
  4. program graph1(output);
  5. const d = 0.0625;  {1/16, 16 lignes pour l'intervalle [x,x+1]}
  6.       s = 32;      {32 largeurs de caractères pour l'intervalle [y,y+1]}
  7.       h = 34;      {position du caractère sur l'axe des x}
  8.       c = 6.28318; {2*pi}  lim = 32;
  9. var X,Y : real; i,n : integer;
  10. begin
  11.    for i := 0 to lim do
  12.       begin x := d*i; y := exp(-x)*sin(c*x);
  13.       n := round (s*y) + h;
  14.       repeat write(' '); n := n-1
  15.       until n = 0;
  16.       writeln('*')
  17.    end
  18. end.

on obtiendra le résultat suivant :

                                  *
                                              *
                                                      *
                                                           *
                                                           *
                                                        *
                                                  *
                                          *
                                  *
                           *
                      *
                   *
                   *
                     *
                         *
                             *
                                  *
                                      *
                                         *
                                           *
                                           *
                                          *
                                        *
                                     *
                                  *
                               *
                              *
                             *
                            *
                             *
                               *
                                *
                                  *

L'instruction case

L'instruction case se compose d'une expression (le sélecteur) et d'une liste d'instructions. Chacune est étiquetée par une constante du type du sélecteur. Le type du sélecteur doit être scalaire, à l'exclusion du type réel. L'instruction case sélectionne pour exécution l'instruction dont l'étiquette est égale à la valeur courante du sélecteur : si aucune étiquette de ce type n'est indiquée, l'effet est indéfini. Une fois l'instruction sélectionnée terminée, le contrôle passe à la fin de l'instruction case. La forme est :

case <expression> of
   <liste des étiquettes de cas> : <instruction>;
   <   <...
   <liste des étiquettes de cas> : <instruction>
end

Exemple (on suppose que var i:Integer;) :

  1. case i of
  2.  0: x := 0;
  3.  1: x := sin(x);
  4.  2: x := cos(x);
  5.  3: x := exp(x);
  6.  4: x := ln(x);
  7. end

Exemple (on suppose que var ch:char;) :

  1. case ch of
  2.    'a','g','d': ch := succ(ch);
  3.    'z','e':     ch := pred(ch);
  4.    'f','g':     { Case vide }
  5. end

Remarques : Les «étiquettes de facilité» ne sont pas des étiquettes ordinaires et ne peuvent pas être référencées par une instruction goto. Leur ordre est arbitraire : cependant, les étiquettes doivent être uniques au sein d'une instruction de facilité donnée.

Bien que l'efficacité de l'instruction case dépende de l'implémentation, la règle générale est de l'utiliser lorsque plusieurs instructions mutuellement exclusives ont une probabilité de sélection similaire.

L'instruction goto

Une instruction goto est une instruction simple indiquant que le traitement ultérieur doit se poursuivre à un autre endroit du texte du programme, à savoir à l'emplacement de l'étiquette.

goto <label>

Chaque étiquette (un entier non signé de 4 chiffres maximum) doit apparaître dans une déclaration d'étiquette avant d'apparaître dans le corps du programme. La portée d'une étiquette L déclarée dans un bloc A correspond au texte entier de ce bloc. Autrement dit, une instruction de la partie instruction de A peut être préfixée par L:. Toute autre instruction du bloc A peut alors référencer L dans une instruction goto.

exemple (fragment de programme) :

  1. label 1; {bloc A}
  2.    ...
  3.   procedure B: {bloc B}
  4.     label 3:
  5.   begin
  6.   3: writeln('erreur'):
  7.       ...
  8.          goto 3
  9.       ...
  10.          goto 1
  11.   end; {bloc B}
  12.  
  13. begin {bloc A}
  14.    ...
  15. 1: writeln(' échec du test')
  16. {un « goto 3 » n'est pas autorisé dans le bloc A}
  17. end

Avertissement : L'effet des sauts depuis l'extérieur d'une instruction structurée vers cette instruction n'est pas défini. Par conséquent, les exemples suivants sont incorrects. (Notez que les compilateurs n'indiquent pas nécessairement une erreur.)

Exemples illégaux :

a)

  1. for i:= 1 to 10 do
  2.    begin S1;
  3.    3: S2
  4.    end;
  5. goto 3

b)

  1. if p then goto 3;
  2.  ...
  3. if q then 3: S

c)

  1. procedure P
  2. begin  ...
  3.   3: S
  4. end;
  5. begin ...
  6.    goto 3
  7. end.

Une instruction goto doit être réservée aux situations inhabituelles ou peu courantes où la structure naturelle d'un algorithme doit être rompue. Il est conseillé d'éviter l'utilisation de sauts pour exprimer des itérations régulières et l'exécution conditionnelle d'instructions, car de tels sauts détruisent la représentation de la structure de calcul dans la structure textuelle (statique) du programme. De plus, l'absence de correspondance entre les structures textuelle et computationnelle (statique et dynamique) nuit considérablement à la clarté du programme et complique considérablement la vérification. La présence de goto dans un programme Pascal indique souvent que le programmeur n'a pas encore appris à «penser» en Pascal (car c'est une construction nécessaire dans d'autres langages de programmation).



Dernière mise à jour : Mardi, le 12 Mars 2024