Programmation DCL de base

 

Tous les langages de 3ième génération se ressemblent un peu dans la structure de leurs énoncés de base (boucles, branchements, conditions). Cependant on doit pour chacun réapprendre à apprivoiser la syntaxe et aussi mémoriser de nouveaux mots clés. Chaque langage a ses particularités propres, et c'est de celles-ci que je discuterai dans cete page, pour DCL. Il n'est pas question ici d'un cours de programmation, mais uniquement d'une présentation des particularités de DCL.

Tout d'abord, un programme DCL est appelée une procédure. Elle peut contenir les mêmes commandes que vous employez à l'invite DCL et aussi d'autres qui ne sont valides que dans le contexte d'une procédure comme par exemple le saut (GOTO) à une autre portion de la procédure. Voyons d'abord quelques principes élémentaires:

Chaque commande doit être précédée du signe de dollar ($)
Un commentaire est indiqué par un point d'exclamation (!). Tout ce qui suit ce dernier est ignoré.
Si on veut espacer les commandes pour alléger la lecture de la procédure, on peut laisser une ligne contenant seulement le signe de dollar. Il n'est pas nécessaire d'y mettre un point d'exclamation.
Vous pouvez taper les commandes en majuscules ou minuscules, indifféremment.
Une commande très longue peut être continuée sur plusieurs lignes: il suffit de terminer chaque ligne incomplète par un tiret (-), puis de continuer sur la ligne suivante sans y mettre le signe de dollar.
De mémoire, une ligne de commande (ce que vous avez tapé) ne peut pas dépasser 255 caractères et, une fois traduites toutes les substitutions (l'instruction complète avec les valeurs entre apostrophes), 1024 caractères.
Une étiquette (couramment appelée "label") est indiquée par un mot suivi du deux-point (:). Elles sont utilisées pour les sauts (GOTO, GOSUB) à l'intérieur de la procédure.
Les noms de symboles (les "variables") ou d'étiquettes peuvent contenir des lettres et des chiffres ainsi que les caractères spéciaux "_" et "$". Le premier caractère doit être une lettre.
Il n'y a aucun mot réservé en DCL. Vous pouvez nommer vos symboles et vos étiquettes comme bon vous semble. Idem pour les noms logiques, mais si vous redéfinissez un nom logique qui existe déjà et dont VMS a besoin, les conséquences peuvent être imprévisibles!

Bon. C'est assez pour un début. Passons à autre chose.

Structure des conditions IF

Il y a deux manières de construire un énoncé IF. La première tient sur une seule ligne et permet d'exécuter une seule commande si la condition est vraie.

Ex.: $ IF X .EQ.  22 THEN GOTO LA_BAS

L'autre façon permet d'exécuter plus d'une commande lorsque la condition est vraie, et optionellement d'autres commandes lorsqu'elle est fausse.

Ex.: $ IF          X .GE. 22 .AND. X .LE. 33
$ THEN   WRITE SYS$OUTPUT "X est une valeur entre 22 et 33"
$               GOTO LA_BAS
$ ELSE    WRITE SYS$OUTPUT "X est plus petit que 22 ou plus grand que 33"
$               GOTO AILLEURS
$ ENDIF

 

Opérateurs logiques et de comparaison

:Comme vous l'avez sans doute remarqué dans l'instruction IF ci-dessus, on utilise des mots-clés encadrés de points (.) pour les opérateurs. Les opérateurs de comparaison sont également divisés en deux groupes: numériques et alphanumériques; les opérateurs pour les comparaisons alphanumériques se terminant par un "S" (pour "String").

Opérateurs de comparaison  

Opérateurs logiques

Numérique Alphanumérique Signification  

 

Signification

.LT. .LTS. Plus petit que (Less Than)   .AND. Et
.LE. .LES. Plus petit ou égal à (Less or Equal to)   .OR. Ou
.EQ. .EQS. Égal à (EQual to)   .NOT. N'est pas (is NOT)
.GE. .GES. Plus grand ou égal à (Greater or Equal to)      
.GT. .GTS. Plus grand que (Greater Than)      
.NE. .NES. Différent de (Not Equal to)      

 

Expressions booléennes

Vous pouvez utiliser des opérations booléennes un peu partout. Voyons quelques exemples:

$ INIT:
$       SAY := WRITE SYS$OUTPUT
$       INQ*UIRE :=  INQUIRE /NOPUNCTUATION
$ DEBUT:
$       INQUIRE AGE "Quel âge avez-vous ?"
$ ENFANTS:
$       INQUIRE ENFANTS "Avez-vous des enfants (O/N) ?"
$       BONNE_REPONSE = ENFANTS .EQS. "O" .OR. ENFANTS .EQS. "N"
$       IF .NOT. BONNE_REPONSE THEN GOTO ENFANTS
$ RESULTAT:
$       IF ENFANTS .EQS. "O" THEN ENFANTS = "TRUE"
$       ADULTE = AGE .GE. 18
$       IF ADULTE THEN SAY "Vous n'êtes plus un enfant!"
$       IF .NOT. ADULTE .AND. ENFANTS THEN SAY "Oh! là là!"

Un symbole numérique contient une valeur "vraie" si: c'est un nombre impair (en général, 1)
Un symbole alphanumérique contient une valeur "vraie" si il contient les mots "TRUE" ou "YES", ou encore l'initiale de ces mots.

 

Traitement des erreurs

L'exécution de chaque commande retourne un statut dans le symbole $STATUS, et la sévérité de l'erreur dans $SEVERITY. Il est possible d'évaluer ces valeurs avec l'instruction IF afin de prendre une action en cas d'erreur dans le traitement.

On peut brancher automatiquement à une routine de traitement des erreurs avec l'instruction:
$ ON sévérité THEN commande
Sévérité est l'un de: WARNING, ERROR ou SEVERE, et commande n'importe quelle commande que l'on veut voir exécuter si une erreur se produit. Souvent, cette dernière est GOTO étiquette, où étiquette est le point de branchement à la routine de traitement des cas d'erreurs. La commande indiquée sera exécutée automatiquement lorsqu'une instruction aura terminé avec un statut d'erreur ayant une sévérité égale ou supérieure à celle indiquée par ON sévérité.

Dans une routine de traitement des erreurs, on peut évaluer $STATUS ou $SEVERITY et prendre action en fonction de ces valeurs. Notez cependant que toute nouvelle commande réinitialisera ces deux valeurs! À vous alors de sauvegerder $STATUS et / ou $SEVERITY si vous ne les évaluez pas immédiatement ou si vous prévoyez les utiliser dans plusieurs commandes. Voyez l'exemple ci-dessous pour plus de détails.

$    ON ERROR THEN GOTO ERROR_TRAP
$    SAY := WRITE SYS$OUTPUT
$
$    DIRECTORY /TICTACTOE                   
$                                                                       
$                                                                       
$    COPY NL: GROS_FICHIER.DAT   -        
$              /ALLOCATION=90000000          
$                                                                        
$    GOTO FIN



! Cette instruction causera un WARNING;
! il n'y aura pas de branchement automatique à
! ERROR_TRAP et le traitement continuera
! Cette commande se terminera en ERROR
! parce qu'il manquera d'espace sur le disque
! et il y aura branchement à ERROR_TRAP
$ ERROR_TRAP:
$    STAT = $STATUS
$    SEV = $SEVERITY
$    SAY "Une erreur a été déclarée en cours d'exécution"
$    SAY "Code de l'erreur: ", STAT, ";    Sévérité: ", SEV
$ FIN:
$    EXIT 'STAT
           

D'autres possiblités de traitement sont offertes en activant (SET ON) ou en désactivant (SET NOON) l'instruction ON sévérité THEN commande. SET NOON fera en sorte que l'exécution de la procédure soit continuée peut importe le résultat de chaque commande subséquente. SET ON rétablit la fonctionalité de traitement immédiat des erreurs.

Paramètres

On peut passer jusqu'à 8 paramètres de 255 caractères maximum chacun à une procédure. Les paramètres porteront les noms P1 à P8. Cependant, il est sage de créer de nouveaux symboles et leur assigner les valeurs de P1 à P8 au tout début de votre procédure, de telle manière que les valeurs reçues portent des noms significatifs.

Ex.: $ INIT:
$      NOM = P1
$     AGE = P2
$
$ DEBUT:
$      WRITE SYS$OUTPUT "Tu t'appelles ", NOM, " et tu as ", AGE, " ans."
$      EXIT

Pour passer les paramètres (NOM et AGE) à cette procédure on procède de la manière suivante:

$ @DEMO.COM  Gaston  32 ! Exécution immédiate
$ SUBMIT  DEMO.COM /PARAMETERS=(Gaston, 32) ! Exécution en lot

Dans ces exemples, DCL aurait transposé la chaîne de caractères en majuscules. Pour conserver les minuscules ou alors pour entrer des espaces ou autres caractères spéciaux, il aurait fallu mettre la chaîne de caractères entre guillemets (").


Si l'on désire donner comme paramètre d'une procédure la valeur d'un symbole, on doit utiliser les caractères de substitution:

Ex.: $ NOM:=GASTON
$ AGE = 32
$ @DEMO.COM  "''NOM'"  'AGE'


! Exécution immédiate
$ SUBMIT  DEMO.COM /PARAMETERS=(&NOM, &AGE) ! Exécution en lot

Notez que pour la commande SUBMIT, j'ai utilisé la perluète comme caractère de substitution. Il est en effet possible de faire cela dans ce contexte (les symboles sont les valeurs du qualificatif /PARAMETERS). Autre avantage non négligeable, cela permet de sauver des touches! Revoyez l'utilisation des perluètes dans ces pages.

 

Boucles et itérations

Il n'y a pas d'instructions de bouclage (FOR, WHILE, UNTIL, etc) en DCL; vous devez contrôler les boucles avec IF et GOTO. Par contre, plusieurs fonctions lexicales se prêtent à ce genre de traitement. F$SEARCH() par exemple, retourne un à un les fichiers d'un répertoire, F$ELEMENT() les éléments d'une liste. Il y a aussi F$PID(), F$DEVICE() et F$GETQUI().

Voyons juste un petit exemple avec F$SEARCH()..

$ INIT:
$      CPT = 0
$ BOUCLE:
$      FICHIER = F$SEARCH("DISQUE:[RÉPERTOIRE]*.TXT")     ! Retourner les noms de tous les fichier .TXT
$      IF        FICHIER .EQS. ""         -                                                 ! Si vide, on a atteint la fin de la liste
        THEN GOTO FIN
$      CPT = CPT + 1
$      GOTO BOUCLE
$ FIN:
$      WRITE SYS$OUTPUT "Il y a ", CPT, "fichiers .TXT danc le répertoire")

 

Branchements

En plus du sympathique GOTO, DCL vous offre deux autres instructions pour vous permettre de structurer votre procédure en créant des sous-routines. Ce sont GOSUB et CALL.

GOSUB exécute une série d'instructions débutant à l'étiquette donnée en paramètre, et terminées par RETURN.

Ex.: $     GOSUB SOUS_ROUTINE
$      GOTO FIN
$ SOUS_ROUTINE:
$      WRITE SYS$OUTPUT "Exemple de sous-routine"
$      RETURN
$ FIN:
$     EXIT
 

CALL exécute les instructions comprises entre SUBROUTINE et ENDSUBROUTINE. Plus encore, il est possible de passer des paramètres à la sous-routine, comme on le fait pour une procédure. Les règles d'utilisations de ces derniers sont les mêmes que lorsqu'utilisés dans le contexte d'une procédure appelée avec la commande @.

Ex.: $      CALL EXEMPLE "Exemple de sous-routine recevant des paramètres"
$      GOTO FIN
$ EXEMPLE:
$      SUBROUTINE
$      MESSAGE = P1
$      WRITE SYS$OUTPUT MESSAGE
$      ENDSUBROUTINE
$ FIN:
$     EXIT


Pour terminer

Quoiqu'on en dise, DCL est un langage assez complet, qui vous permettra d'effectuer de nombreuses tâches. Il sera un outil de tous les jours pour exécuter des travaux en lot ou répétitifs, faire le lien entre vos applications et OpenVMS, et plus encore.

Plus vous apprendrez à le connaître et plus il vous servira. Faites en bon usage!