next up previous contents index
suivant: 4. Les entrées-sorties monter: perl précédent: 2. Structures de données   Table des matières   Index

Sous-sections


3. Syntaxe et structures de contrôle

3.1 Syntaxe

Un script perl consiste en une suite de déclarations. Toutes les variables utilisateur non initialisées sont considérées comme nulles (undefined, la valeur 0 ou la chaîne "", suivant la fonction que vous appliquez).

Les commentaires sont introduits par le caractère #, et s'étendent jusqu'à la fin de la ligne. Il existe également un système de documentation plus évoluée, intégré au langage, connu sous le nom de POD (Plain Old Documentation), qui est traité dans le chapitre 7.

La première ligne du script doit contenir le chemin d'accès à l'interpréteur, soit (expression à modifier suivant la localisation de votre interpréteur) :

#! /usr/local/bin/perl

3.1.1 Commandes simples

Chaque commande doit être terminée par un point-virgule ;. Elle peut être éventuellement suivie d'un modifier3.1 juste avant le ;. Les modifiers possibles sont :

if EXPR
unless EXPR
while EXPR
until EXPR

Par exemple :

print "Test reussi\n" if ($var == 1);

3.1.2 Blocs de commandes

Une séquence de commandes simples constitue un bloc. Un bloc peut être délimité par le fichier qui le contient, mais généralement il est délimité par des accolades {}.


3.2 Structures de contrôle

Les structures de contrôle sont :

if (EXPR) BLOCK
if (EXPR) BLOCK else BLOCK
if (EXPR) BLOCK elsif (EXPR) BLOCK ... else BLOCK
[LABEL] while (EXPR) BLOCK
[LABEL] for (EXPR; EXPR; EXPR) BLOCK
[LABEL] foreach VAR (ARRAY) BLOCK [LABEL] BLOCK continue BLOCK

Attention : contrairement au C, les accolades sont obligatoires même si les blocs ne sont composés que d'une seule commande. Ceci supprime par exemple les ambiguïtés résultant de l'imbrication de plusieurs if. Il est cependant possible d'utiliser la syntaxe vue plus haut ; les exemples suivants sont équivalents :

if (!open(FICHIER, $fichier))
   { die "Impossible d'ouvrir fichier: $!"; }

die "Impossible d'ouvrir $fichier: $!" if (!open(FICHIER, $fichier));

open(FICHIER, $fichier) or die "Impossible d'ouvrir $fichier: $!";

La dernière syntaxe est la plus utilisée dans ce cas précis, elle fait partie des idiomes de perl. N'oubliez jamais de tester la valeur de retour d'une fonction susceptible de ne pas se terminer correctement, et de toujours afficher un message d'erreur le plus précis possible (ici, l'utilisation de la variable spéciale $! permet d'afficher le message standard d'erreur UNIX indiquant la cause du problème). Ce conseil ne s'applique évidemment pas qu'à perl.

3.2.1 La commande while

La commande while exécute le bloc tant que l'expression est vraie. Le LABEL est optionnel. S'il est présent, il consiste en un identificateur, généralement en majuscules, suivi de :. Il identifie la boucle pour les commandes next (équivalent C : continue), last (équivalent C : break) et redo. Il permet ainsi de sortir simplement de plusieurs boucles imbriquées.

BOUCLE:
while ($var == 0)
{
  while ($var2 == 0)
  {
    ...;
    last BOUCLE if ($var3 == 1);
  }
}

3.2.2 La commande for

La commande for a la même syntaxe que son homonyme en C :

for ($i = 1; $i < 10; $i++)
{
  ...;
}

3.2.3 La commande foreach

La commande foreach3.2 va affecter successivement à la variable VAR les éléments du tableau ARRAY. La variable VAR est implicitement locale à la boucle et retrouve sa valeur initiale - si elle existait - à la sortie de la boucle.

Si ARRAY est un tableau réel (et non une liste retournée par exemple par une fonction), il est possible de modifier chaque élément de ce tableau en affectant la variable VAR à l'intérieur de la boucle.

foreach $arg (@ARGV)
{
  print "Argument : ", $arg, "\n";
  # L'action suivante va mettre à zéro les éléments de @ARGV
  # C'est juste pour l'exemple, ne cherchez pas d'utilité à cette action.
  $arg = "";
}


3.2.4 Comment émuler switch ?

Il n'y a pas de commande switch prédéfinie, car il existe plusieurs moyens d'en écrire l'équivalent :

SWITCH: {
  if (EXPR1) { ...; last SWITCH; }
  if (EXPR2) { ...; last SWITCH; }
  if (EXPR3) { ...; last SWITCH; }
  ...;
}

ou encore une suite de if/elsif.


3.3 Les opérateurs de test

Ils reprennent en grande partie la syntaxe du C, également en ce qui concerne les règles de précédence. On se référera à la section perlop du manuel de perl5 [3] pour obtenir la liste complète des opérateurs ainsi que leur précédence.


3.3.1 Les opérateurs classiques

Les opérateurs de perl ne sont pas difficiles à apprendre pour quiconque connait un peu de C, perl s'en inspirant largement.

On peut citer quelques opérateurs :

!, ~, <, >, ||, or, &&, and

La différence entre or et ||, de même qu'entre and et && se situe au niveau de la priorité : and et or sont les éléments de plus faible priorité du langage.

La distinction la plus grande à faire par rapport au C est l'existence d'opérateurs particuliers s'appliquant aux chaînes de caractères. Le tableau 3.1 donne les équivalences entre les opérateurs s'appliquant aux nombres et ceux s'appliquant aux chaînes.


Tableau 3.1: Équivalence des tests nombres-chaînes
Nombres Chaînes Signification
< lt Inférieur à
<= le Inférieur ou égal à
> gt Supérieur à
>= ge Supérieur ou égal à
== eq Égal à
!= ne Différent de
<=> cmp Comparaison


L'opérateur de comparaison (<=> pour les nombre et cmp pour les chaînes) renvoie -1, 0 ou 1 selon que le premier argument est inférieur, égal ou supérieur au second.

Une chose à noter sur les opérateurs || et or : ils n'évaluent que ce qui est nécessaire (c'est-à-dire qu'ils s'arrêtent à la première valeur évaluée à TRUE), et renvoient la dernière valeur évaluée. On peut donc écrire :

$fichier = $ARGV[0] || "defaut.txt";

De même, les opérateurs && et and s'arrêtent à la première valeur évaluée à FALSE :

windows_is_running() && die "Please, execute me on a *REAL* OS...";


3.3.2 Les opérateurs de tests sur les fichiers

Reprenant une des caractéristiques des shells, perl permet d'effectuer simplement différents tests sur les fichiers, sans qu'il soit nécessaire d'invoquer directement la fonction stat.

Chacun de ces opérateurs s'applique soit à un nom de fichier (une chaîne de caractères), soit à un descripteur de fichier (filehandle).

Une liste complète de ces opérateurs de tests est disponible dans la section perlfunc du manuel [3]. Le tableau 3.2 donne les principaux.


Tableau 3.2: Opérateurs de tests sur les fichiers
-r fichier accessible en lecture par la personne qui exécute le script
-w fichier accessible en écriture par la personne qui exécute le script
-x fichier exécutable
-o fichier possédé par la personne qui exécute le script
-e fichier existant
-z fichier de taille nulle
...  
-M âge du fichier en jours à partir de la date d'exécution du script
-s taille du fichier


La plupart de ces opérateurs renvoient un résultat booléen. Les deux derniers renvoient cependant des informations plus précises (l'âge ou la taille du fichier).

$fichier = "/vmunix";
$age = -M $fichier;


3.4 Les fonctions

3.4.1 Déclaration

Les fonctions sont déclarées par le mot-clé sub, suivi par le nom de la fonction, puis le bloc d'instructions correspondant, entre accolades

Le script étant pré-compilé avant d'être interprété, la définition de la fonction peut être effectuée indifféremment avant ou après son appel. Il peut être nécessaire de les déclarer avant (ou de faire une forward declaration à la C) si on utilise le pragma use strict;

Les arguments sont passés dans le tableau @_. On peut définir des variables locales à la fonction grâce aux mots-clés local() ou my().

Le mot-clé return existe, mais est optionnel. S'il n'est pas présent, la fonction retourne la dernière valeur évaluée.

Voici un exemple :

sub factorielle
{
  my $n = shift(@_);
  # ou bien encore
  # my $n = shift;
  # puisque @_ est dans ce cas pris par defaut.

  $n == 1 ? 1 : ( $n * &factorielle($n - 1) );
# équivalent à (notez le return implicite)
# if ($n == 1)
# {
#   1;
# }
# else
# {
#   $n * &factorielle($n - 1);
# }
}

my doit être utilisé de préférence à local, car my donne à la variable une étendue lexicale (lexical scoping), i.e. la variable ne sera pas visible des routines appelées ensuite. Ce n'est pas clair ? Un exemple aidera sûrement :

# On declare quelques fonctions...
sub f_local
{
  local($foo) = "Foo";
  &print_foo();
}
sub f_my
{
  my($foo) = "Bar";
  &print_foo();
}
# Affichage de la valeur de la variable $foo
sub print_foo
{
  print $foo, "\n";
}
# Début du script.
print "Appel avec local sans initialisation globale : ";
&f_local;
print "Appel avec my sans initialisation globale : ";
&f_my;
# Initialisation de la variable de manière globale
$foo = "Toto";
print "Appel avec local avec initialisation globale : ";
&f_local;
print "Appel avec my avec initialisation globale : ";
&f_my;

# Ce qui donne comme résultat a l'exécution :
Appel avec local sans initialisation globale : Foo
Appel avec my sans initialisation globale : 
Appel avec local avec initialisation globale : Foo
Appel avec my avec initialisation globale : Toto

Ça va mieux ? Si la réponse est non, prenez une aspirine, faites-moi confiance et facilitez-vous la vie en utilisant systématiquement my.

3.4.2 Appel

Les noms de fonctions sont précédés du signe &. Ce signe est optionnel lorsqu'on fait appel à une fonction. Il est par contre nécessaire lorsqu'on veut passer une fonction comme paramètre par exemple.

Les parenthèses lors de l'appel ne sont pas obligatoires, même s'il n'y a aucun argument. On peut donc appeler une fonction de plusieurs manières :

&fonction(2, 4);
fonction(2, 4);
# Attention à la suite (man perlsub pour plus de détails):
fonction2();  # fonction2 est appellée avec une liste vide en argument.
&fonction2(); # Idem.  
&fonction2;   # fonction2 est appellée avec la même liste d'arguments
              # que la fonction d'où l'appel est fait. Attention...

3.4.3 Deux fonctions particulières

Il existe deux fonctions particulières, héritées de la syntaxe de awk, qui permettent d'avoir une plus grande maîtrise sur le déroulement du script. Ce sont les fonctions BEGIN et END.

Une fonction BEGIN est exécutée aussitôt que possible, i.e. au moment où elle est complètement définie, avant même que le reste du script ne soit analysé. S'il y a plusieurs définitions de BEGIN, elles seront exécutées dans l'ordre de leur déclaration.

Cette fonction est utilisée en particulier pour modifier le chemin de recherche des fichiers à inclure (voir le chapitre 13 sur les variables spéciales) :

BEGIN
{
  push(@INC, "/home/aubert/lib/perl");
}
# que l'on écrit plutôt à partir de la version 5.001m
# use lib '/home/aubert/lib/perl';

La fonction END est exécutée le plus tard possible, généralement juste avant la sortie de l'interpréteur. Elle permet donc de faire un peu de ménage à la fin d'un programme.


3.5 Les paquetages

perl offre un moyen de protéger les variables d'un éventuel conflit de nom grâce au mécanisme des paquetages (ou encore espaces de nommage).

Un paquetage est déclaré par le mot-clé package, suivi du nom du paquetage, et s'étend jusqu'à la fin du bloc (ou du fichier, les paquetages étant généralement définis chacun dans leur propre fichier) ou à la prochaine déclaration de paquetage..

On accède ensuite depuis l'extérieur aux variables et aux fonctions du paquetage en les précédant du nom du paquetage suivi de ::. Il est possible de subdiviser les paquetages en sous-paquetages, ad nauseam.

Le paquetage principal est appelé main.

Voici un exemple :

package Arb;
$a = 1;

package main;
$a = 2;
print $a, "\n";
# renverra 2
print $Arb::a, "\n";
# renverra 1


3.6 Les modules

3.6.1 Principe

Les modules sont une extension du concept de paquetage : ce sont des paquetages définis dans un fichier de même nom que le module, et qui sont destinés à être réutilisés.

On inclut un module grâce à la ligne suivante :

use Module;

ce qui va en fait être interprété comme

BEGIN {
require "Module.pm";
import Module;
}

use effectue un import en plus du require, ce qui a pour effet d'importer les définitions des fonctions dans l'espace du paquetage courant. Voici l'explication :

require Cwd;                # make Cwd:: accessible
$here = Cwd::getcwd();

use Cwd;                    # import names from Cwd::
$here = getcwd();

require Cwd;                # make Cwd:: accessible
$here = getcwd();           # oops! no main::getcwd()

3.6.2 Modules existants

Une liste complète est régulièrement postée dans les news et archivée sur les sites CPAN (voir l'introduction). Un certain nombre est livré dans la distribution standard de perl, le reste se trouve également sur les sites CPAN.

Les plus importants sont ceux qui permettent de gérer différents formats de bases de données (NDBM_File, GDBM_File, ...), CGI qui fournit une interface très agréable à utiliser lors de l'écriture de scripts CGI,GetCwd qui permet de ne pas avoir à faire un appel à /bin/pwd pour obtenir le répertoire courant, Fcntl qui permet d'accéder aux constantes définies dans fcntl.h, FileHandle qui fournit des méthodes pour accéder aux filehandles, Find qui traverse une arborescence, GetOptions, POSIX qui permet d'accéder aux fonctions POSIX, Tk qui permet de construire des applications graphiques,...


next up previous contents index
suivant: 4. Les entrées-sorties monter: perl précédent: 2. Structures de données   Table des matières   Index
Olivier Aubert 2000-06-28