Actions sur le document
Programmation DCL
Les bases et premiers pas sur la programmation DCL
Pour commencer le dictionnaire en ligne des commandes DCL : c'est par ici
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 cette
page, pour 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:
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 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.
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 sauvegarder $STATUS et/ou $SEVERITY si vous ne les évaluez pas immédiatement ou si vous prévoyez de 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 possibilité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 fonctionnalité de traitement immédiat
des erreurs.
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.
$ 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.
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.
$ 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 qu'utilisés dans le contexte d'une procédure appelée avec la commande @.
$ 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.
Et un petit programme d'exemple pour bien commencer :
$!------------------------------------------------------------------------------
$! SAMPLE.COM Syltrem 29-AVR-2001
$!------------------------------------------------------------------------------
$! Cette procédure donnera, pour le répertoire donné en paramètre, le nombre
$! de blocks occupés pour chaque groupe de fichiers d'un type donné.
$! Le type est identifié par l'extension (ex. PROGRAMME.EXE --> le type est EXE)
$! La liste est triée par ordre décroissant du nombre de blocks.
$!------------------------------------------------------------------------------
$ Init:
$ On Control_Y Then Goto Error_Trap
$ On Error Then Goto Error_Trap
$
$ P_Directory = P1
$
$ Say := Write SYS$OUTPUT ! SYS$OUTPUT = sortie par défaut
$ Define TMP_File SYS$SCRATCH:SAMPLE.TMP ! Un fichier de travail
$
$ File_Types = "" ! Contiendra une liste des types de fichiers rencontrés
$!-------------------------------------------------------------------------------
$ Begin:
$ File_Loop:
$ File = f$search(P1 + "*.*;*")
$ If File .eqs. "" - ! Plus de fichiers; fin de la liste
Then Goto Arrange_Data
$
$ File_Type = f$parse(File,,,"type") ! Extraire le type (.EXE, .DAT etc)
$ ! Si le type de ce fichier n'est pas déjà dans notre liste, on l'ajoute
$ ! et on initialise une variable pour cumuler le nombre de blocks.
$ If f$locate(File_Type, File_Types) .eq. f$length(File_Types) -
Then File_Types = File_Types + File_Type
$ File_Type = File_Type - "." ! Enlever le point (.)
$ If f$type(Num_Blocks_'File_Type) .eqs. "" -! Symbole n'existe pas
Then Num_Blocks_'File_Type = 0 ! initialiser cumulatif
$ Num_Blocks_'File_Type = Num_Blocks_'File_Type -
+ f$file_attributes(File,"ALQ") ! ALlocation Quantity
$ Goto File_Loop ! Passer au fichier suivant
$
$!-------------------------------------------------------------------------------
$ Arrange_Data:
$ Cpt = 1
$ Open/Write TMP TMP_File ! Ouvrir un fichier de travail
$ Arrange_Data_Loop:
$ File_Type = f$element(Cpt, ".", File_Types)
$ If File_Type .eqs. "." - ! Fin de la liste
Then Goto Arrange_Data_End
$
$ ! Écrire dans le fichier le nombre de blocks en format 9(8) avec zéros
$ ! non significatifs, suivi du type (Ex.: "00012345DAT")
$ Write TMP f$fao("!8ZL", Num_Blocks_'File_Type), File_Type
$ Cpt = Cpt + 1
$ Goto Arrange_Data_Loop
$ Arrange_Data_End:
$ Close TMP
$
$ Call

