Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Programmer en COBOL
  3. Déclarer et manipuler les données
Extrait - Programmer en COBOL Développement et Maintenance de programmes
Extraits du livre
Programmer en COBOL Développement et Maintenance de programmes
5 avis
Revenir à la page d'achat du livre

Déclarer et manipuler les données

Introduction

Du fait de l’environnement matériel sur lequel se trouve une grande partie des programmes COBOL aujourd’hui, l’environnement grand système IBM, un petit préambule sur les codes de caractères est indispensable.

1. Codes de caractère : EBCDIC

Après avoir remporté le concours organisé par le Bureau du recensement des États-Unis pour le recensement de 1890 avec une machine de statistiques à cartes perforées s’inspirant du système inventé par Jean-Baptiste Falcon en 1728 sur les métiers à tisser que Basile Bouchon avait rendu programmables à l’aide de rubans perforés en 1725 (invention reprise en 1801 par Joseph Marie Jacquard), Herman HOLLERITH fonde, en 1896, la Tabulating Machine Co. En 1924, après divers regroupements, la Tabulating Machine Co. devient IBM (International Business Machines) qui définit, en 1928, un standard de cartes perforées à 80 colonnes. Le code alors utilisé, baptisé code Hollerith, reste limité en nombre de caractères. En 1955, IBM met au point un code de caractères sur 6 bits qui offre 64 caractères (2^6) : le BCD (Binary Coded Decimal). Ce code sera utilisé sur la série des 700/7000 sur lesquels sera disponible le compilateur FORTRAN.

C’est en 1960 que débutent les travaux de l’American Standards Association (ASA) auxquels participe notamment Robert BEMER, pour la définition d’un code de caractères standard. Bien qu’IBM soit déjà en train de réfléchir à un codage sur 8 bits, définir un code sur 8 bits semble à l’ASA trop en avance par rapport aux technologies existantes et ils décident donc de définir un code sur 7 bits seulement n’offrant qu’un jeu de 128 (2^7) caractères.

Le 7 avril 1964, IBM annonce la mise sur le marché de sa série des 360. Ils utilisent une extension sur 8 bits du BCD, qui offre un jeu de 256 (2^8) caractères : l’EBCDIC (Extended Binary-Coded Decimal Interchange Code). IBM décide de faire de l’EBCDIC son code de caractères principal tout en annonçant que la série des 360 serait compatible avec l’ASCII en cours de définition.

Ce n’est qu’en 1968 qu’est...

Numéros de niveaux hiérarchiques

1. Présentation

Toute déclaration de zone doit commencer par son numéro de niveau hiérarchique : ce numéro de niveau permet d’organiser les données de façon hiérarchique ou, plus précisément, de détailler une zone en plusieurs autres. Ceci permet de travailler sur la zone dans son intégralité mais également sur des parties de cette zone.

Exemple : la donnée INSTANT est constituée d’une date et d’une heure

03CBL09.png

Deux représentations COBOL de cette donnée sont possibles sans notion de niveau hiérarchique :

  • déclaration simple de la donnée INSTANT :

    ----+----1----+----2----+----3----+----4----+----5----+----6----+
           01  ws-instant              PIC 9(14). 
  • déclaration en parties indépendantes, ou zones élémentaires :

    ----+----1----+----2----+----3----+----4----+----5----+----6----+
           01  ws-date                 PIC 9(8).
           01  ws-heure                PIC 9(6). 

En fonction de l’une ou l’autre de ces descriptions, il est possible d’utiliser :

  • soit la donnée stockée dans la zone WS-INSTANT sans avoir la possibilité d’en extraire d’une manière distincte ses composantes date et heure (exemple 1),

  • soit chaque donnée élémentaire stockée dans les zones WS-DATE et WS-HEURE sans pouvoir les manipuler ensemble puisque la variable WS-INSTANT n’est pas déclarée (exemple 2). Nous verrons qu’il existe cependant des instructions plus sophistiquées que le MOVE permettant tout de même de manipuler "ensemble" des zones élémentaires.

L’utilisation de niveaux hiérarchiques permet de déclarer une zone de manière à avoir ces deux possibilités.

Il faut partir de la donnée de plus haut niveau (ici la donnée INSTANT) et déclarer la zone correspondante SANS clause PICTURE :

----+----1----+----2----+----3----+----4----+----5----+----6----+
       01  ws-instant. 

Il faut ensuite déclarer les deux zones contenant la date et l’heure, en indiquant un numéro de niveau hiérarchique plus élevé. Si WS-INSTANT est déclarée en niveau 01, il faut déclarer WS-DATE et WS-HEURE en niveau 02 ou plus. Si WS-INSTANT est déclarée en niveau 05, il faut déclarer...

Zones alphanumériques : déclaration et usage

Comme évoqué précédemment, il y a deux grandes familles de données en COBOL :

  • les données alphanumériques,

  • les données numériques.

Nous allons tout d’abord étudier la déclaration des zones pour manipuler des données alphanumériques. Dans le paragraphe suivant seront étudiées les déclarations pour utiliser des données numériques.

Pour toute zone sur laquelle il n’est pas besoin de faire de calculs, le caractère de PICTURE à utiliser est X. Il correspond à la définition d’une zone alphanumérique pouvant contenir tout type de caractère : lettre, symbole, chiffre, espace...

La longueur maximum possible d’une zone alphanumérique est fixée par le compilateur : les plus récents affichent la possibilité de déclarer une zone alphanumérique de 134 217 727 caractères. Les compilateurs fixent également une limite maximale de taille pour la WORKING-STORAGE et pour la LINKAGE. Elle est généralement exprimée en megabytes et avoisine aujourd’hui les 128 Mb. Ces limites sont indiquées dans les Language Reference, Error Messages... ou autres documents de référence selon les compilateurs.

1. MOVE avec zone réceptrice alphanumérique

Comme vu précédemment, le résultat d’un MOVE dépend du format de la zone réceptrice. Sans indication particulière toute donnée, numérique ou alphanumérique, mise dans une zone alphanumérique (de PICTURE X) est cadrée à gauche.

C’est la PICTURE de la zone réceptrice qui détermine le stockage en mémoire de la donnée origine quel que soit le format de cette donnée.

Si la donnée est de longueur inférieure à la zone réceptrice, le reste de la zone réceptrice est complété par des espaces.

Exemple 1 :

TXT1 PIC X(20) :       LIBELLE PIC X(35) :
l'épaule d'Orion       De grands navires en feu surgissant
1...5....0....5....2   1...5....0....5....2....5....3....5 

Instruction :

           MOVE TXT1                 TO LIBELLE 

Après exécution de cette instruction la zone LIBELLE contient les mêmes données que TXT1, cadrées...

Les zones numériques

Bien qu’orienté gestion - et non pas scientifique - COBOL offre la possibilité de manipuler plusieurs formats internes de données numériques. Nous étudierons ici les trois principales PICTURE :

  • numérique étendu,

  • numérique compacté,

  • binaire.

Toute zone numérique peut également être :

  • signée ou non,

  • avec virgule ou non.

Comme pour les données alphanumériques, la longueur maximum possible d’une zone numérique dépend du compilateur mais également des options de compilation. Avec le compilateur COBOL for Z/OS d’IBM Enterprise, l’option ARITH(COMPAT) autorise une longueur de 18 bytes et ARITH(EXTEND) une longueur de 31.

1. USAGE DISPLAY

La clause USAGE DISPLAY est la clause USAGE par défaut : elle signifie que les zones déclarées ainsi sont affichables et donc lisibles directement. Cela facilite la lecture des fichiers, mais de telles zones occupent plus de place mémoire que les zones en numérique compacté ou en binaire et sont moins performantes pour les calculs.

Pour des variables nécessitant de nombreux calculs ce format de zone est à éviter.

Il nécessite une conversion binaire qui peut pénaliser lourdement le temps de traitement.

Déclaration

Le caractère de PICTURE à utiliser est 9.

Exemple :

       01 ws-mtt               PIC 9(5). 

Cette zone numérique peut contenir les valeurs 0 à 99999.

L’importance de la déclaration d’une zone lorsqu’elle est utilisée dans une PERFORM...UNTIL en tant que condition de fin a été évoquée dans le précédent chapitre. Voyons en quoi une mauvaise déclaration de zone peut provoquer une boucle infinie.

Prenons une variable J déclarée sur 2 :

       01 J                    PIC 99. 

Elle peut prendre les valeurs 00 à 99. Lorsqu’elle est à 99, si le programme lui ajoute 1... elle repasse à zéro !

Toute variable numérique qui dépasse sa capacité repasse à zéro.

Reprenons l’exemple déjà vu à cette occasion :

           PERFORM  MD10 UNTIL  J = 10
           [...]
       MD10.
           ADD    1      TO J
           DISPLAY "J = " J
           . 

Si la zone J est déclarée en PIC(9), la condition J=10 ne peut jamais être remplie : c’est alors...

Les conditions de signe et de classe

1. Les conditions de signe

Pour tester qu’une zone est positive, négative ou à zéro (attention : il ne faut pas confondre zone à zéro et valeur nulle : ce point sera abordé dans le chapitre Traitement des entrées-sorties), il est possible de coder :

           PERFORM UNTIL SQLCA-SQLCODE > 0
           [...]
           If ws-flot-file-status < 0
           [...]
           WHEN 0
           [...]
           If sqlcode not = 0 

COBOL possède des conditions de signe permettant d’exprimer le test sans formulation algébrique :

  • POSITIVE,

  • NEGATIVE,

  • ZERO.

Chacune d’entre elles peut être enrichie de la négation NOT.

Exemple :

           PERFORM UNTIL SQLCA-SQLCODE POSITIVE
           [...]
           If ws-flot-file-status NEGATIVE
           [...]
           WHEN ZERO         
           [...]
           If sqlcode not zero     

Certaines expressions sont équivalentes.

Ainsi :

  • ZEROES,

  • IS NOT ZEROES,

  • IS NOT POSITIVE,

  • IS NOT NEGATIVE.

équivaut à :

  • ZERO,

  • NOT ZERO,

  • NEGATIVE,

  • POSITIVE.

2. Les conditions de classe

Le terme "classe" n’a pas de lien avec la notion de classe utilisée en programmation objet : les conditions de classe faisaient déjà partie des spécifications originelles de 1960, bien avant que n’apparaisse l’objet.

Une condition de classe COBOL permet d’évaluer de façon très simple le contenu d’une zone pour certains critères difficiles à exprimer autrement. Deux conditions ont été...

Expression CORRESPONDING

L’expression CORR est disponible pour les instructions ADD, SUBTRACT et MOVE. Elle permet d’effectuer l’opération entre les zones élémentaires d’une zone groupe réceptrice et les zones élémentaires d’une zone groupe émettrice en fonction de la correspondance de ces noms de zones élémentaires et non pas en fonction de leur emplacement.

Cette expression n’est pas possible sur des zones de niveau 66, 77 et 88.

Syntaxe :

----+----1----+----2----+----3----+----4----+----5----+----6---...
           Instruction CORR variable-1 TO variable-2 

Les deux zones doivent être des zones groupe. Seules les zones ayant la même déclaration d’un côté comme de l’autre sont impactées par l’instruction.

Les FILLER explicites ou implicites ne sont pas impactés.

Exemple :

       WORKING-STORAGE SECTION.
           [...]
           02  DATE-AMJ.
               03 DATE-AA  PIC XXXX.
               03 DATE-MM  PIC XX.
               03 DATE-JJ  PIC XX.

           02  DATE-JMA.
               03 DATE-JJ  PIC XX.
               03 DATE-MM  PIC XX.
               03 DATE-AA  PIC XXXX.
           [...]
       PROCEDURE DIVISION.
           [...]
           MOVE  CORR DATE-AMJ        TO DATE-JMA. 

Cela revient au même que :

           MOVE DATE-AA OF DATE-AMJ  TO DATE-AA OF DATE-JMA
           MOVE DATE-MM OF DATE-AMJ  TO DATE-MM OF DATE-JMA
           MOVE DATE-JJ OF DATE-AMJ  TO DATE-JJ OF DATE-JMA 

Il s’agit ici d’un exemple classique permettant de reformater une date : la date origine de format AAMMJJ sera convertie au format JJMMAA....

Les registres spéciaux

En plus des constantes figuratives, des conditions de classe et des conditions de signe, COBOL met à disposition du développeur des registres spéciaux : ce sont des variables qui peuvent être utilisées sans avoir besoin d’être déclarées. Elles ne peuvent cependant pas être utilisées en DATA DIVISION. Les variables suivantes vont être étudiées :

  • WHEN-COMPILED,

  • RETURN-CODE,

  • LENGTH OF,

  • ADDRESS OF.

1. WHEN-COMPILED

Ce registre spécial est utilisé pour indiquer la date de compilation du programme dans sa trace (messages qui vont être mis à disposition avec l’instruction DISPLAY). Cela permet notamment de s’assurer de la version qui tourne en production.

Cette variable est une zone alphanumérique de 16 caractères contenant la date et l’heure de début de compilation du programme. Son contenu dépend directement de la version du compilateur.

Exemples sur IBM/MVS :

  • OS/VS/COBOL : hh.mm.ssMMM DD, YYYY

  • COBOL/370 : MM/DD/YYhh.mm.ss

  • COBOL for z/OS : MM/DD/Yyhh.mm.ss

Ce registre ne peut pas être utilisé directement dans une instruction DISPLAY : il doit au préalable être affecté dans une zone déclarée en WORKING-STORAGE.

Exemple :

           05  WD-COMPILE               PIC X(16).
[...]   
           MOVE WHEN-COMPILED           TO WD-COMPILE
           DISPLAY "Pgm CHOUETTE, compilé le : " WD-COMPILE  

La trace indiquera :

Pgm CHOUETTE, compilé le 05/20/1012.37.19 

pour une compilation effectuée le 20 mai 2010 à 12:37:19 avec le COBOL for Z/OS d’IBM Enterprise.

Ce registre peut être manipulé comme une variable afin, par exemple, d’être remis en forme, mais ne peut en aucun cas être modifié.

Il possède son homologue de même nom en fonction intrinsèque.

2. RETURN-CODE

Le RETURN-CODE a pour déclaration...

Clause REDEFINES : masque de donnée

Toute zone COBOL, groupe ou élémentaire, numérique ou alphanumérique, peut être utilisée au travers d’une autre PICTURE que sa PICTURE de déclaration. Elle doit pour cela être redéfinie à l’aide de l’instruction REDEFINES, spécifique à la DATA DIVISION.

C’est un masque qui est appliqué sur une zone mémoire déjà déclarée.

Elle n’occupe pas de place mémoire supplémentaire et il est impossible d’utiliser une clause VALUE sur une zone de redéfinition.

Syntaxe :

----+----1----+----2----+----3----+----4----+----5----+----6---...
       No    nom-zone1...
       No    nom-zone2      REDEFINES nom-zone1... 
La zone de redéfinition doit être de même niveau hiérarchique que la zone qu’elle redéfinit.

Exemple :

           05 ws-noliv               pic  x(07)   value " ".
           05 ws-noliv-num redefines ws-noliv pic 9(07). 

La zone ws-noliv-num redéfinit la zone ws-noliv. Bien entendu la zone ws-noliv-num ne peut être utilisée immédiatement en l’état : le masque est celui d’une zone numérique alors que la zone déclarée en mémoire contient des blancs. À l’exécution cette opération déclencherait la traditionnelle DATA EXCEPTION.

Il s’agit ici de zones élémentaires : le REDEFINES...

Initialisations : INITIALIZE

Nous avons vu qu’il est primordial d’initialiser les zones de travail déclarées en WORKING-STORAGE avant de les utiliser en PROCEDURE.

Pour les constantes, c’est la clause VALUE en WORKING-STORAGE qui est préconisée.

Pour les variables, l’initialisation peut être effectuée en WORKING-STORAGE mais aussi en PROCEDURE. Dans ce dernier cas, c’est généralement dans une section prévue à cet usage et appelée en début de programme que se font les initialisations de début de traitement. Il peut également être nécessaire de procéder à des initialisations de zones en cours de traitement.

Dans tous les cas, les deux méthodes les plus couramment employées pour initialiser des variables sont :

  • l’instruction MOVE,

  • l’instruction INITIALIZE.

Lorsque les zones de travail numériques sont regroupées sous un même niveau hiérarchique en WORKING-STORAGE, une instruction MOVE ZERO suffit. Il en est de même pour les zones de travail alphanumériques avec un MOVE SPACE. Il n’est cependant pas toujours possible de regrouper ainsi les déclarations par format. Dans ce cas l’instruction INITIALIZE est très utile : elle initialise chaque zone alphanumérique avec des espaces et chaque zone numérique à zéro. Elle...

Tableaux : clause OCCURS

1. Déclarations

Il existe plusieurs possibilités de déclaration d’un tableau :

  • tableau à une ou plusieurs dimensions,

  • tableau de longueur fixe ou de longueur variable,

  • tableau trié ou non,

  • tableau utilisable avec un indice ou avec un index.

La déclaration d’un tableau se fait par l’ajout de la clause OCCURS à la déclaration d’une zone, élémentaire ou groupe. Cette zone ne peut cependant pas être de niveau 66, 77 ou 88, ni même, pour certains compilateurs, de niveau 01.

Syntaxe :

----+----1----+----2----+----3----+----4----+----5----+----6---...
           OCCURS            n         TIMES
           DEPENDING ON      Nom-zone1
           ASCENDING KEY     Nom-clé
           DESCENDING KEY    Nom-clé
           INDEXED           Nom-Index 

Le nombre de lignes du tableau est indiqué par la donnée n, littéral numérique positif supérieur à zéro.

  • L’option DEPENDING ON permet la déclaration d’un tableau de longueur variable.

  • L’option ASCENDING ou DESCENDING indique s’il est trié, et dans quel ordre.

  • L’option INDEXED déclare un INDEX qui permet d’effectuer des recherches via l’instruction SEARCH.

Exemple avec une zone élémentaire

Déclaration COBOL :

           05  WS-MOIS     PIC X(9)  OCCURS 12 TIMES. 

WS-MOIS est un tableau :

  • à une dimension : une seule clause OCCURS,

  • de longueur fixe : son nombre d’occurrences est fixe,

  • de 12 occurrences.

03CBL35.PNG

Exemple avec une zone groupe :

Déclaration :

           05  WS-ADR               OCCURS 5 TIMES.
               10  WS-LIG1          PIC X(50).
               10  WS-LIG2          PIC X(50).
               10  WS-CP            PIC X(5).
               10  WS-VILLE         PIC X(20).
               10  WS-PAYS          PIC X(20). 

WS-ADR est un tableau :

  • à une dimension : une seule clause OCCURS,

  • de longueur fixe : son nombre d’occurrences est fixe,

  • de 5 occurrences.

03CBL33.png

a. Tableau à plusieurs dimensions

Un tableau à plusieurs dimensions est obligatoirement une zone groupe avec l’une de ses zones élémentaires elle-même déclarée en tableau avec la clause OCCURS.

Exemple :

           01  WS-MATRICE.
               05  WS-MATRICE-CHU            OCCURS 10 TIMES.
                   10  WS-CLETAB    PIC X(5) OCCURS 5 TIMES.
                   10  WS-CODE-RT   PIC 9(4)V99. 

WS-MATRICE-CHU est un tableau principal :

  • à deux dimensions : la zone élémentaire WS-CLETAB est déclarée en tableau secondaire,

  • de longueur fixe : son nombre d’occurrences est fixe, ainsi que le nombre d’occurrences...

Conclusion : recommandations

Que ce soit à la création d’un programme ou lors d’une maintenance, il est toujours utile d’effectuer une rapide revue des zones déclarées en WORKING-STORAGE afin de s’assurer que toutes les zones déclarées sont effectivement utilisées. Une recherche systématique en PROCEDURE de chaque zone élémentaire déclarée en WORKING permet bien souvent de découvrir ainsi des zones qui ne servent plus à rien.

Outre le fait de "nettoyer" ainsi ces déclarations inutiles, cela permet surtout de ne pas induire en erreur les futurs mainteneurs de l’application. En effet un reliquat de constantes inutilisées peut par exemple faire croire lors d’un simple survol du programme, que ce sont ces valeurs qui sont testées, alors qu’en réalité les zones concernées ne sont plus testées avec ces constantes mais avec des données stockées en table. Ces données parasites constituent également des sources d’erreur dans les éventuelles études d’impact basées sur des outils de recherche de zones...

Même des zones utilisées en PROCEDURE peuvent être inutiles. Des MOVE peuvent leur affecter une valeur... mais elles ne sont ensuite pas mises en sortie de quoi que ce soit : ni affichées, ni écrites......