Guide de programmation en Pascal

Il ne faut pas considérer ce guide comme le Saint Graal de la programmation mais comme une ligne de conduite possible : il vise à éviter de trop nombreuses erreurs récurrentes en TP ou en projet.

Variables

Le nom des variables, constantes ou des procédure/fonctions doit être en adéquation avec leur fonction/rôle. Par exemple, on appelera "compteur" une variable compteur et non pas "c".

Constantes

Eviter les noms trop simples comme "n", choisir par exemple "N_MAX". Ecrire ces constantes en majuscules (même si le pascal ne fait pas la différence) est un bon moyen de les repérer dans le code.

Place du bloc de variables globales

Il faut placer le bloc de variables globales juste avant le begin du programme principal et ceci afin d'éviter d'utiliser des variables globales dans les procédures/fonctions : celles-ci peuvent être ainsi réutilisées plus facilement avec un simple copier/coller de code. Il n'y a pas de surcharge de nom de variable (un variable locale prend toujours le pas sur la variable globale), source d'erreur fréquente.

Cette règle admet tout de même des exceptions : une variable globale "ERREUR" peut être visible dans tout le programme... (comme IOResult par exemple). En général, la variable "ERREUR" ne prendra que des valeurs prédéfinies (dans le bloc const) : "ERREUR_LECTURE".

Pointeurs

* Tous les pointeurs doivent être initialisés à "nil" (sauf s'ils sont utlisés tout de suite)

* Les opérations sur les pointeurs doivent être parfaitement maîtrisées, il ne faut pas hésiter à faire de petits dessins.

* Chaque emplacement de mémoire alloué doit être libéré. En particulier, à la fin de l'éxécution d'un programme, il faut vérifier que toute la mémoire a été rendue.

Commentaires

Les commentaires sont très importants dans un programme même s'ils donnent l'impression de rallonger inutilement la taille de fichier. Il peut y avoir une sélection :
un commentaire {incrémente le variable i} pour l'instruction inc(i) est parfaitement inutile.

Il faut soigner les commentaires pour les procédures ou fonctions. Une légère description de ce que la fcontion/procédure réalise est la bien venue, un glossaire sur les paramètres aussi. Si le temps manque ou si l'on estime que le nom des variables est suffisant pour la compréhension, il faut au moins décrire les variables de sortie : c'est-à-dire les variables passées par adresse (précédées par le fameux "var") et le résultat de la fonction.

 

{
EchangeConditionnel : échange les opérandes op1 et op2 si op1>op2 et retourne true si l'échange à eu lieu
PARAMETRES
op1,
op2 : opérandes à échanger éventuellement. En sortie, on aura op1<op2
RETOURNE true si l'échange a eu lieu , false sinon
}

fonction echangeConditionnel(var op1, op2 : operande) : boolean

Bonnes idées

Les "énumérations"

Regardons le code suivant :

function resultat(a : string) : boolean
begin
... if a='normal' then resultat := false else
......if a='essai' then resultat := true else
.........resultat := false;
end;

Cette fonction renvoie "true" si la chaîne de caractères passée en paramètre vaut 'essai' et 'false' dans les autres cas. Lister "tous" les cas possibles pour le résultat est une mauvaise idée, en particulier si cette liste est longue. En général, on fixera une valeur par défaut et on listera le moins de cas possibles.

function resultat(a : string) : boolean
begin
...resultat := false;
...if a = 'essai' then resultat := true;
end;

Récursivité :

La récursivité est un concept formidable pour la compréhension de certains phénomènes mais en programmation, elle est souvent à éviter. En effet, chaque appel récursif est coûteux : temps d'appel de la fonction elle-même, les arguments sont empilés dans la pile : cela prend aussi du temps et la pile peut déborder. Pour conclure, cela veut dire que l'on évite d'abuser de la récursivité au profit des versions itératives des mêmes algorithmes.

Comparaison de deux réels

Sur un ordinateur, les réels ne vérifient plus les propriétés élémentaires qui définissent un "corps". Cela implique en particulier qu'il faut faire très attention lors de la comparaison de deux réels.

Ainsi, il ne faudra pas écrire a=b pour tester l'égalité mais abs(a-b)<e où e est une valeur positive petite : il faut autoriser une certaine marge d'erreur pour la comparaison.

Les fichiers typés passés en paramètres

analysons le code suivant :

type t_fichier : file of real;

procedure lire (var fic : t_fichier)
var r : real;
begin
...while not(eof(fic)) do begin
......read(fic,r);
......writeln(r);
...end;
end;

Cette procédure lit un fichier de réels pour les afficher à l'écran, non ?? Les reproches que l'on peut faire à cette procédure est que l'on a aucune information sur le fichier à lire :

* est- ce que le fichier a été correctement défini ? (assign correct)

* est-ce que le fichier est déjà ouvert ou déjà refermé ? est si oui, est-ce que le pointeur de fichier est placé là où on pense qu'il est (en général, au début)

* et dans le cas, où le fichier est ouvert en écriture, est-ce que les données ont bien été écrites ? Ce ui, je le rapelle, n'arrive que lorsque la mémoire tampon d'entrée-sortie est pleine ou que le fichier est explicitement fermé.

Pour répondre, de manière naturelle à toutes ces questions, il faut essayer de maintenit une unité logique : ainsi, on évitera au possible de passer des fichiers typés en paramètre au profit de leur nom, ce qui donne :

type t_fichier : file of real;

procedure lire (nom : string)
var
...r : real;
...fic : t_fichier
begin
...assign(fic, nom);
... reset(fic);
...while not(eof(fic)) do begin
......read(fic,r);
......writeln(r);
...end;
...close(fic);
end;

Présentation du programme

C'est un point délicat, chaque programmeur a un style différent même si ceux du C++/Java font souvent référence.

Il faut d'abord éviter de se servir de la tabulation et abuser de la touche espace. Pour ma part, je préconise une indentation de trois caractères.

program ?????;

type
... tableau : array [1..10] or real;

procedure rien;
begin
...
...
end;

var
... t : tableau;

begin
...
...
...
end;

Le bloc IF est représenté ainsi

if (test) then begin
...instruction1;
...instruction2;
...end
else begin
...instruction3;
...instruction4;
...end
end;

Le bloc WHILE

while (test) do begin
...instruction1;
...instruction2;
end;