Le langage PASCAL

Ce cours ne nécessite aucune connaissance informatique préalable. Le Pascal est un langage de programmation.

Base numérique :

Afin de pouvoir bien commencer ce cours, il faut rappeler quelques notions numériques qui seront indispensables pour la suite. Bien sûr, il ne faut pas croire que je vais m'étaler sur des détails interminables. Pour simplifier mes explications, je vais utiliser des notions mathématiques : les bases numériques. En fait, nous avons l'habitude de compter avec les nombres décimaux ; mais il ne faut pas oublier ce qu'ils signifient. Lorsque nous lisons le nombre «23», il faut se rappeler que nous avons en réalité écrit 2*10^1 + 3*10^0 (Le signe «^» représente la puissance). Ici, nous voyons bien que nous sommes en base dix, que «3» est l'unité, et «2» la dizaine.
Maintenant que nous avons rappelé rapidement les principes de l'écriture d'un nombre en décimal, concentrons-nous sur les nombres binaires, définis avec la base 2. Cette base est intéressante car elle modélise un état électrique ; les valeurs 0 et 1 représentent respectivement un état électrique nul ou élevé. Nous désignerons un chiffre binaire par le terme bit signifiant «binary-digit». Avec deux bits, nous pourrions avoir quatre combinaisons possibles : 00, 01, 10, 11. Le nombre d'états différents peut être calculé par la formule suivante: 2^(nombre de bits). La mémoire des ordinateurs est composée d'octets, c'est-à-dire des paquets de huit bits. Ainsi, nous pouvons avoir 2^8 = 256 combinaisons différentes. Comme en décimal, le bit de droite est l'unité ; ainsi en binaire, le nombre décimal 23 se code : 16 + 4 + 2 +1 = 2^4+ 2^2 + 2^1 + 2^0 = 10111. Pour ne pas confondre les nombres binaires des nombres décimaux, nous écrirons un «b» minuscule après le nombre«10111b». De même, nous pouvons écrire un «d» pour désigner le nombre décimal «23d».

Pour simplifier la lecture et l'écriture d'un octet, nous utilisons un nouveau format : l'hexadécimal. Nous allons simplement grouper les bits par paquet de quatre. Ce paquet est nommé quartet, et peut prendre seize valeurs différentes. Comme nous ne possédons que dix chiffres, nous allons utiliser les six premières lettres de l'alphabet. Nous utiliserons les caractères : «0123456789ABCDEF». Pour coder en hexadécimal un octet, il ne nous faudra que deux chiffres hexadécimaux, suivis de la lettre «h». Cette dernière nous informe que le nombre est en base seize. Ainsi, «10111b» sera écris «17h».

 

Mémoire :

Dans un octet, nous allons pourvoir stocker une valeur de l'intervalle [0..255]. Les octets peuvent être combinés dans des blocs de mémoire, et ainsi permettre de mémoriser de plus grandes valeurs.
Différents blocs de mémoire en pascal :

Octet huit bits ; BYTE (entier de 0 à 255), ShortInt (entier signé de -128 à 127), Char (caractères) et Booléen (0= False, autre valeur=True).
Mot deux octets; Word (0 à 65535), Integer (entier signé) et d'autres très peu utilisés
Double mot quatre octets; LongInt (-2^31 à 2^31) et pointer.

 

Éditeur :

L'éditeur de Turbo Pascal 7 nous permet d'écrire des programmes, de les compiler (vérification du programme), de les exécuter (lancer) et aussi de les tracer (mode pas à pas).
Pour faciliter l'édition, l'EDI (éditeur de Développement Intégré) utilise des couleurs différentes pour représenter les termes du programme : en vert, vous aurez les chaînes de caractères, en blanc les mots réservés, en bleu les nombres, et en jaune le reste…
Pour compiler (vérifier le programme sans le lancer), utilisez l'option «compile» du menu «compile». Pour cela, soit vous utilisez la souris, soit vous appuyez sur F10 pour accéder à la barre de menu. Vous utiliserez «run» du menu «run» pour lancer votre programme.
Avant de lancer la première compilation (ou exécution), sauvegardez votre travail pour lui donner un nouveau nom. Pour cela, allez dans le menu "files", choisissez le menu "save as" puis sélectionnez le répertoire de l'unité de telle façon à vous retrouver dans le répertoire "G:\PROG" (sur les ordinateur du BEST). Là, vous pouvez sauvegarder votre fichier en lui donnant un nom de votre choix.

 

Terminologie :

Une variable est en fait un identificateur (sens espace) qui nomme (baptise) le contenu d'un bloc de mémoire. Il existe plusieurs identificateurs différents. Ainsi, les formats (type) comme «BYTE» et «WORD» sont des identificateurs.
Un type est un format de données permettant d'informer le pascal de la taille de mémoire à réserver pour stocker une variable future définie dans ce style.
Les constantes sont aussi indexées par des identificateurs.
Affecter: j'utilise ce terme pour désigner «l'action» de mettre une valeur (quelconque) dans la mémoire de la variable. En pascal, le signe ":=" permet d'affecter une valeur à un identificateur.

 

Typographie :

Un programme en pascal obéit à une norme syntaxique et typographique (bien que cette dernière ne soit pas obligatoire). Chacune des actions (informatiques) est séparée par un point virgule. Ce caractère ne signifie rien par lui-même. Il est là, simplement pour faire une séparation. En effet, le pascal ne fait pas de différence entre les majuscules/minuscules, et ne prend pas les espaces (du moins doublés) en compte ; nous pouvons imaginer que le compilateur supprime tous les espaces et majuscules pour analyser le programme.
Nous ne sommes pas limités par la mémoire : alors nous utiliserons des identificateurs clairs. Si nous devons stocker le nom d'un individu en mémoire, il semble logique de définir une variable nommée «Nom» et non pas «a» ou «b».
Vous remarquerez la majuscule de l'identificateur. Cela provient d'une norme typographique. En effet, nous mettrons une majuscule sur tous les débuts de «sens» et des termes représentatifs. Ainsi, nous écrirons «WriteLn» et non pas «writeln» ou «Writeln». Une majuscule pour commencer le mot «write» et une pour le mot (terme) «ln» ; ce dernier désignant «New Line».
Pour que tous les programmes soient lisibles, nous utiliserons les indexages et les conventions définies par les exemples suivants :

(******************************************************)
(* désignation / information du programme             *)
(* but, auteur(s) … unités…                           *)
(*                                                    *)
(******************************************************)
Program nom_prog;
Uses
      Crt,                 {commentaire aligné à droite}
      U1;                                  {commentaire}
Type
      Liste : format;                          {bla bla}
      Liste : format;
Var
      Liste : Format;
Const
      liste : format;

{******************************************************}
{ désignation / information                            }
{                                                      }
Procedure/Function (liste arguments):type;
Begin
      Bloc
End;

{*********** Programme principal **********************}
Begin
     
Bloc
End.

Documentation et information globale...

Dans le tableau ci-dessous, «action» désigne un code simple, et bloc représente en ensemble d'actions encadrées par un "Begin" et un "End", et les crochets sélectionnent ce qui est facultatif.

test conditionnel boucle
If condition Then action;
If condition
_Then block;
If condition
_Then action/block
_[Else action/block];
For Id:= val To/DownTo val
_Do action/block;
Repeat
_[action;]
_action
Until condition;
While condition
_Do action/block;

Programmation :

Nous allons commencer par écrire le plus petit programme fonctionnant sans erreur :

Begin
End.

Voilà, et il fonctionne. Nous remarquons qu'il n'est pas obligatoire d'identifier le programme avec le mot réservé «program».
Nous allons maintenant définir une variable. Soit Taille, une variable dans laquelle nous stockerons une hauteur (dans IR). Cela nous donne le programme suivant :

Var
_ _ _ Taille : Real;
Begin
End
.

Voilà, c'est fait. Nous allons maintenant affecter la valeur «1.72» à cette variable.

Var_ _Taille : Real;
Begin
_Taille := 1.72;
End.

Le point virgule derrière le «1.72» est facultatif devant un «End». De même, il n'y a pas de point virgule derrière le «Begin», mais vous pouvez en mettre.
Pour apprendre à utiliser l'EDI, faites les manipulations suivantes : tapez F8 jusqu'à l'exécution de la ligne «Taille:= 1.72» (je veux dire par-là, que la ligne de sélection est sur «End.»), puis placez votre curseur sur le terme «Taille» et tapez Ctrl-F4 (§ menu debug, puis evalue…). Vous avez ouvert une fenêtre qui vous affiche la valeur stockée par Taille.

C'est bien, mais nous avons un programme un peu simple, non ? Il serait intéressant que le programme affiche lui-même la valeur de Taille. Nous allons utiliser la procédure pascal «WriteLn». WriteLn est une procédure qui prend un nombre indéfini d'argument ; je veux dire par-là, que vous ne pouvez lui donner aucun paramètre si vous le voulez, ou même en mettre plusieurs, et même de types différents…

Var
_ _ _ Taille : Real;
Begin
_Taille := 1.72;
_WriteLn('Taille contient :',Taille);
End.

En pascal, la procédure Write (ou WriteLn) a la possibilité d'afficher une valeur sous un format structure. Si vous écrivez «Taille:5:3», il sera affiché cinq chiffres (virgule comprise), dont trois derrière la virgule. Si la variable «Taille» était définie en tant qu'entier (Integer), nous ne pourrions définir le format qu'avec le nombre de chiffres, car il n'y a pas de nombre derrière la virgule.

Var
_ _ _ Taille : Real;
Begin
_Taille := 1.72;
_WriteLn('Taille contient :',Taille:5:3);
End.

Ici, l'affectation est définie à l'intérieur du programme. C'est une solution simple, mais figée. Demandons à l'utilisateur d'affecter avec une saisie une valeur à notre variable. Pour cela, nous utiliserons la procédure «ReadLn». N'oubliez pas, il faut toujours écrire quelque chose sur l'écran pour informer l'utilisateur qu'il va devoir entrer des données (ainsi que le format).

Var
_ _ _ Taille : Real;
Begin
_Write('Quel est ta taille:');
_ReadLn(Taille);
_WriteLn('Taille contient:',Taille:5:3);
End.

Note : La procédure «Read» ne sera pas utilisée pour l'instant. L'utilisation de cette procédure prête à confusion dans le cas de saisies multiples.

Maintenant, faisons une petite comparaison de taille :

Var
_ _ _ Taille : Real;
Begin
_Write('Quel est ta taille:');
_ReadLn(Taille);
_If Taille < 1.24
_Then WriteLn('Tu est petit(e)');
_Else WriteLn('Tes pieds touchent sûrement le sol.');
_WriteLn('Taille contient:',Taille:5:3);
End.

A méditer :

Var
_ _ _ A,B : String;
Begin
_Write(A);
_WriteLn(B);
_WriteLn(A,B);
_ReadLn(A);
_ReadLn(B);
_ReadLn(A,B);
End.

Afin d'amener d'une façon utile quelques nouvelles instructions, nous allons élaborer un petit projet simple, que nous affinerons au fur et à mesure, donc voici le sujet:

Établissez un programme demandant "entrez un nombre entier de l'intervalle [0..100]" à un utilisateur. Suivant la saisie, vous informerez l'utilisateur, si son nombre appartient à l'intervalle demandé.

Nous allons décortiquer cet énoncé, et établir un programme. Nous pouvons a priori utiliser un BYTE pour stocker un nombre de l'intervalle demandé. Il semble être intéressant de savoir qu'une saisie numérique avec «ReadLn» ne vérifie pas réellement si la variable est d'un type signé (ShortInt). De ce fait, si j'utilise «ReadLn» avec un BYTE, je peux saisir «-2», ce qui sera converti en «254». Vu ce petit problème, nous utiliserons un «ShortInt» : ce dernier pourra stocker notre intervalle, et de plus, permettra une vérification. Je n'ai pas demandé de réitérer la saisie jusqu'à ce quelle soit dans l'intervalle définit ; nous ne le ferons donc pas. Pour informer l'utilisateur, nous devrons tester la saisie, et afficher des textes en conséquence.

Var
_ _ _ Saisie : ShortInt;
Begin
_Write('Entrez un nombre entier de [0..100] : ');
_ReadLn(Saisie);
_If Saisie < 0_ _ _ _ _ _ _ {Liste de test conditionnel}
_Then WriteLn('Nombre inférieur à l''intervalle')
_Else
_If Saisie > 100
_Then WriteLn('Nombre supérieur à l''intervalle')
_Else WriteLn('Nombre correct');
End.

Nous remarquons rapidement qu'il est lourd d'enchaîner des tests. Nous allons donc utiliser les opérateurs booléens qui nous simplifierons l'écriture.

 

Booléens :

Lorsque nous faisons une condition, nous obtenons un nombre booléen, donc les valeurs peuvent être «Vrai» ou «Faux» (True/False). Si nous désirons associer plusieurs booléen ensemble, nous allons utilisé les opérateurs booléen suivant : AND, OR, XOR et NOT

AND comme une multiplication (True = 1 et Flase=0); Il faut que les deux soit vrai en même temps
OR comme une addition; Il faut au moins l'un des deux vrai
XOR l'addition binaire sens retenu; seul l'un doit être vrai
NOT renvoi le complémentaired'un seul booléen ; vrai si il est faux

Voici quatre possibilité de tester l'appartenance de notre nombre à l'intervalle définie:

IF (Saisie < 0) Or (Saisie > 100)
Then WriteLn('Hors intervalle);
IF Not ((Saisie >= 0) AND (Saisie <= 100))
Then WriteLn('Hors intervalle);
IF (Saisie >= 0) AND (Saisie <= 100)
Then WriteLn('Dans l''intervalle);
IF Not((Saisie < 0) Or (Saisie > 100))
Then WriteLn('Dans l''intervalle);

Boucle :

Maintenant que nous pouvons vérifier la saisie, il serait intéressant d'obliger l'utilisateur d'entrer correctement un nombre de l'intervalle. Nous allons répéter la saisie plusieurs fois jusqu'à obtenir une réponse correcte. Avant tous, regardons les trois formes de boucle (simple) disponibles :

For <Id_Var> := <Valeur> To/DonwTo <Valeur>
Do Bloc;

Repeat
_[action;]
_action
Until <condition>;

While <condition>
Do bloc;

La boucle "for" est utilisée lorsque l'on sait à l'avance le nombre de fois que l'on désire répéter une (ou plusieurs) action. "Repeat" et "While" permettent de répéter des actions suivant les valeurs d'une condition. Avec "While", si la condition n'est pas satisfaite dès le départ, le bloc d'action ne sera pas exécuté ; avec "Repeat", les actions seront exécutées au moins une fois.

Nous pouvons écrire le programme suivant, pour forcer l'utilisateur à saisir un nombre de l'intervalle :

Var
_ _ _ Saisie : ShortInt;
Begin
_Repeat
_ Write('Entrez un nombre entier de [0..100] : ');
_ ReadLn(Saisie);
_Until (Saisie>=0)And(Saisie<=100);{Nb dans Intervalle}
End.

Ici, la demande de saisie sera répétée tant que l'utilisateur ne rentrera pas une valeur de l'intervalle.

 

Sous-programme :

Même si l'on peut continuer à mettre notre code dans la partie principale du programme, il serait intéressant de créer des sous-programmes. Ces derniers permettront une meilleure lisibilité, et un avantage pour rechercher les erreurs éventuelles.
Pascal propose deux sortes de sous-programme : les fonctions ("Function") et les procédures ("Procedure"). Les fonctions sont comparables à des variables à lecture seule (on ne peut pas affecter avec ":="), ou à des fonctions numériques comme "sin(t)"… Les procédures sont des blocs de programme effectuant des actions sur les paramètres fournis (passés).
Nous allons créer une fonction saisie qui nous renverra le nombre entré par l'utilisateur, avec les conditions d'obligation de l'intervalle :

Function Saisie : ShortInt;
Var Tmp : ShortInt;
_ _ _ _ {Variable locale de travail}
Begin
_Repeat
_ Write('Entrez un nombre entier de [0..100] : ');
_ ReadLn(Tmp);
_Until (Tmp>=0) And (Tmp<=100);
_Saisie := Tmp;
End;

Var
_ _ _ Memo : ShortInt;
Begin
_Memo := Saisie;
End.

Nous avons créer une variable «Tmp» pour stocker la lecture de «ReadLn». Certes, il est possible de ne pas utiliser de variable temporaire, et d'utiliser directement «Saisie», mais ceci ne serait pas compatible avec toutes les versions Pascal.

 

Premier programme :

Compléter le programme pour qu'un utilisateur recherche un nombre préalablement mémorisé. Les informations sur la saisie suivante seront implémentées : «nombre recherché plus grand/plus petit»

Function Saisie: ShortInt;
Var _ Tmp: ShortInt;_ _ _ _{Variable locale de travail}
Begin
_ Repeat
_ _ Write('Entrez un nombre entier de [0..100]: ');
_ _ ReadLn(Tmp);
_ Until (Tmp>=0)And(Tmp<=100);
_ Saisie:= Tmp;
End;

Var
_ Memo, _ _ _ __ _ _ _ _ _ _ _ _ _ _ _ _{Mémorisé}
_ _ _ Prop: ShortInt;_ _ _ _ _ _ _ _ _ _ {Proposition}
_ _ _ i_ _: Byte;_ _ _ _ _ _ _ _ _ _ _ _ _ _{compteur}
Begin
_ WriteLn('Mémorisation du nombre');
_ Memo:= Saisie;
_ For i:=24 DonwTo 0 Do WriteLn;_ _ _ {Efface l'écran}
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ {Ici, i=0}
_ WriteLn('Recherchez le nombre');
_ Repeat
_ _ Prop:= Saisie;
_ _ Inc(i); {équivalant à «i:=i+1»}
_ _ If Prop<Memo
_ _ Then WriteLn('Nombre cherché plus grand.')
_ _ Else
_ _ If Prop>Memo
_ _ Then WriteLn('Nombre cherché plus petit.')
_ _ Else WriteLn('Vous avez trouvé en ',i,'coups.');
_ Until Prop=Memo;
End.

Les paramètres :

Utiliser un sous programme est très intéressant pour effectuer un traitement modulaire. Ci-dessus, nous avons définir un sous-programme pour gérer la saisie d'un nombre. En général, nous découperons nos programmes en petite tâche : un peu comme des paquets d'idées.
Pour traiter des données, il nous faudra rapidement pouvoir donner des conditions de traitement : un peu comme une fonction numérique avec variables. Les procédures (et fonctions) du pascal peuvent recevoir des paramètres (arguments) pour personnaliser le traitement. Ainsi, nous allons modifier notre fonction «saisie» de telle façon qu'elle puisse effectuer une saisie d'un nombre dans un intervalle préciser en paramètres.

Syntaxe: _ Procedure Id (liste_id : type; …; liste_id:type);
_ _ _ _ Function Id (liste_id : type; …; liste_id:type):type;
_ _ _ _ où Id est un nom de sous-programme; liste_id est une liste de nom de paramètre suivit du type.

Function Saisie(Min,Max :Integer):ShortInt;
Var Tmp : ShortInt;
_ _ _ _ {Variable locale de travail}
Begin

Repeat
Write('
Entrez un entier de l'intervalle [',Min,'..',Max,'] : ');
ReadLn(Tmp);
Until (Min<=Tmp)And(Tmp<=Max);
Saisie := Tmp;
End;
Var
Memo : ShortInt;
Begin
Memo := Saisie(0,100);
End.

Ici, nous avons définir deux paramètres nommés "MIN" et "MAX", en tant qu'entier signé. Ces deux paramètres sont équivalent à des variables locales : c'est-à-dire, fonctionnant de la même façon que la variable "Tmp". Lorsque l'on modifie la valeur d'une variable locale, cette modification n'est pas retournée au programme d'appel (appelant le sous-programme). Nous pouvons imaginer que pascal donne une copie des données dans les paramètres, et qu'une fois le sous-programme achevé, ces copies sont détruites. Grâce à ce principe, nous pouvons passer en paramètre à un sous-programme de valeurs directes : 1, 2 , 10, 'TEXT' …. Ici, nous avons donné les extremums en valeur directe. Nous verrons plus tard qu'il est possible de retourner des valeurs par les paramètres.

 

Logique Binaire (ou booléen) sur l'opérateur XOR :

L'opérateur XOR permet d'effectuer des opérations binaires sur deux opérandes (des nombres) suivant la table binaire suivante :

XOR 0 1
0 0 1
1 1 0

Si nous notons par "a" et "b" les deux opérandes. Nous remarquons que "a XOR b" est nul si "a" et "b" ont la même valeur.
Nous désirons (fada que nous somme) substituer l'opérateur «XOR» par une nouvelle expression (seulement sur des opérandes binaires [0..1]). Pour cela, nous allons écrire les sous-programmes paramétrés suivants : XOR_Vrai et XOR_Subst. Puis un programme principal, nous permettant de vérifier l'équivalence de nos deux calculs paramétrés.

Function XOR_Vrai(a,b :Byte):Byte;
Begin
_ XOR_Vrai := a XOR b ;
End;
Function
XOR_Subst(a,b :Byte):Byte;
Begin
{---- Ici, nous allons voir plusieurs possibilité –}
End;
Var
_ _ _ Memo ,_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ {Mémorisé}
_ _ _ Prop : ShortInt;_ _ _ _ _ _ _ _ _ _{Proposition}
_ _ _ i_ _ : Byte;_ _ _ _ _ _ _ _ _ _ _ _ _ {compteur}
Begin
_ For Op1 := 0 To 1
_ Do For Op2 := 0 To 1
_ Do Begin
_ _ Write(Op1,' XOR ',Op2,' – ');
_ _ V1 := XOR_Vrai(Op1,Op2);
_ _ V2 := XOR_Subst(Op1,Op2);
_ _ Write('V1 :',V1,' ');
_ _ Write('V2 :',V2,' ');
_ _ If V1=V2
_ _ Then WriteLn('Equivalent')
_ _ Else WriteLn('— différent –');
_ End;
End.

 


Dernière mise à jour : dimanche 06 janvier 2008