| Le langage PASCAL |
Ce cours ne nécessite aucune connaissance informatique préalable. Le Pascal est un langage de programmation.
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.
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.
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; |
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.
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.
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. |
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 |