Programmation Pascal/Version imprimable
Une version à jour et éditable de ce livre est disponible sur Wikilivres,
une bibliothèque de livres pédagogiques, à l'URL :
https://fr.wikibooks.org/wiki/Programmation_Pascal
Sections
Introduction
Le langage de programmation Pascal (dont le nom vient du mathématicien français Blaise Pascal) a été inventé par Niklaus Wirth dans les années 1970. Il a été conçu pour servir à l'enseignement de la programmation de manière rigoureuse mais simple, en réaction à la complexité de l'ALGOL 68. Le Pascal est donc principalement utilisé dans l'enseignement et notamment dans les universités.
Ce livre explique comment implémenter un algorithme impératif en Pascal pour ensuite l'exécuter sur une machine. Ce livre n'enseigne pas comment créer des algorithmes et résoudre des problèmes mais comment, à partir d'un algorithme impératif créer un programme informatique.
Prérequis cognitif :
- Algorithmique impérative, nécessaire pour créer des algorithmes avant de les implémenter.
- Utilisation simple de l'ordinateur (édition de texte, shell simple)
Prérequis matériels :
- un ordinateur, n'importe lequel et de n'importe qu'elle architecture du moment que les prérequis logiciels sont respectés.
Prérequis logiciels :
- un éditeur de texte : le plus simple suffit. Un Environnement de développement pascal serait un plus.
- un compilateur Pascal fonctionnant pour cet ordinateur.
Exemple d'environnement de travail classique :
- Lazarus (créé en... Pascal) pour éditer le code source
- Free Pascal comme compilateur
- Le tout sous le système d'exploitation Linux, Microsoft Windows, ou Mac OS
- Sur un ordinateur de type PC ou Macintosh.
Un premier programme
Le fichier source[modifier | modifier le wikicode]
Le classique Hello world en Pascal, enregistrez le code suivant dans un fichier texte nommé hworld.pas
:
program hworld;
begin
writeln("Hello world!")
end.
Compilez ce programme, et lancez-le. Le message suivant doit normalement s'afficher :
Hello world!
Le code source en détail[modifier | modifier le wikicode]
program hworld;
Le code source commence par déclarer qu'il s'agit d'un programme nommé hworld
Remarque:
Le nom du programme pourrait être Hello_World et comporter ici 11 caractères par exemple, même sous DOS: la chaine de caractères n'est pas trop longue car il ne s'agit pas là du nom du fichier DOS en format 8.3, mais simplement du nom du programme pour le compilateur.
Par contre, le fichier quand à lui devra ne comporter que 8 caracrètres, par exemple hwold.pas.
begin
Début de la routine principale, appelée au démarrage du programme.
writeln("Hello world!")
Appel à la procédure writeln
(write line) pour afficher la chaîne "Hello world!"
sur la sortie standard.
end.
Fin de la routine principale et du programme.
Donc,
program Hello_World;
begin
writeln('Hello world!')
end.
se compile et s'exécute très bien avec n'importe quel compilateur Pascal, y compris les anciens depuis Turbo Pascal 3 sous DOS.
Structure d'un programme
Instructions et blocs[modifier | modifier le wikicode]
Une instruction séquence d'instructions regroupe plusieurs instructions en une seule.
Celle-ci commence par le mot clé begin
et se termine par end
.
Le ; sert à séparer deux instructions.
Voici un exemple :
begin
temp := x ;
x := y ;
y := temp
end;
Cette instruction Pascal sera traduite par un bloc en Java
{
int temp = x ;
x = y ;
y = temp ;
}
Catégorie[modifier | modifier le wikicode]
Un fichier source Pascal débute toujours par un mot clé indiquant le type de code :
- Un programme, c'est à dire une application indépendante (
program
) ; - Un module utilisable dans un programme ou un autre module (
unit
).
Ce mot clé doit être suivi d'un identifiant (un nom) afin de pouvoir faire référence à ce module ou ce programme.
Afin que le compilateur trouve les modules à partir de leur nom, il faut que le nom du fichier source soit identique : un module nommé par :
unit my_unit;
doit être enregistré dans un fichier nommé my_unit.pas
.
Exemple 1 : un programme[modifier | modifier le wikicode]
program first_app;
...
Exemple 2 : un module[modifier | modifier le wikicode]
unit my_unit;
...
Exemple 3 : un programme utilisant le module de l'exemple 2[modifier | modifier le wikicode]
Le mot clé uses
spécifie la liste des modules utilisés :
program second_app;
uses my_unit;
...
Compilation[modifier | modifier le wikicode]
L'extension des fichiers produits par la compilation varie selon la plateforme utilisée et le compilateur (natif ou P-code).
Cependant, la plupart des compilateurs ne gère pas la compilation en chaîne : chaque module et programme doit être compilé séparemment et deux modules ne peuvent donc s'utiliser mutuellement.
Commentaires[modifier | modifier le wikicode]
Les commentaires sont encadrés par les accolades :
program first_app;
{ ma première application en Pascal }
...
Alternativement, on peut utiliser les parenthèses-étoiles :
program first_app;
(* ma première application en Pascal *)
...
Ce qui était plus pratique avec les anciens claviers ne comportant pas les accolades.
Le compilateur Turbo Pascal utilise certains commentaires spéciaux pour préciser des directives de compilations. Ceux-ci débutent par un caractère $, par exemple {$R-,I-}
pour désactiver la vérification des erreurs d'intervalle (Range errors) et des erreurs d'entrée-sortie (I/O errors).
Structure générale d'un programme[modifier | modifier le wikicode]
program {nom du programme};
uses {liste des modules utilisés};
{...déclaration des variables globales et des types...}
{...déclaration des procédures et fonctions...}
begin
{...instructions de la routine principale...}
end.
Structure générale d'un module[modifier | modifier le wikicode]
Le module est divisé en deux grandes parties :
- La partie
interface
expose les fonctions, procédures, variables et types publiques, c'est à dire accessibles depuis les modules et programmes qui utilisent ce module. - La partie
implementation
contient le code implémentant les fonctions et procédures publiques, et peut contenir d'autres variables, types, fonctions et procédures internes au module.
unit {nom du module};
interface
uses {liste des modules utilisés};
{...déclaration des variables globales et des types...}
{...déclaration des procédures et fonctions...}
implementation
uses {liste des modules utilisés};
{...déclaration des variables globales et des types...}
{...déclaration des procédures et fonctions...}
begin
{...instructions d'initialisation du module...}
end.
Variables
Une variable sert à stocker une donnée. Elle a un nom, et un type (entier, chaîne de caractères, tableaux d'entiers, ...).
Déclaration des variables[modifier | modifier le wikicode]
Les variables peuvent être déclarées en début de programme ou de module. Dans ce cas, elles sont globales, car accessibles à toutes les procédures et fonctions qui suivent.
Les variables peuvent également être déclarées en début de procédure ou de fonction, où elle seront locales à celle-ci.
Les déclarations de variables commencent par le mot clé var
, puis chaque variable est déclarée selon la syntaxe suivante :
nom_variable : type_de_variable ;
Il est également possible de regrouper les variables ayant le même type :
nom_variable1 , nom_variable2 : type_de_variable ;
Par exemple :
var
i,j : integer;
s : String;
Affectation[modifier | modifier le wikicode]
Pour affecter une valeur constante ou le résultat d'une expression à une variable, il faut utiliser l'opérateur :=
(caractère deux-points suivi du caractère égal).
Par exemple :
i:=5;
j:=i+10;
Affectation à la déclaration[modifier | modifier le wikicode]
Il est possible d'affecter une valeur à la déclaration d'une variable, en utilisant l'opérateur égal ( =
), le caractère deux-points étant déjà utilisé pour déclarer le type :
var i:integer=5;
Procédures et fonctions
Une procédure ou une fonction est une sous-routine, en général appelée plusieurs fois. Ceci permet de regrouper un code utilisé plusieurs fois, de diviser le programme en sous-programmes.
Différences procédure/fonction[modifier | modifier le wikicode]
Procédures et fonctions acceptent des paramètres, seule une fonction retourne une valeur. La procédure n'en retourne pas.
Déclaration d'une procédure[modifier | modifier le wikicode]
La déclaration d'une procédure se fait avec le mot clé procedure
suivi du nom de la procédure, et de la liste des paramètres entre parenthèses. Cette liste de paramètres est déclarée avec la même syntaxe que les variables.
Ensuite, les variables locales sont déclarées, puis les instructions sont comprises dans un bloc begin
... end;
Par exemple :
procedure NumeroFoisDix( numero : integer ) ;
var j : integer;
begin
j := numero * 10 ;
println('j = ', j) ;
end ;
Déclaration d'une fonction[modifier | modifier le wikicode]
La syntaxe est similaire à celle d'une procédure, excepté que le mot clé utilisé est function
et que le type de retour doit être déclaré.
Par exemple :
function NumeroPlusCinq( numero : integer ) : integer ;
var j : integer ;
begin
j := numero + 5 ;
NumeroPlusCinq := j ;
end ;
Retourner une valeur se fait en affectant celle-ci au nom de la fonction.
Interface et implémentation dans un module[modifier | modifier le wikicode]
Dans un module, la partie implentation
contient le code des sous-routines en utilisant la syntaxe des paragraphes précédant.
La partie interface
ne reprend que la première ligne.
Par exemple :
unit MonModule;
interface
procedure NumeroFoisDix( numero : integer ) ;
function NumeroPlusCinq( numero : integer ) : integer ;
implementation
procedure NumeroFoisDix( numero : integer ) ;
var j : integer;
begin
j := numero * 10 ;
println("j = ", j) ;
end ;
function NumeroPlusCinq( numero : integer ) : integer ;
var j : integer ;
begin
j := numero + 5 ;
NumeroPlusCinq := j ;
end
end.
Ordre de déclaration[modifier | modifier le wikicode]
La compilation en une passe implique que chaque fonction ou procédure appelée doit être définie avant. L'ordre des sous-routines est donc important.
L'exemple suivant produit une erreur de compilation :
procedure FaireFaire;
begin
println('Procédure qui sous-traite l''action');
Faire;
end;
procedure Faire;
begin
println('Procédure qui fait l''action');
end;
L'ordre correct est le suivant :
procedure Faire;
begin
println('Procédure qui fait l''action');
end;
procedure FaireFaire;
begin
println('Procédure qui sous-traite l''action');
Faire;
end;
Cette restriction ne s'applique pas aux sous-routines publiques d'un même module, car elles sont pré-déclarées dans la partie interface.
Il existe des cas où deux procédures s'appellent mutuellement. Aucune ne peut être située avant/après l'autre. Dans ce cas, il faut en prédéclarer une avec le mot clé forward
.
Par exemple :
procedure GrandCalcul(n:integer); forward;
procedure PetitCalcul(n:integer);
begin
if n>100 then GrandCalcul(n);
else begin
...
endif;
end;
procedure GrandCalcul(n:integer);
begin
if n<=100 then PetitCalcul(n);
else begin
...
endif;
end;
Dépendances mutuelles et références circulaires
Dépendances mutuelles et références circulaires[modifier | modifier le wikicode]
Parfois, on est amené à faire deux unités où chacune fait références aux fonctions de l'autre. Il s'agit d'une dépendance mutuelle. Dans certains cas, cela peut poser des difficultés.
Dépendance au niveau implémentation[modifier | modifier le wikicode]
Pour commencer, il y a un cas où cela marche sans problème, c'est quand la clause uses qui fait référence à l'autre unité se trouve dans la section d'implémentation. Dans ce cas, l'ensemble des déclarations de types, de procédures et de fonctions sont lues dans chacune des deux unités. En effet, ces déclaration se trouve dans la section interface, c'est-à-dire avant que la question de la dépendance mutuelle soit soulevée. Quand, dans l'implémentation, on fait référence à l'autre unité, tous les membres publics sont déjà définis.
Dépendance mixte interface-implémentation[modifier | modifier le wikicode]
Il se peut qu'une unité A fasse référence à une unité B par une cause uses dans sa partie implémentation, tandis que l'unité B fasse référence l'unité A dans sa partie interface. Dans ce cas, le compilateur va d'abord lire l'interface de A parce qu'elle est nécessaire à l'interprétation de l'interface de l'unité B. Par exemple, l'unité B peut proposer des fonctions qui prennent en paramètre un type défini dans l'unité A. Une fois l'interface de B déterminée, le compilateur va s'occuper des implémentations. Par la suite, l'unité A et l'unité B peuvent utiliser dans leur implémentation les fonctions de l'autre. Référence circulaire ou dépendance interface-interface
Maintenant, si l'on fait deux unités qui font référence l'une à l'autre, mais avec une clause uses dans leur interface, on obtient l'erreur de référence circulaire. En effet, pour pouvoir interprêter correctement l'interface d'une unité, il faut que le compilateur ait lu l'interface de l'autre unité, et vice-versa. Certains compilateurs ne génère pas d'erreur dans ces cas-là, mais en Pascal, pour le moment, une telle chose est impossible.
Fausse référence circulaire et vraie référence circulaire[modifier | modifier le wikicode]
Il se peut qu'en réalité, il ne soit pas nécessaire de déclarer la dépendance au niveau de l'interface de l'unité. Dans ce cas, il suffit de déplacer une partie de la clause uses dans la partie implémentation, pour les unités ne faisant appel seulement à ce moment à des procédures, des fonctions, ou à des types déclarés dans d'autres unités. C'est le cas le plus fréquent fort heureusement.
Sinon, c'est généralement que certains objets définis dans une unité A contiennent des champs ou des méthodes utilisant des objets définis dans une unité B, qui eux-même contiennent des champs ou des méthodes utilisant des objets définis dans l'unité A. Par exemple :
{ dans l'unité A }
type
TObjetA = class
function DonneObjetB: TObjetB;
end;
{ dans l'unité B }
type
TObjetB = class
function DonneObjetA: TObjetA;
end;
Solution par la fusion[modifier | modifier le wikicode]
On peut régler le problème de la référence circulaire en mettant les deux objets dans une seule et même unité et en prédéclarant les types. Cela se fait de la manière suivante :
{ dans l'unité fusionnée AB }
type
TObjetA = class; { prédéclaration de A }
TObjetB = class; { prédéclaration de B }
TObjetA = class { déclaration complète de A }
function DonneObjetB: TObjetB;
end;
TObjetB = class { déclaration complète de B }
function DonneObjetA: TObjetA;
end;
Bien entendu, il se peut que, de fil en aiguille, on obtiennent des fichiers de code très gros, ce qui est l'inconvénient de cette méthode.
Solution par le non-typage[modifier | modifier le wikicode]
Enfin, on peut résoudre le problème en ne typant pas les champs ou les paramètres et les valeurs de retour des procédures et des fonctions.
{ dans l'unité A }
type
TObjetA = class
function DonneObjetB: TObject;
end;
{ dans l'unité B }
type
TObjetB = class
function DonneObjetA: TObject;
end;
Bien que la solution ne soit pas très élégante, elle permet de contourner le problème. Lors de l'appel des fonctions DonneObjetA et DonneObjetB, il faudra faire un transtypage pour avoir un objet bel et bien identifié comme étant de type TObjetA ou TObjetB. Par exemple :
procedure UtiliseObjetA;
var objA : TObjetA;
begin
objA := TObjetA(objB.DonneObjetA);
objA.Affiche;
end;
Créer de nouveaux types
Déclaration des types[modifier | modifier le wikicode]
Les déclarations de types commencent par le mot clé type
, puis chaque nouveau type est déclaré selon la syntaxe suivante :
nom_type = type ;
Par exemple :
type
entier = integer;
vraifaux = boolean;
Ensuite, les variables peuvent utiliser ces types :
var i:entier;
b:vraifaux;
Structure[modifier | modifier le wikicode]
Une structure est appelée record (enregistrement) en Pascal. Ce type regroupe plusieurs données, chacune portant un nom. Elle ne nécessite pas d'allocation de mémoire particulière, au contraire des objets (type class
).
Exemple[modifier | modifier le wikicode]
type
point = record
x , y : integer ;
end record;
Une variable de ce type :
var point_depart : point;
possède deux membres accessibles par l'opérateur point ( .
) :
point_depart.x := 10;
point_depart.y := 15;
![]() |
Vous avez la permission de copier, distribuer et/ou modifier ce document selon les termes de la licence de documentation libre GNU, version 1.2 ou plus récente publiée par la Free Software Foundation ; sans sections inaltérables, sans texte de première page de couverture et sans texte de dernière page de couverture. |