Cours gratuits » Cours informatique » Cours programmation » Cours Perl » Tutoriel pour apprendre à créer un exécutable à partir de sources Perl

Tutoriel pour apprendre à créer un exécutable à partir de sources Perl

Problème à signaler:

Télécharger



★★★★★★★★★★3.5 étoiles sur 5 basé sur 1 votes.
Votez ce document:

Cours pour apprendre à créer un exécutable à partir de sources Perl

...

2.2          DESCRIPTION

Perl est un langage optimisé pour extraire des informations de fichiers texte et imprimer des rapports basés sur ces informations. C’est aussi un bon langage pour de nombreuses tâches d’administration système. Il est écrit dans le but d’être pratique (simple à utiliser, efficace, complet) plutôt que beau (petit, élégant, minimaliste).

Le Perl combine (du point de vue

de l’auteur) les meilleures fonctionnalités de C, sed, awk et sh, de telle manière que les personnes familiarisées à ces langages ne devraient avoir aucune difficulté avec celui-ci. (Les historiens pourront noter quelques vestiges de csh, Pascal, et même de BASIC-PLUS). La syntaxe se rapproche presque totalement de celle du C. Contrairement à la plupart  des utilitaires Unix, Perl ne limite pas arbitrairement la taille des données – si vous avez assez de mémoire, Perl peut remplir une chaine de caractères avec le contenu total d’un fichier. Il n’y a pas de niveau maximum à la récursivité. Et les tables utilisées par les tableaux de hachage (anciennement appellé "tableaux associatifs") croissent dès que nécessaire afin de garantir un bon niveau de performance. Perl utilise des techniques sophistiquées de recherche de motif pour pouvoir traiter très rapidement de très grandes quantités de données. Bien qu’optimisé pour le traitement des fichiers textes, Perl peut aussi traiter des données binaires, et faire que des fichiers dbm soient vus commes des tableaux de hachage. Les scripts Perl ayant leurs setuid bits positionnés sont plus sûrs que des programmes C grâce à des mécanismes de suivi de flot de données qui permettent d’éviter de nombreux trous de securité particulièrement stupides.

Si vous avez un problème pour lequel vous auriez utilisé sed, awk ou sh, mais qui dépasse leurs capacités ou qui doit fonctionner un peu plus rapidement et que vous ne voulez pas l’écrire en C, alors le Perl est pour vous. Il existe aussi des convertisseurs pouvant transformer vos scripts sed et awk en scripts Perl.

Mais il y a beaucoup plus...

La version 5 de Perl constitue une réécriture presque complète, et introduit les fonctionnalités suivantes :

–             De nombreuses améliorations à l’utilisation

Il est maintenant possible d’écrire du code Perl nettement plus lisible (même dans les expressions régulières). Les variables absconses peuvent être remplacées par des identificateurs plus compréhensibles. Les messages d’erreurs sont plus detaillés, et les messages optionnels d’avertissement devraient indiquer une grande majorité des erreurs peuvant être commises par un novice. On ne le dira jamais assez, mais lorsque vous obtenez un comportement erratique, essayez de lancer votre script avec le modificateur

-w !!! De toutes manières, même si n’avez pas de comportement erratique, essayez d’utiliser le modificateur -w.

–             Une grammaire simplifiée

La taille de la nouvelle grammaire yacc fait environ la moitié de la précédente. Un très grand nombre de règles arbitraires ont été régularisées. Le nombre des mots réservés a été réduit de plus de 2/3. Malgré cela, presque tous les anciens scripts Perl fonctionnent sans aucun changement.

–             Portée lexicale

Les variables Perl peuvent maintenant être déclarées à l’interieur d’une portée lexicale, de la même manière que les variables "auto" en C. Non seulement, c’est plus efficace, mais ça contribue à une plus grande sécurité pour la programmation de code réutilisable. Les routines anonymes disposent ainsi d’un couplage fort des variables locales.

–             Structure de données performantes

N’importe quelle variable scalaire, y compris un élément de tableau, peut maintenant contenir une référence vers une autre variable ou une routine. Il devient simple de créer des variables et routines anonymes. Perl gère pour vous les compteurs de référence.

–             Modularité et réutilisabilité

La bibliothèque Perl est maintenant constituée de modules qui peuvent être partagés facilement entre plusieurs paquetages. Un paquetage peut choisir d’importer tout ou parties de l’interface publiée d’un module. Les pragmas (directives de compilation) sont définis et utilisés par le même mécanisme.

–             Programmation orientée objet

Un paquetage peut fonctionner comme un classe. L’héritage multiple dynamique et les méthodes virtuelles sont supportées de manière très directe et n’introduisent que peu de changements syntaxiques. Les descripteurs de fichiers sont maintenant gérés comme des objets.

–             Intégrable et extensible

Perl peut maintenant être intégré simplement dans vos applications en C ou C++, et peut indifférement appeler ou être appelé par vos routines à travers une interface documentée. Le préprocesseur XS fourni facilite l’intégration de routines en C ou C++ dans une application Perl. Le chargement dynamique de module est supporté, et Perl lui-même peut être transformé en une librairie dynamique.

–             Conforme POSIX

Un apport majeur est la création du module POSIX, qui fournit l’accès à toutes les routines et définitions POSIX, au travers de classes d’objets lorsque c’est approprié.

–             Constructeurs et destructeurs de paquetage

Les nouveaux blocs BEGIN et END sont exécutés lorsque la compilation du paquetage s’achève et juste à la sortie du programme. Ils peuvent être utilisés dans un mode dégradé correspondant à celui du awk en utilisant les modificateurs -p ou -n.

–             De multiples implémentations de DBM en simultané

Un script Perl peut maintenant accéder à des fichiers DBM, NDBM, SDBM, GDBM et Berkeley DB simultanément. En fait, l’ancienne interface dbmopen a été généralisée pour permettre à n’importe quelle variable d’être rattachée à une classe d’objet définissant ses propres méthodes d’accès.

–             Les définitions des routines peuvent desormais être chargées automatiquement

En fait, le mécanisme AUTOLOAD vous permet aussi de définir n’importe quelle sémantique arbitraire pour l’appel de routines indéfinies. Ce n’est pas seulement du chargement automatique.

–             Amélioration des expressions régulières

Vous pouvez maintenant spécifier des quantificateurs qui ne sont pas avides. Il est aussi possible de faire des regroupements sans créer de références. Tout comme vous pouvez ajouter des espacements et des commentaires dans les expressions régulières. Un mécanisme conséquent permettant d’étendre les capacités des expressions régulières a été ajouté mais reste presque entièrement compatible.

–             Une pléthore de modules disponibles

Le CPAN (Comprehensive Perl Archive Network ou Réseau d’archives détaillées de Perl) décrit dans la page de manuel le manuel perlmodlib contient des centaines de modules prêts à l’emploi fournissant une quantité astronomique de code réutilisable. Vous trouverez le site miroir le plus proche de chez vous à l’adresse : 

–             Compilateur

Bien qu’il ne soit pas encore en production, il existe un compilateur Perl-vers-C qui fonctionne. Il peut générer un byte code (code objet) portable, du simple C ou bien du code C optimisé.

D’accord, j’en fini avec le battage publicitaire de Perl.

 2.3. ENVIRONNEMENT perl

2.3          ENVIRONNEMENT

Voir le manuel perlrun.

2.4          AUTEUR

Si vous désirez faire partager votre témoignage sur les succès remportés en utilisant Perl, aidant ainsi ceux qui voudraient recomman- der Perl pour leurs applications, ou tout simplement si vous voulez exprimer votre gratitude à Larry et l’équipe de développement, alors écrivez s’il vous plaît à ...

2.5          FICHIERS

"/tmp/perl-e$$" fichier temporaire pour les commandes -e "@INC"     emplacements des librairies Perl

2.6          VOIR AUSSI

a2p traducteur awk vers perl s2p traducteur sed vers perl

2.7          DIAGNOSTICS

Le modificateur -w génère de magnifiques diagnostics.

Voir le manuel perldiag pour l’explication de tous ces diagnostics. Le pragma use diagnostics oblige Perl à rendre ces messages plus verbeux.

En cas d’erreur de compilation le numéro de la ligne fautive est indiqué ainsi que l’emplacement approximatif du mot concerné. (Dans le cas de script utilisant le modificateur -e, chaque -e est compté comme une ligne.)

Les scripts en setuid ont des contraintes supplémentaires pouvant produire des messages d’erreur tel que "Insecure dependency". Voir le manuel perlsec.

Avons-nous mentionné que vous devriez vraiment penser à utiliser le modificateur -w ?

2.8          BUGS

Le modificateur -w n’est pas obligatoire.

Perl est à la merci de la définition de plusieurs opérations telles que casting, atof() et l’affichage des nombres flottants par sprintf() qui peuvent être différentes sur votre machine.

Si votre stdio nécessite un déplacement (seek) ou une fin de fichier (eof) entre les lectures et les écritures sur des flots de données particuliers, alors Perl les requiert aussi. (Ceci ne s’applique pas à sysread() et syswrite().)

Il n’y a aucune limite en ce qui concerne la taille des types de données prédéfinies (à part la mémoire disponible) mais il existe toujours un petit nombre de limites arbitraires : un nom de variable ne peut dépasser 255 caractères, aucun composant de votre PATH ne doit être plus long que 255 caractères si vous utilisez le modificateur -S. Une expression régulière ne peut dépasser 32767 octets lors de sa compilation.

Si vous envoyez un rapport de bug (assurez-vous d’inclure toutes les informations sur la configuration obtenue par le programme myconfig fourni avec Perl, ou par perl -V) à <perlbug@perl.com>;. Si vous avez réussi à compiler Perl, le script perlbug fourni dans le répertoire utils/ peut être utilisé pour envoyer un rapport de bug.

L’acronyme Perl signifie réellement Pathologically Eclectic Rubbish Lister, mais ne dites à personne que je vous ai dit ça.

4.1          DESCRIPTION

Un script Perl est constitué d’une suite de déclarations et d’instructions.

La séquence d’instructions est exécutée une seule fois, contrairement aux scripts sed et awk, où la séquence est exécutée pour chaque ligne en entrée. Même si cela signifie que vous devez explicitement boucler sur les lignes de votre (ou de vos) fichier(s) d’entrée, cela veut aussi dire que vous avez bien plus de contrôle sur les fichiers et les lignes que vous manipulez (en fait, je mens – il est possible de faire une boucle implicite avec les options -n ou -p. Ce n’est juste pas le comportement par défaut comme avec sed et awk).

Perl est, en majeure partie, un langage à syntaxe libre (La seule exception en est les déclarations de format, pour des raisons évidentes). Le texte situé entre un caractère "#" et la fin de la ligne est un commentaire, et est ignoré. Si vous essayez d’utiliser

/* */ pour des commentaires dans le style du C, ce sera interprété soit comme une division, soit comme un pattern matching, en fonction du contexte, et les commentaires // du C++ auront juste l’air d’une expression régulière nulle, alors ne faites pas cela.

4.1.1      Declarations

Les seules choses que vous devez déclarer en Perl sont les formats de rapport et les sous-programmes – et même des sous- programmes indéfinis peuvent être manipulés via AUTOLOAD. Une variable contient la valeur indéfinie (undef) jusqu’à ce qu’on lui affecte une valeur, qui est n’importe quoi sauf undef. Lorsqu’il est utilisé comme un nombre, undef est traité comme 0; lorsqu’il est utilisé comme une chaîne, il est traité comme la chaîne vide, ""; et lorsqu’il est utilisé comme une référence qui n’a pas été affectée, il est traité comme une erreur. Si vous validez les avertissements, vous serez notifié de l’utilisation d’une valeur non ini- tialisée chaque fois que vous traiterez undef comme une chaîne ou un nombre. En tout cas, habituellement. Les contextes booléens ("je-m’en-moque") et les opérateurs tels que ++, -, +=, -= et .= sont toujours exempts de tels avertissements.

Une déclaration peut être mise partout où une instruction peut trouver place, mais n’a pas d’effet sur l’exécution de la séquence d’instructions principale - les déclarations prennent toutes effet au moment de la compilation. Typiquement, toutes les déclarations sont placées au début ou à la fin du script. Toutefois, si vous utilisez des variables privées de portée lexicales créées avec my(), vous devrez vous assurez que la définition de votre format ou de votre sous-programme est à l’intérieur du même bloc que le my si vous voulez pouvoir accéder à ces variables privées.

La déclaration d’un sous-programme permet à un nom de sous-programme d’être utilisé comme s’il était un opérateur de liste à partir de ce point dans le programme. Vous pouvez déclarer un sous-programme sans le définir en disant sub name, ainsi :

sub myname;

$me = myname $0          or die "can’t get myname";

Notez que my fonctionne comme un opérateur de liste, pas comme un opérateur unaire ; faites donc attention d’utiliser or au lieu de || dans ce cas. Toutefois, si vous déclariez le sous-programme avec sub myname ($), alors myname fonctionnerait comme un opérateur unaire, donc or aussi bien que || feraient l’affaire.

Les déclarations de sous-programmes peuvent aussi être chargées à l’aide de l’instruction require ou bien à la fois chargées et importées dans votre espace de noms via l’instruction use. Voir le manuel perlmod pour plus de détails.

Une séquence d’instructions peut contenir des déclarations de variables de portée lexicale, mais à part pour déclarer un nom de variable, la déclaration fonctionne comme une instruction ordinaire, et est élaborée à l’intérieur de la séquence d’instructions en tant que telle. Cela signifie qu’elle a à la fois un effet à la compilation et lors de l’exécution.

 4.1.2     Instructions Simples

Le seul type d’instruction simple est une expression évaluée pour ses effets de bord. Chaque instruction simple doit être terminée par un point-virgule, à moins qu’elle ne soit la dernière instruction d’un bloc, auquel cas le point-virgule est optionnel (Nous vous encourageons tout de même à placer ce point-virgule si le bloc prend plus d’une ligne, car vous pourriez éventuellement ajouter une autre ligne). Notez qu’il existe des opérateurs comme eval {} et do {} qui ont l’air d’instructions composées, mais qui ne le sont pas (ce sont juste les TERMES d’une expression), et ont donc besoin d’une terminaison explicite s’ils sont utilisés comme dernier élément d’une instruction.

Toute instruction simple peut être suivie de façon optionelle par un UNIQUE modificateur, juste avant le point-virgule de terminaison (ou la fin du bloc). Les modificateurs possibles sont :

if EXPR unless EXPR while EXPR until EXPR foreach EXPR

Les modificateurs if et unless ont la sémantique attendue, en supposant que vous parlez anglais. Le modificateur foreach est un itérateur : il place successivement $_ à chaque valeur de EXPR et exécute l’instruction. Les modificateurs while et until ont la sémantique habituelle "while loop" (la condition est évaluée en premier), sauf lorsqu’ils sont appliqués à un do-BLOC (ou à l’instruction désapprouvée do-SOUS_PROGRAMME), auquel cas le bloc s’exécute une fois avant que la condition ne soit évaluée. C’est ainsi pour que vous puissiez écrire des boucles telles que :

do {

$line = <STDIN>;

...

} until $line eq ".\n";

Voir le titre do dans le manuel perlfunc. Notez aussi que l’instruction de contrôle de boucle décrite plus tard ne fonctionnera pas dans cette construction, car les modificateurs n’utilisent pas de labels de boucle. Désolé. Vous pouvez toujours mettre un autre bloc à l’intérieur (for next) ou autour (for last) pour réaliser ce genre de choses. Pour next, il suffit de doubler les accolades :

do {{

next if $x == $y; # do something here

}} until $x++ > $z;

Pour last, vous devez faire quelque chose de plus élaboré :

LOOP: {

do {

last if $x = $y**2; # do something here

} while $x++ <= $z;

}

4.1.3      Instructions Composées

En Perl, une séquence d’instructions qui définit une portée est appelée un bloc. Un bloc est parfois délimité par le fichier qui le contient (dans le cas d’un fichier requis, ou dans celui du programme en entier), et parfois un bloc est délimité par la longueur d’une chaîne (dans le cas d’un eval).

Mais généralement, un bloc est délimité par des accolades. Nous appellerons cette construction syntaxique un BLOC. Les instructions composées suivantes peuvent être utilisées pour contrôler un flux :

if (EXPR) BLOC

if (EXPR) BLOC else BLOC

if (EXPR) BLOC elsif (EXPR) BLOC ... else BLOC LABEL while (EXPR) BLOC

LABEL while (EXPR) BLOC continue BLOC LABEL for (EXPR; EXPR; EXPR) BLOC LABEL foreach VAR (LIST) BLOC

LABEL foreach VAR (LIST) BLOCK continue BLOCK LABEL BLOC continue BLOC

Notez que, contrairement au C et au Pascal, tout ceci est défini en termes de BLOCs, et non d’instructions. Ceci veut dire que     les accolades sont requises - aucune instruction ne doit traîner. Si vous désirez écrire des conditionnelles sans accolades, il existe plusieurs autres façons de le faire. Les exemples suivants font tous la même chose :

if (!open(FOO)) { die "Can’t open $FOO: $!"; } die "Can’t open $FOO: $!" unless open(FOO);

open(FOO) or die "Can’t open $FOO: $!";           # FOO or bust! open(FOO) ? ’hi mom’ : die "Can’t open $FOO: $!";

# ce dernier est un peu exotique

L’instruction if est directe. Puisque les BLOCs sont toujours entourés d’accolades, il n’y a jamais d’ambiguïté pour savoir à quel

if correspond un else. Si vous utilisez unless à la place de if, le sens du test est inversé.

L’instruction while exécute le bloc tant que l’expression est vraie (son évaluation ne renvoie pas une chaîne nulle ("") ou 0 ou "0"). Le LABEL est optionnel, et s’il est présent, il est constitué d’un identifiant suivi de deux points. Le LABEL identifie la boucle pour les instructions de contrôle de boucle next, last, et redo. Si le LABEL est omis, l’instruction de contrôle de boucle se réfère à la boucle incluse dans toutes les autres. Ceci peut amener une recherche dynamique dans votre pile au moment de l’exécution pour trouver le LABEL. Un comportement aussi désespéré provoque un avertissement si vous utilisez le pragma use warnings ou l’option -w. Contrairement à une instruction foreach, une instruction while ne localise jamais implicitement une variable.

S’il existe un BLOC continue, il est toujours exécuté juste avant que la condition ne soit à nouveau évaluée, de la même manière que la troisième partie d’une boucle for en C. Il peut ainsi être utilisé pour incrémenter une variable de boucle, même lorsque la boucle a été continuée via l’instruction next (qui est similaire à l’instruction continue en C).

4.1.4      Contrôle de Boucle

La commande next a le même rôle que l’instruction continue en C ; elle démarre la prochaine itération de la boucle :

LINE: while (<STDIN>) {

next LINE if /^#/;            # elimine les commentaires

...

}

La commande last est identique à l’instruction break en C (telle qu’elle est utilisée dans les boucles) ; elle sort immédiatement de la boucle en question. Le bloc continue, s’il existe, n’est pas exécuté :

LINE: while (<STDIN>) {

last LINE if /^$/;               # sort quand on en a fini avec l’en-tete

...

}

La commande redo redémarre le bloc de la boucle sans réévaluer la condition. Le bloc continue, s’il existe, n’est pas exécuté. Cette commande est normalement utilisée par les programmes qui veulent se mentir à eux-mêmes au sujet de ce qui vient de leur être fourni en entrée.

Par exemple, lors du traitement d’un fichier comme /etc/termcap. Si vos lignes en entrée sont susceptibles de se terminer par un antislash pour indiquer leur continuation, vous pouvez vouloir poursuivre et récupérer l’enregistrement suivant.

while (<>) { chomp;

if (s/\\$//) {

$_ .= <>;

redo unless eof();

}

# now process $_

}

qui est le raccourci Perl pour la version plus explicite :

LINE: while (defined($line = <ARGV>)) { chomp($line);

if ($line =~ s/\\$//) {

$line .= <ARGV>;

redo LINE unless eof(); # pas eof(ARGV)!

}

# now process $line

}

Notez que s’il y avait un bloc continue dans le code ci-dessus, il serait exécuté même pour les lignes rejetées. Ceci est souvent utilisé pour réinitialiser les compteurs de lignes ou les recherches de motifs ?pat?.

# inspire par :1,$g/fred/s//WILMA/ while (<>) {

?(fred)?               && s//WILMA $1 WILMA/;

?(barney)? && s//BETTY $1 BETTY/;

?(homer)?          && s//MARGE $1 MARGE/;

} continue {

print "$ARGV $.: $_";

close ARGV if eof();       # reinitialise $.

reset     if eof(); # reinitialise ?pat?

}

Si le mot while est remplacé par le mot until, le sens du test est inversé, mais la condition est toujours testée avant la première itération.

Les instructions de contrôle de boucle ne fonctionnent pas dans un if ou dans un unless, puisque ce ne sont pas des boucles. Vous pouvez toutefois doubler les accolades pour qu’elles le deviennent.

if (/pattern/) {{ next if /fred/; next if /barney/;

# mettre quelque chose ici

}}

La forme while/if BLOC BLOC, disponible en Perl 4, ne l’est plus. Remplacez toutes les occurrences de if BLOC par if (do BLOC).

4.1.5      Boucles For

Les boucles for de Perl dans le style de C fonctionnent exactement de la même façon que les boucles while correspondantes ; cela signifie que ceci :

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

...

}

est la même chose que ça :

$i = 1;

while ($i < 10) {

...

} continue {

$i++;

}

(Il existe une différence mineure : la première forme implique une portée lexicale pour les variables déclarées avec my dans l’expres- sion d’initialisation).

En plus du bouclage classique dans les indices d’un tableau, for peut se prêter à de nombreuses autres applications intéressantes. En voici une qui évite le problème que vous rencontrez si vous testez explicitement la fin d’un fichier sur un descripteur de fichier interactif, ce qui donne l’impression que votre programme se gèle.

$on_a_tty = -t STDIN && -t STDOUT;

sub prompt { print "yes? " if $on_a_tty } for ( prompt(); <STDIN>; prompt() ) {

# faire quelque chose ici

}

 4.1.6     Boucles Foreach

La boucle foreach itère sur une liste de valeurs normale et fixe la variable VAR à chacune de ces valeurs successivement. Si la variable est précédée du mot-clé my, alors elle a une portée limitée du point de vue lexical, et n’est par conséquent visible qu’à l’intérieur de la boucle. Autrement, la variable est implicitement locale à la boucle et reprend sa valeur précédente à la sortie de    la boucle. Si la variable était précédemment déclaré par my, elle utilise cette variable au lieu de celle qui est globale, mais elle est toujours locale à la boucle.

Le mot-clé foreach est en fait un synonyme du mot-clé for, vous pouvez donc utiliser foreach pour sa lisibilité ou for pour sa concision (Ou parce que le Bourne shell vous est plus familier que csh, vous rendant l’utilisation de for plus naturelle). Si VAR est omis, $_ est fixée à chaque valeur. Si un élément de LIST est une lvalue, vous pouvez la modifier en modifiant VAR à l’intérieur de la boucle. C’est parce que la variable d’index de la boucle foreach est un alias implicite de chaque élément de la liste sur laquelle vous bouclez.

Si une partie de LIST est un tableau, foreach sera très troublé dans le cas où vous lui ajouteriez ou retireriez des éléments à l’intérieur de la boucle, par exemple à l’aide de splice. Ne faites donc pas cela.

foreach ne fera probablement pas ce que vous désirez si VAR est une variable liée ou une autre variable spéciale. Ne faites pas cela non plus.

Exemples :

for (@ary) { s/foo/bar/ } for my $elem (@elements) {

$elem *= 2;

}

for $count (10,9,8,7,6,5,4,3,2,1,’BOOM’) {

print $count, "\n"; sleep(1);

}

for (1..15) { print "Merry Christmas\n"; }

foreach $item (split(/:[\\\n:]*/, $ENV{TERMCAP})) { print "Item: $item\n";

}

Voici comment un programmeur C pourrait coder un algorithme en Perl :

for (my $i = 0; $i < @ary1; $i++) { for (my $j = 0; $j < @ary2; $j++) {

if ($ary1[$i] > $ary2[$j]) {

last; # ne peut pas sortir totalement :-(

}

$ary1[$i] += $ary2[$j];

}

# voici l’endroit ou ce last m’emmene

}

Tandis que voici comment un programmeur Perl plus à l’aise avec l’idiome pourrait le faire :

OUTER: for my $wid (@ary1) { INNER:   for my $jet (@ary2) {

next OUTER if $wid > $jet;

$wid += $jet;

}

}

Vous voyez à quel point c’est plus facile ? C’est plus propre, plus sûr, et plus rapide. C’est plus propre parce qu’il y a moins de bruit. C’est plus sûr car si du code est ajouté entre les deux boucles par la suite, le nouveau code ne sera pas exécuté accidentellement. Le next itère de façon explicite sur l’autre boucle plutôt que de simplement terminer celle qui est à l’intérieur. Et c’est plus rapide parce que Perl exécute une instruction foreach plus rapidement qu’une boucle for équivalente.

4.1.7      BLOCs de Base et Instruction Switch

Un BLOC en lui-même (avec ou sans label) est d’un point de vue sémantique, équivalent à une boucle qui s’exécute une fois. Vous pouvez donc y utilisez n’importe quelle instruction de contrôle de boucle pour en sortir ou le recommencer (Notez que ce n’est PAS vrai pour les blocs eval{}, sub{}, ou do{} contrairement à la croyance populaire, qui NE comptent PAS pour des boucles). Le bloc continue est optionnel.

La construction de BLOC est particulièrement élégante pour créer des structures case.

SWITCH: {

if (/^abc/) { $abc = 1; last SWITCH; } if (/^def/) { $def = 1; last SWITCH; } if (/^xyz/) { $xyz = 1; last SWITCH; }

$nothing = 1;

}

Il n’y a pas d’instruction switch officielle en Perl, car il existe déjà plusieurs façons d’écrire l’équivalent. Vous pourriez écrire à la place de ce qui précède :

SWITCH: {

$abc = 1, last SWITCH if /^abc/;

$def = 1, last SWITCH if /^def/;

$xyz = 1, last SWITCH if /^xyz/;

$nothing = 1;

}

(Ce n’est pas aussi étrange que cela en a l’air une fois que vous avez réalisé que vous pouvez utiliser des "opérateurs" de contrôle de boucle à l’intérieur d’une expression, c’est juste l’opérateur virgule, normal en C).

ou

SWITCH: {

/^abc/ && do { $abc = 1; last SWITCH; };

/^def/ && do { $def = 1; last SWITCH; };

/^xyz/ && do { $xyz = 1; last SWITCH; };

$nothing = 1;

}

ou formaté de façon à avoir un peu plus l’air d’une instruction switch "convenable" :

SWITCH: {

/^abc/  && do {

$abc = 1; last SWITCH;

};

/^def/  && do {

$def = 1; last SWITCH;

};

/^xyz/  && do {

$xyz = 1; last SWITCH;

};

$nothing = 1;

}

ou

SWITCH: {

/^abc/ and $abc = 1, last SWITCH;

/^def/ and $def = 1, last SWITCH;

/^xyz/ and $xyz = 1, last SWITCH;

$nothing = 1;

}

or même, horreur,

if (/^abc/)

{ $abc = 1 } elsif (/^def/)

{ $def = 1 } elsif (/^xyz/)

{ $xyz = 1 } else

{ $nothing = 1 }

Un idiome courant pour une instruction switch est d’utiliser l’aliasing de foreach pour effectuer une affectation temporaire de $_

pour une reconnaissance pratique des cas :

SWITCH: for ($where) {

/In Card Names/             && do { push @flags, ’-e’; last; };

/Anywhere/      && do { push @flags, ’-h’; last; };

/In Rulings/        && do {                last; }; die "unknown value for form variable where: ‘$where’";

}

Une autre approche intéressante de l’instruction switch est de s’arranger pour qu’un bloc do renvoie la valeur correcte :

$amode = do {

if             ($flag & O_RDONLY) { "r" }          # XXX : n’est-ce pas 0? elsif ($flag & O_WRONLY) { ($flag & O_APPEND) ? "a" : "w" } elsif  ($flag & O_RDWR)    {

if ($flag & O_CREAT) { "w+" }

else       { ($flag & O_APPEND) ? "a+" : "r+" }

}

};

ou

print do {

($flags & O_WRONLY) ? "write-only"     :

($flags & O_RDWR)        ? "read-write"  :

"read-only";

};

Ou si vous êtes certain que toutes les clauses && sont vraies, vous pouvez utiliser quelque chose comme ceci, qui "switche" sur la valeur de la variable d’environnement HTTP_USER_AGENT.

#!/usr/bin/perl

# choisir une page du jargon file selon le browser

...

Ce type d’instruction switch ne fonctionne que lorsque vous savez que les clauses && seront vraies. Si vous ne le savez pas, l’exemple précédent utilisant ?: devrait être utilisé.

Vous pourriez aussi envisager d’écrire un hachage de références de sous-programmes au lieu de synthétiser une instruction switch.

4.1.8      Goto

Bien que cela ne soit pas destiné aux âmes sensibles, Perl supporte une instruction goto. Il en existe trois formes : goto-LABEL, goto-EXPR, et goto-&NAME. Un LABEL de boucle n’est pas en vérité une cible valide pour un goto; c’est juste le nom de la boucle.

La forme goto-LABEL trouve l’instruction marquée par LABEL et reprend l’exécution à cet endroit. Elle ne peut pas être utilisée pour aller dans une structure qui nécessite une initialisation, comme un sous-programme ou une boucle foreach. Elle ne peut pas non plus être utilisée pour aller dans une structure très optimisée. Elle peut être employée pour aller presque n’importe où ailleurs à l’intérieur de la portée dynamique, y compris hors des sous-programmes, mais il est habituellement préférable d’utiliser une autre construction comme last ou die. L’auteur de Perl n’a jamais ressenti le besoin d’utiliser cette forme de goto (en Perl, à vrai dire - C est une toute autre question).

La forme goto-EXPR attend un nom de label, dont la portée sera résolue dynamiquement. Ceci permet des gotos calculés à la mode de FORTRAN, mais ce n’est pas nécessairement recommandé si vous optimisez la maintenance du code :

goto(("FOO", "BAR", "GLARCH")[$i]);

La forme goto-&NAME est hautement magique, et substitue au sous-programme en cours d’exécution un appel au sous-programme nommé. C’est utilisé par les sous-programmes AUTOLOAD() qui veulent charger une autre routine et prétendre que cette autre routine a été appelée à leur place (sauf que toute modification de @_ dans le sous-programme en cours est propagée à l’autre routine). Après le goto, même caller() ne pourra pas dire que cette routine n’a pas été appelée en premier.

Dans presque tous les cas similaires, une bien, bien meilleure idée est d’utiliser les mécanismes de contrôle de flux structurés comme next, last, ou redo au lieu de s’en remettre à un goto. Pour certaines applications, la paire eval{} - die() pour le traitement des exceptions peut aussi être une approche prudente.

4.1.9      POD : Documentation Enfouie

Perl dispose d’un mécanisme pour mélanger de la documentation avec le code source. Lorsqu’il s’attend au début d’une nouvelle instruction, si le compilateur rencontre une ligne commençant par un signe égal et un mot, comme ceci

=head1 Here There Be Pods!

Alors ce texte et tout ce qui suit jusqu’à et y compris une ligne commençant par =cut sera ignoré. Le format du texte en faisant partie est décrit dans le manuel perlpod.

Ceci vous permet de mélanger librement votre code source et votre documentation, comme dans

=item snazzle($)

La fonction snazzle() se comportera de la facon la plus spectaculaire que vous pouvez imaginer, y compris la pyrotechnie cybernetique.

=cut retour au compilateur, nuff of this pod stuff! sub snazzle($) {

my $thingie = shift;

.........

}

Notez que les traducteurs pod ne devraient traiter que les paragraphes débutant par une directive pod (cela rend leur analyse plus simple), tandis que le compilateur sait en réalité chercher des séquences pod même au milieu d’un paragraphe. Cela veut que le matériel secret qui suit sera ignoré à la fois par le compilateur et les traducteurs.

$a=3;

=truc secret

warn "Neither POD nor CODE!?"

=cut back

print "got $a\n";

Vous ne devriez probablement pas vous reposer sur le fait que le warn() sera ignoré pour toujours. Les traducteurs pod ne sont pas tous bien élevés de ce point de vue, et le compilateur deviendra peut-être plus regardant.

On peut aussi utiliser des directives pod pour mettre rapidement une partie de code en commentaire.

 4.2. VERSION FRANÇAISE           perlsyn

4.1.10    Bons Vieux Commentaires (Non !)

À la manière du préprocesseur C, Perl peut traiter des directives de ligne. Avec cela, on peut contrôler l’idée que Perl se fait des noms de fichiers et des numéros de ligne dans les messages d’erreur ou dans les avertissements (en particulier pour les chaînes traitées par eval()). La syntaxe de ce mécanisme est la même que pour pour la plupart des préprocesseurs C : elle reconnaît l’expression régulière /ˆ# s*line s+( d+) s*(?: s"([ˆ"]*)")?/ s*$/ où $1 est le numéro de la prochaine ligne, et $2 le nom de fichier optionnel (spécifié entre apostrophes).

Voici quelques exemples que vous devriez pouvoir taper dans votre interpréteur de commandes :

% perl

# line 200 "bzzzt"

# the ‘#’ on the previous line must be the first char on line die ’foo’;

    END 

foo at bzzzt line 201.

% perl

# line 200 "bzzzt"

eval qq[\n#line 2001 ""\ndie ’foo’]; print $@;

    END 

foo at - line 2001.

% perl

eval qq[\n#line 200 "foo bar"\ndie ’foo’]; print $@;

    END 

foo at foo bar line 200.

% perl

# line 345 "goop"

eval "\n#line " . LINE . ’ "’ . FILE ."\"\ndie ’foo’"; print $@;

    END 

Chapitre 5

perldata – Types de données de Perl

Types de données de Perl

5.1          DESCRIPTION

5.1.1      Noms des variables

Perl a trois types de données intégrés : les scalaires, les tableaux de scalaires, et les tableaux associatifs de scalaires, appelés

« hachages ». Les tableaux normaux sont des listes ordonnées de scalaires indexées par des nombres, en commençant par 0 et      où les indices négatifs sont comptés depuis la fin. Les tables de hachages sont des collections non ordonnées de valeurs scalaires indexées par des chaînes qui sont leurs clés associées.

On fait habituellement référence aux valeurs par leur nom, ou par une référence nommée. Le premier caractère du nom vous indique à quel type de structure de données il correspond. Le reste du nom vous dit à quelle valeur particulière il fait référence. Habituellement, ce nom est un simple identifiant, c’est-à-dire une chaîne commençant par une lettre ou un caractère souligné, et contenant des lettres, des soulignés, et des chiffres. Dans certains cas, il peut être une chaîne d’identifiants, séparés par :: (ou par le légèrement archaïque ’) ; tous sauf le dernier sont interprétés comme des noms de paquetages, pour localiser l’espace de nommage dans lequel l’identifiant final doit être recherché (voir le titre Paquetages dans le manuel perlmod pour plus de détails). Il est possible de substituer à un simple identifiant une expression qui produit une référence à la valeur lors de l’exécution. Ceci est décrit plus en détails plus bas, et dans le manuel perlref.

Perl a aussi ses propres variables intégrées dont les noms ne suivent pas ces règles. Elles ont des noms étranges pour qu’elles ne rentrent pas accidentellement en collision avec l’une de vos variables normales. Les chaînes qui correspondent aux parties entre parenthèses d’une expression rationnelle sont sauvées sous des noms qui ne contiennent que des chiffres après le $ (voir le manuel perlop et le manuel perlre). De plus, plusieurs variables spéciales qui ouvrent des fenêtres dans le fonctionnement interne de Perl ont des noms contenant des signes de ponctuation et des caractères de contrôle. Elles sont décrites dans le manuel perlvar.

Les valeurs scalaires sont toujours désignées par un ’$’, même si l’on se réfère à un scalaire qui fait partie d’un tableau ou d’un hachage. Le symbole ’$’ fonctionne d’un point de vue sémantique comme les mots « le », « la ». Ainsi, nous avons :

$days    # la simple valeur scalaire "days"

$days[28]            # le 29ème élément du tableau @days

$days{’Feb’}      # la veleur ’Feb’ dans le hachage %days

$#days # le dernier indice du tableau @days

Les tableaux complets (et les tranches de tableaux ou de hachage sont dénotés par ’@’, qui fonctionne plutôt comme le mot « ces , en ce sens qu’il indique que des valeurs multiples sont attendues :

@days                  # ($days[0], $days[1],... $days[n]) @days[3,4,5]              # identique à ($days[3],$days[4],$days[5]) @days{’a’,’c’}                                   # identique à ($days{’a’},$days{’c’})

Les hachages complets sont dénotés par ’%’ :

%days   # (clé1, valeur1, clé2, valeur2 ...)

De plus, les sous-programmes sont nommés avec un ’&’ initial, bien que ce soit optionnel lorsqu’il n’y a pas d’ambiguïté, tout comme « faire » est souvent redondant en français. Les entrées des tables de symboles peuvent être nommées avec un ’*’ initial, mais vous ne vous souciez pas vraiment de cela pour le moment (si jamais :-).

Chaque type de variable a son propre espace de nommage, tout comme les identifiants de plusieurs types autres que les variables. Ceci signifie que vous pouvez, sans craindre un conflit, utiliser le même nom pour une variable scalaire, un tableau, ou un hachage – ou, pour cette affaire, un handle de fichier, un handle de répertoire, un nom de sous-programme, ou un label. Ceci veut dire que $foo et @foo sont deux variables différentes. Ceci veut aussi dire que $foo[1] fait partie de @foo, et pas de $foo. Cela peut sembler un peu étrange, mais c’est normal, puisque c’est étrange.

Puisque les références de variables commencent toujours par ’$’, ’@’, ou ’%’, les mots « réservés » ne sont en fait pas réservés en ce qui concerne les noms de variables (Ils SONT toutefois réservés en ce qui concerne les labels et les handles de fichiers, qui n’ont pas de caractère spécial initial. Vous ne pouvez pas avoir un handle de fichier nommé « log », par exemple. Indice : vous pourriez dire open(LOG,’logfile’) plutôt que open(log,’logfile’). Utiliser des handles de fichiers en lettres majuscules améliore aussi la lisibilité et vous protège de conflits avec de futurs mots réservés. La casse est significative – « FOO », « Foo », et « foo » sont tous des noms différents. Les noms qui commencent par une lettre ou un caractère souligné peuvent aussi contenir des chiffres et des soulignés.

Il est possible de remplacer un tel nom alphanumérique par une expression qui retourne une référence au type approprié. Pour une description de ceci, voir le manuel perlref.

Les noms qui commencent par un chiffre ne peuvent contenir que des chiffres. Les noms qui ne commencent pas par une lettre, un souligné ou un chiffre sont limités à un caractère, e.g., $% or $$ (La plupart de ces noms d’un seul caractère ont une signification prédéfinie pour Perl. Par exemple, $$ est l’id. du processus courant).

5.1.2      Contexte

L’interprétation des opérations et des valeurs en Perl dépend parfois des exigences du contexte de l’opération ou de la valeur. Il existe deux contextes majeurs : le contexte de liste et le contexte scalaire. Certaines opérations retournent des valeurs de liste dans les contextes qui réclament une liste, et des valeurs scalaires autrement Ssi ceci est vrai pour une opération alors cela sera mentionné dans la documentation pour cette opération. En d’autres termes, Perl surcharge certaines opérations selon que la valeur de retour attendue est singulière ou plurielle. Certains mots en français fonctionnent aussi de cette façon, comme « lys » et « dos ».

Réciproquement, une opération fournit un contexte scalaire ou de liste à chacun de ses arguments. Par exemple, si vous dites :

int( <STDIN> )

L’opération int fournit un contexte scalaire pour l’opérateur <STDIN>, qui répond en lisant une ligne depuis STDIN et en la passant à l’opération int, qui trouvera alors la valeur entière de cette ligne et retournera cela. Si, au contraire, vous dites :

sort( <STDIN> )

alors l’opération sort fournit un contexte de liste pour <STDIN>, qui se mettra à lire toutes les lignes disponibles jusqu’à la fin du fichier, et passera cette liste de lignes à la routine de tri, qui triera alors ces lignes et les retournera en tant que liste à ce qui est le contexte de sort, quel qu’il soit.

L’affectation est un petit peu spéciale en ce sens qu’elle utilise son argument gauche pour déterminer le contexte de l’argument droit. L’affectation à un scalaire évalue la partie droite dans un contexte scalaire, tandis que l’affectation à un tableau ou à un hachage évalue la partie droite dans un contexte de liste. L’affectation à une liste (ou à une tranche, qui est juste une liste de toute façon) évalue aussi la partie droite dans un contexte de liste.

Lorsque vous utilisez le pragma use warnings ou l’option de ligne de commande -w de Perl, il arrive que vous voyiez des aver- tissements sur un usage inutile de constantes ou de fonctions dans un « contexte vide » (« void context », NDT). Le contexte vide signifie juste que la valeur a été abandonnée, comme pour une instruction ne contenant que "fred"; ou getpwuid(0);. Il compte toujours pour un contexte scalaire pour les fonctions qui se soucient de savoir si elles sont ou non appelées dans un contexte scalaire.

Les sous-programmes définis par l’utilisateur peuvent se soucier d’avoir été appelés dans un contexte vide, scalaire ou de liste. La plupart des sous-programmes n’en ont toutefois pas besoin. C’est parce que les scalaires et les listes sont automatiquement interpolés en listes. Voir le titre wantarray dans le manuel perlfunc pour une façon dont vous pourriez discerner dynamiquement le contexte d’appel de votre fonction.

5.1.3      Valeurs scalaires

Toute donnée en Perl est un scalaire, un tableau de scalaires ou un hachage de scalaires. Les variables scalaires peuvent contenir des une seule valeur de trois formes différentes : un nombre, une chaîne ou une référence. En général, la conversion d’une forme à une autre est transparente. Bien qu’un scalaire ne puisse pas contenir des valeurs multiples, il peut contenir une référence à un tableau ou à un hachage qui à son tour contient des valeurs multiples.

Les scalaires ne sont pas nécessairement une chose ou une autre. Il n’y a pas d’endroit où déclarer qu’une variable scalaire doit être de type « chaîne », de type « nombre », de type « référence », ou n’importe quoi d’autre. Du fait de la conversion automatique des scalaires, les opérations qui en retournent n’ont pas besoin de se soucier (et en fait ne le peuvent pas) de savoir si leur appelant attend une chaîne, un nombre ou une référence. Perl est un langage contextuellement polymorphe dont les scalaires peuvent être des chaînes, des nombres, ou des références (ce qui inclut les objets). Tandis que les chaînes et les nombres sont considérés comme presque la même chose pour pratiquement tous les usages, les références sont des pointeurs au typage fort et impossible à forcer, avec comptage de référence intégré et invocation de destructeur.

Une valeur scalaire est interprétée comme TRUE (VRAIE, NDT) au sens booléen si ce n’est pas une chaîne vide ou le nombre 0 (ou son équivalent sous forme de chaîne, « 0 »). Le contexte booléen est juste un genre spécial de contexte scalaire, où aucune conversion vers une chaîne ou un nombre n’est jamais effectuée.

Il existe en fait deux variétés de chaînes nulles (parfois appelées des chaînes « vides »), l’une définie et l’autre non. La version définie est juste une chaîne de longueur zéro, telle que "". La version non définie est la valeur qui indique qu’il n’existe pas de vraie valeur pour quelque chose, comme lorsqu’il s’est produit une erreur, ou à la fin d’un fichier, ou lorsque vous vous référez à une variable ou à un élément de tableau ou de hachage non initialisé. Bien que dans les anciennes versions de Perl, un scalaire indéfini ait pu devenir défini lorsqu’il était utilisé pour la première fois dans un endroit où une valeur définie était attendue, cela ne se produit plus, sauf dans de rares cas d’autovivification tels qu’expliqués dans le manuel perlref. Vous pouvez utiliser l’opérateur defined() pour déterminer si une valeur scalaire est définie (cela n’a pas de sens pour les tableaux ou les hachages), et l’opérateur undef() pour produire une valeur indéfinie.

Pour trouver si une chaîne donnée est un nombre différent de zéro valide, il suffit parfois de la tester à la fois avec le 0 numérique et le « 0 » lexical (bien que ceci provoquera du bruit en provenance de -w). C’est parce que les chaînes qui ne sont pas des nombres comptent comme 0, tout comme en awk :

if ($str == 0 && $str ne "0") {

warn "That doesn’t look like a number";

}

Cette méthode est peut-être meilleure parce qu’autrement vous ne traiteriez pas correctement les notations IEEE comme NaN ou Infinity. À d’autres moments, vous pourriez préférer déterminer si une donnée chaîne peut être utilisée numériquement en appelant la fonction POSIX::strtod() ou en inspectant votre chaîne avec une expression rationnelle (tel que documenté dans le manuel perlre).

warn "has nondigits"     if             /\D/; warn "not a whole number"          unless /^\d+$/;

warn "not an integer"   unless /^[+-]?\d+$/

warn "not a decimal number" unless /^[+-]?\d+\.?\d*$/ warn "not a C float"

unless /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/;

La longueur d’un tableau est une valeur scalaire. Vous pourriez trouver la longueur du tableau @days en évaluant $#days, comme en csh. D’un point de vue technique, ce n’est pas la longueur du tableau ; c’est l’indice de son dernier élément, parce qu’il y a ordinairement un élément numéro 0. Une affectation à $#days change véritablement la longueur du tableau. Le raccourcissement d’un tableau par cette méthode détruit les valeurs intermédiaires. L’agrandissement d’un tableau ayant précédemment été raccourci ne récupère pas les valeurs qui étaient stockées dans ces éléments (c’était le cas en Perl 4, mais nous avons dû supprimer cela pour nous assurer que les destructeurs sont bien appelés quand on s’y attend).

Vous pouvez aussi gagner en efficacité en pré-étendant un tableau qui va devenir gros (vous pouvez aussi étendre un tableau en affectant des données à un élément qui est au-delà de la fin du tableau). Vous pouvez tronquer totalement un tableau en y affectant la liste vide (). Les expressions suivantes sont équivalentes :

@whatever = ();

$#whatever = -1;

Si vous évaluez un tableau dans un contexte scalaire, cela renvoie la longueur du tableau (notez que ceci n’est pas vrai pour les listes, qui renvoient leur dernière valeur, comme l’opérateur virgule en C, et contrairement aux fonctions intégrées, qui renvoient ce qu’elles ont envie de renvoyer). Ce qui suit est toujours vrai :

scalar(@whatever) == $#whatever - $[ + 1;

La version 5 de Perl a changé la sémantique de $[ : les fichiers qui ne fixent pas la valeur de $[ n’ont plus besoin de s’inquiéter de savoir si un autre fichier a changé sa valeur (en d’autres termes, l’usage de $[ est désapprouvé). Donc de façon générale, vous pouvez présumer que

scalar(@whatever) == $#whatever + 1;

Certains programmeurs choisissent d’utiliser une conversion explicite pour ne rien laisser au hasard :

$element_count = scalar(@whatever);

Si vous évaluez un hachage dans un contexte scalaire, vous obtenez faux si le hachage est vide. S’il contient une paire clé/valeur quelconque, il renvoie vrai ; plus précisément, la valeur retournée est une chaîne constituée du nombre de buckets utilisés et du nombre de buckets alloués, séparés par un signe de division. Ceci n’a tendance à être très utile que pour déterminer si les algorithmes de hachage (compilés) en Perl ont des performances médiocres sur vos données. Par exemple, vous mettez 10 000 trucs dans un hachage, mais l’évaluation de %HASH dans un contexte scalaire révèle « 1/16 », ce qui signifie qu’un seul des seize buckets a été touché, et contient probablement tous vos 10 000 éléments. Cela ne devrait pas se produire).

5.1.4      Constructeurs de valeurs scalaires

Les littéraux numériques sont spécifiés dans un quelconque des formats suivants de nombres entiers ou à virgule flottante :

12345

12345.67

.23E-10 # un très petit nombre 4_294_967_296                # souligné pour la lisibilité 0xff  # hexa

0377      # octal

0b011011            # binaire

Les littéraux de chaîne sont habituellement délimités soit par des apostrophes, soit par des guillemets. Ils fonctionnent beaucoup comme dans un shell Unix standard : les littéraux de chaîne entre guillemets sont sujets aux substitutions de variables et au préfixage par barre oblique inverse ; les chaînes entre apostrophes ne le sont pas (sauf pour ’ et ). Les règles habituelles d’utilisation de la barre oblique inverse en C s’appliquent aussi bien pour créer des caractères comme la nouvelle ligne, la tabulation, etc., que sous des formes plus exotiques. Voir le titre Opérateurs apostrophe et type apostrophe dans le manuel perlop pour une liste.

Les représentations hexadécimales, octales ou binaires sous forme de chaînes (e.g. ’0xff’) ne sont pas automatiquement converties sous leur représentation entière. Les fonctions hex() et oct() font ces conversions pour vous. Voir le titre hex dans le manuel perlfunc et le titre oct dans le manuel perlfunc pour plus de détails.

Vous pouvez aussi inclure des « nouvelles lignes » directement dans vos chaînes, i.e., elles peuvent se terminer sur une ligne différente de celles où elles ont commencé. C’est bien joli, mais si vous oubliez votre apostrophe de fin (ou votre guillemet - NDT), l’erreur ne sera pas rapportée avant que Perl n’ait trouvé une autre ligne comportant une apostrophe, qui peut se trouver bien plus loin dans le script. La substitution de variable à l’intérieur des chaînes est limitée aux variables scalaires, aux tableaux et aux tranches de tableau ou de hachage (en d’autres termes, des noms commençant par $ ou @, suivi d’une expression optionnelle entre crochets comme indice). Le segment de code qui suit affiche « The price is $100. »

$Price = ’$100’; # pas interprété

print "The price is $Price.\n";     # interprété

Comme dans certains shells, vous pouvez mettre des accolades autour d’un nom pour le séparer des caractères alphanumériques qui le suivent. Vous devez aussi faire cela lorsque vous interpolez une variable dans une chaîne pour séparer son nom d’un deux-points ou d’une apostrophe, puisqu’ils seraient autrement traités comme un séparateur de paquetage :

$who = "Larry";

print PASSWD "${who}::0:0:Superuser:/:/bin/perl\n"; print "We use ${who}speak when ${who}’s here.\n";

Sans les accolades, Perl aurait cherché un $whospeak, un $who::0, et une variable who’s. Les deux dernières auraient été les variables $0 et $s dans le paquetage who (probablement) inexistant.

En fait, un identifiant situé entre de telles accolades est forcé d’être une chaîne, tout comme l’est tout identificateur isolé à l’intérieur d’un indice d’un hachage. Aucun des deux n’a besoin d’apostrophes. Notre exemple précédent, $days{’Feb’} peut être écrit sous la forme $days{Feb} et les apostrophes seront présumées automatiquement. Mais tout ce qui est plus compliqué dans l’indice sera interprété comme étant une expression.

Un littéral de la forme v1.20.300.4000 est analysé comme une chaîne composée de caractères correspondants aux ordinaux spé- cifiés. Ceci fournit une façon alternative plus lisible pour construire des chaînes, au lieu d’utiliser l’interpolation quelque peu moins lisible " x{1} x{14} x{12c} x{fa0}". C’est utile pour représenter des chaînes Unicode, et pour comparer des numéros de version en utilisant les opérateurs de comparaison de chaînes, cmp, gt, lt etc. Si le littéral contient plusieurs points, le premier v peut être omis.

print v9786;        # affiche le SMILEY codé en UTF-8, # "\x{263a}"

print v102.111.111;         # affiche "foo" print 102.111.111;            # idem

De tels littéraux sont acceptés à la fois par require et use pour réaliser une vérification de numéro de version. La variable spéciale

$ˆV contient aussi le numéro de version sous cette forme de l’interpréteur Perl en cours d’utilisation. Voir le titre $ˆV dans le manuel

perlvar.

Les littéraux spéciaux    FILE    ,     LINE    , et     PACKAGE     représentent le nom de fichier courant, le numéro de la ligne, et   le nom du paquetage à ce point de votre programme. Ils ne peuvent être utilisés que comme des mots-clé isolés ; ils ne seront pas interpolés dans les chaînes. S’il n’existe pas de paquetage courant (à cause d’une directive package;), PACKAGE est la valeur indéfinie.

Les deux caractères de contrôle ˆD et ˆZ, et les mots-clé   END    et    DATA    peuvent être utilisés pour indique la fin logique   d’un script avant la fin effective du fichier. Tout texte les suivant est ignoré.

Le texte qui suit DATA peut être lu via le handle de fichier PACKNAME::DATA, où PACKNAME est le paquetage qui était courant lorsque le mot-clé   DATA    a été rencontré. Le handle de fichier est laissé ouvert, pointant vers le contenu après    DATA    . Il est de la responsabilité du programme d’effectuer un close DATA lorsqu’il a fini d’y lire. Pour la compatibilité avec d’anciens scripts écrits avant que   DATA   ne soit introduit,   END    se comporte comme    DATA    dans le script principal (mais pas dans les fichiers chargés par require ou do) et laisse le contenu restant du fichier accessible via main::DATA.

Voir le manuel SelfLoader pour une plus longue description de DATA  , et un exemple de son utilisation. Notez que vous ne  pouvez pas lire depuis le handle de fichier DATA dans un bloc BEGIN : ce bloc est exécuté dès qu’il est vu (pendant la compilation), à un moment où le mot-clé DATA (ou END ) correspondant n’a pas encore été rencontré.

Un mot qui n’a aucune autre interprétation dans la grammaire sera traité comme s’il était une chaîne entre apostrophes. Ces mots sont connus sous le nom de « barewords ». Comme pour les handles de fichier et les labels, un bareword constitué entièrement de lettres minuscules risque d’entrer en conflit avec de futurs mots réservés, et si vous utilisez le pragma use warnings ou  l’option

-w, Perl vous avertira pour chacun d’entre eux. Certaines personnes pourraient vouloir rendre les barewords totalement hors-la-loi.

Si vous dites

use strict ’subs’;

alors tout bareword qui ne serait PAS interprété comme un appel à un sous-programme produit à la place une erreur au moment de la compilation. La restriction continue jusqu’à la fin du bloc qui le contient. Un bloc interne pourrait annuler ceci en disant no strict ’subs’.

Les tableaux et les tranches sont interpolés en chaînes entre guillemets en joignant tous les éléments avec le délimiteur spécifié dans la variable $" ($LIST_SEPARATOR dans le paquetage English.pm), une espace par défaut. Les expressions suivantes sont équivalentes :

$temp = join($", @ARGV); system "echo $temp";

system "echo @ARGV";

À l’intérieur d’un motif de recherche (qui subit aussi la substitution entre guillemets) il y a une malheureuse ambiguïté : est-ce que

/$foo[bar]/ doit être interprété comme /${foo}[bar]/ (où [bar] est une classe de caractères pour l’expression régulière) ou comme /${foo[bar]}/ (où [bar] est un indice du tableau @foo) ? Si @foo n’existe pas par ailleurs, alors c’est évidemment une classe de caractères. Si @foo existe, Perl choisit de deviner la valeur de [bar], et il a presque toujours raison. S’il se trompe, ou si vous êtes simplement complètement paranoïaque, vous pouvez forcer l’interprétation correcte avec des accolades comme ci-dessus.

Une forme de citation orientée ligne est basée sur la syntaxe « here-document » du shell. Après un « vous spécifiez une chaîne pour terminer le matériel cité, et toutes les lignes qui suivent la ligne courante jusqu’à la chaîne de terminaison forment la valeur de l’élément. La chaîne de terminaison peut être soit un identificateur (un mot), soit du texte cité. S’il est entre guillemets, le type de guillemets que vous utilisez détermine le traitement du texte, tout comme dans une citation normale. Un identificateur sans guillemets fonctionne comme des guillemets normaux. Il ne doit pas y avoir d’espace entre le « et l’identificateur (si vous mettez une espace, elle sera traitée comme un identificateur nul, ce qui est valide, et correspond à la première ligne vide). La chaîne de terminaison doit apparaître toute seule (sans guillemets et sans espaces l’entourant) sur la ligne de terminaison.

print <<EOF;

The price is $Price.

EOF

print <<"EOF";  # comme ci-dessus The price is $Price.

EOF

print <<‘EOC‘;   # exécute les commandes echo hi there

echo lo there EOC

print <<"foo", <<"bar"; # vous pouvez les empiler I said foo.

foo

I said bar. bar

myfunc(<<"THIS", 23, <<’THAT’);

Here’s a line or two.

THIS

and here’s another.

THAT

N’oubliez simplement pas que vous devez mettre un point-virgule à la fin pour terminer la déclaration, car Perl ne sait pas que vous n’allez pas essayer de faire ceci :

print <<ABC 179231

ABC

+ 20;

Si vous désirez que vos here-documents soient indentés avec le reste du code, vous devrez retirer manuellement la première espace de chaque ligne :

($quote = <<’FINIS’) =~ s/^\s+//gm; The Road goes ever on and on,

down from the door where it began.

FINIS

5.1.5      Constructeurs de listes de valeurs

Les valeurs de liste sont dénotées en séparant les valeurs individuelles par des virgules (et en enfermant la liste entre parenthèses lorsque la précédence le requiert) :

(LIST)

Dans un contexte qui ne requiert pas une valeur de liste, la valeur de ce qui apparaît être un littéral de liste est simplement la valeur de l’élément final, comme avec l’opérateur virgule en C. Par exemple,

@foo = (’cc’, ’-E’, $bar);

affecte la totalité de la valeur de liste au tableau @foo, mais

$foo = (’cc’, ’-E’, $bar);

affecte la valeur de la variable $bar à la variable $foo. Notez que la valeur d’un véritable tableau dans un contexte scalaire est la longueur du tableau ; ce qui suit affecte la valeur 3 à $foo :

@foo = (’cc’, ’-E’, $bar);

$foo = @foo;     # $foo prend la valeur 3

Vous pouvez avoir une virgule optionnelle avant la parenthèse fermante d’un littéral de liste, vous pouvez donc dire :

@foo = ( 1,

2,

3,

);

Pour utiliser un here-document afin d’affecter un tableau, une ligne par élément, vous pourriez utiliser l’approche suivante :

@sauces = <<End_Lines =~ m/(\S.*\S)/g; normal tomato

spicy tomato green chile pesto

white wine End_Lines

Les LIST font une interpolation automatique des sous-listes. C’est-à-dire que lorsqu’une LIST est évaluée, chaque élément de la liste est évalué dans un contexte de liste, et la valeur de liste résultante est interpolée en LIST tout comme si chaque élément était un membre de LIST. Ainsi, les tableaux perdent leur identité dans une LIST - la liste

(@foo,@bar,&SomeSub)

contient tous les éléments de @foo suivis par tous les éléments de @bar, suivis par tous les éléments retournés par le sous-programme appelé SomeSub quand il est appelé dans un contexte de liste. Pour faire une référence à une liste qui NE soit PAS interpolée, voir le manuel perlref.

La liste vide est représentée par (). L’interpoler dans une liste n’a aucun effet. Ainsi, ((),(),()) est équivalent à (). De façon similaire, interpoler un tableau qui ne contient pas d’élément revient à ce qu’aucun tableau n’ait été interpolé à ce moment-là.

Une valeur de liste peut aussi être indicée comme un tableau normal. Vous devez mettre la liste entre parenthèses pour éviter les ambiguïtés. Par exemple :

# Stat renvoit une valeur de liste.

$time = (stat($file))[8];

# ICI, ERREUR DE SYNTAXE.

$time = stat($file)[8]; # OOPS, OUBLI DES PARENTHESES

# Trouver un chiffre hexadécimal.

$hexdigit = (’a’,’b’,’c’,’d’,’e’,’f’)[$digit-10];

# Un "opérateur virgule inversé". return (pop(@foo),pop(@foo))[0];

Les listes ne peuvent être affectées que si chaque élément de la liste peut l’être lui aussi :

($a, $b, $c) = (1, 2, 3);

($map{’red’}, $map{’blue’}, $map{’green’}) = (0x00f, 0x0f0, 0xf00);

Une exception à ceci est que vous pouvez affecter undef dans une liste. C’est pratique pour balancer certaines valeurs de retour d’une fonction :

($dev, $ino, undef, undef, $uid, $gid) = stat($file);

L’affectation de liste dans un contexte scalaire renvoie le nombre d’éléments produits par l’expression du côté droit de l’affectation :

$x = (($foo,$bar) = (3,2,1));        # met 3 dans $x, pas 2

$x = (($foo,$bar) = f());                # met le nombre de valeurs # de retour de f() dans $x

Ceci est pratique lorsque vous voulez faire une affectation de liste dans un contexte booléen, parce que la plupart des fonctions de liste renvoient une liste vide quand elle se terminent, ce qui donne un 0 quand on l’affecte, 0 qui est interprété comme FALSE (FAUX

-              NDT).

L’élément final peut être un tableau ou un hachage :

 ($a, $b, @rest) = split; local($a, $b, %rest) = @_;

Vous pouvez en vérité mettre un tableau ou un hachage n’importe où dans la liste, mais le premier situé dans la liste va aspirer toutes les valeurs, et tout ce qui le suivra deviendra indéfini. Cela peut être pratique dans un local() ou un my().

Un hachage peut être initialisé en utilisant une liste de littéraux contenant des paires d’éléments qui doivent être interprétées comme des couples clé/valeur :

# identique à l’affectation de map ci-dessus

%map = (’red’,0x00f,’blue’,0x0f0,’green’,0xf00);

Tandis que les littéraux de liste et les tableaux nommés sont souvent interchangeables, ce n’est pas le cas pour les hachages. Le simple fait que vous puissiez indicer une valeur de liste comme un tableau normal ne veut pas dire que vous pouvez indicer une valeur de liste comme un hachage. De la même manière, les hachages inclus comme parties d’autres listes (y compris les listes de paramètres et les listes de retour de fonctions) s’aplatissent toujours en paires clé/valeur. C’est pourquoi il est parfois bon d’utiliser des références.

Il est parfois plus lisible d’utiliser l’opérateur => dans les paires clé/valeur. L’opérateur => est principalement juste un synonyme plus clair visuellement qu’une virgule, mais il permet aussi à son opérande de gauche d’être interprété comme une chaîne, si c’est un bareword qui serait un identifiant légal. Cela rend plus jolie l’initialisation des hachages :

%map = (

red => 0x00f, blue => 0x0f0, green => 0xf00,

);

ou pour initialiser les références de hachage devant être utilisées en tant qu’enregistrements :

$rec = {

witch => ’Mable the Merciless’, cat        => ’Fluffy the Ferocious’, date => ’10/31/1776’,

};

ou pour utiliser l’appel par variables pour les fonctions compliquées :

$field = $query->radio_group(

name    => ’group_name’,

values   => [’eenie’,’meenie’,’minie’], default  => ’meenie’,

linebreak => ’true’, labels           => \%labels

);

Notez que ce n’est pas parce qu’un hachage est initialisé dans un certain ordre qu’il ressortira dans cet ordre. Voir le titre sort dans le manuel perlfunc pour des exemples sur la façon de s’arranger pour obtenir des sorties ordonnées.

5.1.6      Tranches

Une façon commune d’accéder à un tableau ou à un hachage est d’en prendre un élément à la fois. Vous pouvez aussi indicer une liste pour en obtenir un seul élément.

$whoami = $ENV{"USER"};         # un élément du hachage

$parent = $ISA[0];          # un élément du tableau

$dir        = (getpwnam("daemon"))[7];  # idem, mais avec une liste

Une tranche accède à plusieurs éléments d’une liste, d’un tableau ou d’un hachage simultanément en utilisant une liste d’indices. C’est plus pratique que d’écrire les éléments individuellement sous la forme d’une liste de valeurs scalaires séparées.

($him, $her)      = @folks[0,-1]; # tranche de tableau @them    = @folks[0 .. 3];                               # tranche de tableau ($who, $home)  = @ENV{"USER", "HOME"};     # tranche de hachage ($uid, $dir)            = (getpwnam("daemon"))[2,7];                                  # tranche de liste

Puisque vous pouvez affecter à une liste de variables, vous pouvez aussi affecter à une tranche de tableau ou de hachage.

@days[3..5]       = qw/Wed Thu Fri/; @colors{’red’,’blue’,’green’}

= (0xff0000, 0x0000ff, 0x00ff00); @folks[0, -1] = @folks[-1, 0];

Les affectations précédentes sont exactement équivalents à

 ($days[3], $days[4], $days[5]) = qw/Wed Thu Fri/; ($colors{’red’}, $colors{’blue’}, $colors{’green’})

= (0xff0000, 0x0000ff, 0x00ff00); ($folks[0], $folks[-1]) = ($folks[0], $folks[-1]);

Puisque changer une tranche change le tableau ou le hachage original dont la tranche est issue, une structure foreach altèrera certaines – ou même toutes les – valeurs du tableau ou du hachage.

foreach (@array[ 4 .. 10 ]) { s/peter/paul/ } foreach (@hash{keys %hash}) {

s/^\s+//; # supprime les espaces au début des éléments s/\s+$//; # supprime les espaces à la fin des éléments s/(\w+)/\u\L$1/g; # met une majuscule aux mots

}

Une tranche d’une liste vide est encore une liste vide. Ainsi :

@a = ()[1,0];      # @a n’a pas d’éléments @b = (@a)[0,1];   # @b n’a pas d’éléments @c = (0,1)[2,3]; # @c n’a pas d’éléments

Mais :

@a = (1)[1,0];    # @a a deux éléments @b = (1,undef)[1,0,2]; # @b a trois éléments

Ceci rend aisée l’écriture de boucles qui se terminent lorsqu’une liste nulle est renvoyée :

while ( ($home, $user) = (getpwent)[7,0]) { printf "%-8s %s\n", $user, $home;

}

Comme noté précédemment dans ce document, le sens scalaire de l’affectation de liste est le nombre d’éléments de la partie droite de l’affectation. La liste nulle ne contient pas d’éléments, donc lorsque le fichier de mots de passe est vidé, le résultat est 0 et non pas 2.

Si vous êtes troublé par le pourquoi de l’usage d’un ’@’ ici sur une tranche de hachage au lieu d’un ’%’, pensez-y ainsi. Le type  de parenthésage (avec des crochets ou des accolades) décide si c’est un tableau ou un hachage qui est examiné. D’un autre côté, le symbole en préfixe (’$’ ou ’@’) du tableau ou du hachage indique si vous récupérez une valeur simple (un scalaire) ou une valeur multiple (une liste).


72