Section courante

A propos

Section administrative du site

Les premiers pas

Le langage de programmation COBOL (acronyme de Common Business Oriented Language) est l'un des langages de programmation les plus anciens et les plus utilisés dans le domaine du traitement de données à grande échelle, notamment dans les environnements bancaires, gouvernementaux et commerciaux. Depuis sa création, il s'est imposé comme un outil incontournable pour la gestion des bases de données complexes, des transactions financières, ou encore des systèmes de paie.

Le COBOL a été spécialement conçu pour être un langage universel et accessible, facilitant le partage des programmes ainsi que la portabilité des méthodes de travail entre différents types d'ordinateurs et systèmes d'exploitation. Cette orientation visait à standardiser les pratiques de programmation à une époque où chaque fabricant d'ordinateur proposait ses propres langages et environnements, rendant l'interopérabilité difficile.

L'une des caractéristiques les plus remarquables de COBOL est sa syntaxe proche de l'anglais courant, ce qui le rend intuitif et lisible non seulement pour les programmeurs expérimentés, mais aussi pour les utilisateurs métier ou les responsables fonctionnels n'ayant pas nécessairement de formation technique. Cela permettait, et permet encore, une meilleure collaboration entre les équipes de développement et les équipes métier.

Dans ce fascicule, nous allons explorer dans quelle mesure les objectifs initiaux de COBOL - à savoir la lisibilité, la transférabilité, et l'universalité - ont été réalisés. Nous analyserons aussi pourquoi, malgré l'apparition de nombreux langages modernes, COBOL continue d'occuper une place centrale dans de nombreux systèmes critiques et pourquoi sa compréhension reste un atout précieux pour tout développeur orienté vers les systèmes d'information d'entreprise.

Historique du langage de programmation COBOL

À la fin des années 1950, les milieux industriels, gouvernementaux et informatiques ont commencé à exprimer un besoin croissant : disposer d'un langage de programmation universel, spécifiquement conçu pour le traitement automatisé de données. Jusque-là, chaque entreprise ou constructeur développait ses propres outils logiciels, ce qui compliquait grandement le partage, la maintenance, et la compatibilité entre systèmes.

En mai 1959, un événement marquant a eu lieu à Washington D.C., où des représentants de divers horizons - constructeurs d'ordinateurs, grandes entreprises utilisatrices et agences gouvernementales américaines - se sont réunis pour discuter sérieusement de la création d'un langage standardisé. Ce rassemblement donna naissance au groupe CODASYL (Conference on Data Systems Languages), une commission interdisciplinaire chargée d'élaborer les spécifications d'un nouveau langage dédié aux applications de gestion.

Peu de temps après sa création, la commission publia une première ébauche du langage, posant les bases de ce qui allait devenir COBOL. En avril 1960, une version révisée de cette proposition fut rendue publique sous le nom de COBOL 60. L'année suivante, en 1961, une deuxième version, appelée COBOL 61, fut largement diffusée et adoptée par de nombreuses organisations, confirmant l'intérêt du secteur pour ce langage.

En 1963, le langage subit un premier élargissement avec l'apparition de COBOL 61 Extended, intégrant de nouvelles fonctionnalités pour mieux répondre aux besoins des développeurs. Deux ans plus tard, en 1965, une autre évolution importante vit le jour avec la COBOL Edition 1965, version qui affina la syntaxe et renforça la portabilité. Cette version fut reconnue officiellement comme standard en 1968, marquant un tournant dans l'histoire de COBOL.

Entre 1968 et 1973, le langage connut une série de révisions régulières, publiées notamment dans le COBOL Journal of Development, ce qui permit d'améliorer sa robustesse et de suivre l'évolution rapide des technologies de l'époque. Puis, en 1974, un nouveau standard important fut validé par l'ANSI (American National Standards Institute), consolidant toutes les améliorations accumulées depuis la version de 1968.

Depuis cette date, le groupe CODASYL a poursuivi ses travaux, en collaboration avec des experts internationaux, pour enrichir encore les capacités de COBOL. En 1981, une version préliminaire révisée fut présentée, annonçant les futures orientations du langage, et était en cours d'adoption à l'époque de la rédaction de ce document.

Implémentations et variantes du langage de programmation COBOL

La version de COBOL utilisée comme référence dans ce document correspond à celle définie par le Standard national américain de 1974 (American National Standard, ANSI). Cette version, largement adoptée à travers le monde, constitue la base commune à de nombreuses implémentations disponibles à l'époque. Grâce à sa robustesse et à sa portabilité, COBOL a été porté sur une vaste gamme de plateformes informatiques, allant des grands systèmes centraux aux micro-ordinateurs domestiques et professionnels.

En effet, COBOL a été implémenté avec succès sur la majorité des mini-ordinateurs et mainframes utilisés dans les secteurs bancaires, industriels et publics. Parmi les constructeurs majeurs qui ont proposé leur propre version de COBOL, on peut citer les systèmes suivants :

Chacune de ces plateformes proposait une version propre de COBOL, toutes compatibles avec le standard de 1974, mais comportant souvent des extensions spécifiques adaptées aux caractéristiques techniques des machines ou aux besoins particuliers des utilisateurs. Ces ajouts permettaient d'améliorer la performance, d'ajouter de nouvelles fonctions ou de mieux intégrer le langage aux systèmes d'exploitation hôtes.

Toutefois, les implémentations sur micro-ordinateurs (tels que l'Apple, l'IBM PC ou le TRS-80 de Radio Shack) étaient souvent plus limitées que celles des grands systèmes. Elles servaient surtout à des fins pédagogiques, à du prototypage ou à de petites applications de gestion, plutôt qu'à des traitements de masse.

En parallèle, divers groupes universitaires et entreprises informatiques ont également développé leurs propres variantes de COBOL. L'une des plus célèbres reste WATBOL, une version pédagogique conçue par l'Université de Waterloo au Canada. Elle se distinguait par une vitesse de compilation remarquable et une facilité d'utilisation dans un contexte académique, ce qui en a fait un outil très utilisé pour l'enseignement du langage dans les années 1980.

Principales applications du langage de programmation COBOL

Le langage de programmation COBOL a été spécifiquement développé pour répondre aux besoins du traitement de données commerciales. Dès sa conception, il a été pensé pour gérer de vastes volumes d'informations structurées, en particulier dans les secteurs de la finance, de l'administration publique, des assurances et de la gestion d'entreprise. Bien qu'il soit théoriquement possible d'utiliser COBOL pour des applications scientifiques ou de traitement de texte, ce n'est ni sa vocation première ni son domaine de prédilection.

Ce qui distingue COBOL, c'est sa richesse en outils intégrés dédiés à la manipulation de fichiers et de données. Il comprend par exemple des fonctions avancées de recherche dans des tables, des utilitaires de tri puissants, ainsi que des instructions permettant la lecture, l'écriture, le tri et la mise à jour de fichiers séquentiels ou indexés. Ces fonctionnalités sont au cour de l'architecture du langage, et ont été pensées pour faciliter la gestion rigoureuse de données transactionnelles.

Les applications typiques de COBOL concernent la gestion de bases de données clients, le traitement de la paie, la facturation, la comptabilité, la gestion des stocks, ainsi que tout autre domaine nécessitant des traitements répétitifs, fiables et structurés sur de grandes quantités d'informations. Grâce à sa syntaxe claire et à sa proximité avec l'anglais, il permet également une meilleure lisibilité pour les non-programmeurs, comme les gestionnaires ou les analystes métier.

En résumé, COBOL offre au programmeur un environnement robuste pour organiser, extraire, filtrer, classer, mettre à jour et transférer des données stockées dans des fichiers, le tout avec un haut degré de fiabilité. C'est précisément cette capacité à automatiser et sécuriser le traitement de l'information ayant permis à COBOL de s'imposer dans les systèmes d'information critiques depuis plusieurs décennies.

Écrire des programmes COBOL

Un programme écrit en COBOL est organisé de façon très structurée et suit une architecture rigide composée de quatre grandes divisions, appelées «divisions». Chacune de ces divisions a un rôle bien défini dans l'élaboration du programme, et elles doivent apparaître dans un ordre précis pour garantir le bon fonctionnement du code. Voici un aperçu des noms et des fonctions principales de ces divisions fondamentales :

Nom de la division Fonction ou objectif principal
Identification Division Sert à identifier le programme de manière formelle. Elle contient des informations générales comme le nom du programme, son auteur, sa date de création et son but.
Environment Division Permet de définir les caractéristiques matérielles spécifiques à la machine sur laquelle le programme est exécuté, en particulier les périphériques utilisés.
Data Division Décrit en détail toutes les variables, les constantes, les structures de données et les fichiers utilisés dans le programme, y compris leur organisation en mémoire.
Procedure Division Contient l'ensemble du code exécutable du programme, c'est-à-dire les instructions proprement dites, organisées en sections, paragraphes, et phrases.

Chaque division doit être introduite par son nom exact suivi d'un point final. L'ordre des divisions est impératif : toute variation entraînerait une erreur à la compilation. À l'intérieur des divisions, le code est organisé de manière hiérarchique : les divisions contiennent des sections, elles-mêmes composées de paragraphes, étant formés de phrases (appelées sentences), elles-mêmes constituées de mots (words), décomposables en caractères (characters). Cette structure linguistique rappelle celle d'une langue naturelle comme l'anglais, ce qui était d'ailleurs un des objectifs de COBOL : le rendre lisible par des personnes non programmeuses.

Dans COBOL, certains mots ont un statut spécial : ce sont les mots réservés, c'est-à-dire des termes prédéfinis par le langage et ne pouvant pas être réutilisés comme noms de variables, de fichiers ou pour tout autre usage personnel. Ces mots sont indispensables à la syntaxe du langage et leur emploi incorrect entraîne des erreurs. Une liste complète de ces mots réservés est disponible plus loin dans ce fascicule, et ils seront écrits en majuscules pour les distinguer facilement.

Enfin, pour illustrer concrètement la logique de COBOL, un exemple simple de programme est proposé. Il permet de lire une suite de nombres, de calculer leur moyenne, puis de l'afficher à l'écran. Si l'on saisit, par exemple, les valeurs 85.5, 87.5, 89.5 et 91.5, le programme donnera en sortie la moyenne 88.5. Le code repose sur quelques variables : la variable X entrepose la valeur lue à chaque itération, N représente le nombre total de valeurs entrées, SUMX accumule la somme de ces valeurs, et AV contient la moyenne finale.

 IDENTIFICATION DIVISION.                                                                                   
  PROGRAM-ID. AVERAGER.                                                                                     
 
 ENVIRONMENT DIVISION.                                                                                      
 CONFIGURATION SECTION.                                                                                     
   SOURCE-COMPUTER. IBM-PC.                                                                                 
   OBJECT-COMPUTER. IBM-PC.                                                                                 
 
 INPUT-OUTPUT SECTION.                                                                                      
  FILE-CONTROL.                                                                                             
   SELECT INFILE ASSIGN TO DISK.                                                                            
   SELECT OUTFILE ASSIGN TO PRINTER.                                                                        
 
 DATA DIVISION.                                                                                             
 FILE SECTION.                                                                                              
   FD INFILE LABEL RECORDS STANDARD,                                                                        
             VALUE OF FILE-ID IS "B:SCORES".                                                                
   01 A-RECORD.                                                                                             
    02  A-NUMBER      PICTURE X(5).                                                                         
    02  FILLER        PICTURE X(75).                                                                        
   FD OUTFILE LABEL RECORDS OMITTED.                                                                        
   01 A-LINE.                                                                                               
    02 MSG            PICTURE X(20).                                                                        
    02 AV-OUT         PICTURE -9(5).9.                                                                      
    02 FILLER         PICTURE X(52).                                                                        
 WORKING-STORAGE SECTION.                                                                                   
  77   X              PICTURE S99V9.                                                                        
  77   SUMX           PICTURE S9(5)V9 VALUE 0.                                                              
  77   AV             PICTURE S9(5)V9.                                                                      
  77   N              PICTURE S9(5)   VALUE 0.                                                              
  77   EOF            PICTURE X(3)    VALUE "NO".                                                         
 PROCEDURE DIVISION.                                                                                        
 INITIALIZE.                                                                                                
     OPEN INPUT INFILE,OUTPUT OUTFILE                                                                       
     READ INFILE AT END MOVE "YES" TO EOF.                                                                  
     PERFORM READ-LOOP UNTIL EOF = "YES".                                                                   
 
 * FIN DE TRAITEMENT DU FICHIER : AFFICHAGE MOYENNE ET STOP.
          COMPUTE AV = SUMX / N.                                                                            
          MOVE "THE AVERAGE = " TO MSG.                                                                     
          MOVE AV TO AV-OUT.                                                                                
          WRITE A-LINE AFTER ADVANCING 1 LINES.                                                             
          STOP RUN.                                                                                         
 
 * BOUCLE POUR CHAQUE VALEUR DE DONNÉES D'ENTRÉE LUE.
 READ-LOOP.                                                                                                 
          MOVE A-NUMBER TO X.                                                                               
          ADD X TO SUMX.                                                                                    
          ADD 1 TO N.                                                                                       
          READ INFILE AT END MOVE "YES" TO EOF.  

Comme nous avons pu le constater à travers l'analyse du programme, la structure d'un programme COBOL est extrêmement rigide et fortement normée. Il existe des règles très précises concernant l'emplacement des éléments syntaxiques dans chaque ligne de code. Cette codification stricte est une particularité notable du langage, qui impose aux développeurs de respecter des marges définies, appelées "marge A" et "marge B", afin de garantir la lisibilité et la bonne interprétation par le compilateur.

La marge A, correspondant aux positions 8 à 11 sur chaque ligne, est réservée aux éléments structurants du programme. C'est dans cette zone que doivent impérativement apparaître les noms des divisions (comme IDENTIFICATION DIVISION, PROCEDURE DIVISION,...), mais aussi les noms des sections, des paragraphes (par exemple INITIALIZE ou READ-LOOP), les déclarations de variables de niveau 77 (comme X et N), ou encore les enregistrements de niveau 01 (comme A-LINE ou A-RECORD). Les descriptions de fichiers, commençant par le mot-clef FD pour "File Description", sont également alignées dans cette même marge.

En revanche, tout le corps du programme, c'est-à-dire les instructions, les opérations, les expressions et les appels de procédure, doivent être placés dans la marge B, définie par les positions 12 à 72. Cela garantit une séparation claire entre la structure du programme et son contenu exécutable. COBOL permet que certaines instructions se poursuivent d'une ligne à l'autre sans avoir besoin d'un caractère spécial de continuation, ce qui facilite l'écriture de commandes longues. De plus, il est autorisé d'écrire plusieurs instructions sur une seule ligne, ce qui peut rendre le code plus compact, bien que potentiellement moins lisible.

Dans la PROCEDURE DIVISION, chaque phrase (sentence) se termine obligatoirement par un point final (.). Ce point joue un rôle essentiel : il indique au compilateur la fin d'un bloc logique d'instruction. C'est un élément syntaxique crucial que l'on ne peut pas omettre. COBOL se veut un langage proche du langage naturel, ce qui se reflète dans l'utilisation de verbes comme READ, WRITE ou ADD, conservant en anglais leur sens intuitif : lire, écrire, additionner.

Les structures de contrôle comme les boucles utilisent des mots-clés explicites. Par exemple, la construction PERFORM ... UNTIL correspond à une boucle qui s'exécute tant qu'une condition n'est pas remplie. Cela s'apparente à des structures de type repeat ... until ou while ... do dans d'autres langages plus modernes. Il est cependant important de noter que le paragraphe ou bloc de code ciblé par PERFORM n'a pas besoin d'être placé immédiatement après cette instruction. Cela offre une certaine flexibilité, mais nécessite une attention accrue de la part du programmeur pour ne pas désorganiser la logique du traitement.

Une grande précaution doit également être prise avec les enregistrements et la gestion des fichiers, notamment lorsqu'il s'agit de convertir des données d'un format à un autre. En COBOL, chaque fichier utilisé dans le programme doit être préalablement déclaré dans la section FILE-CONTROL, se trouvant elle-même à l'intérieur de l'ENVIRONMENT DIVISION. Ensuite, les enregistrements correspondant à ce fichier doivent être décrits dans la FILE SECTION de la DATA DIVISION. COBOL traite généralement les entrées et sorties par enregistrements complets, plutôt que par flux de données (comme en C ou en Java).

Concernant les commentaires, ils sont introduits par un astérisque placé en position 7 sur la ligne. Toute ligne comportant un astérisque à cette position est ignorée lors de l'exécution du programme. Dans l'exemple de programme pour calculer une moyenne, deux commentaires sont présents dans la PROCEDURE DIVISION, servant à documenter le fonctionnement de certaines parties du code.

Enfin, dans COBOL, chaque mot clef ou élément syntaxique doit être séparé par un espace, représenté par le caractère b dans certains manuels. La ponctuation (comme les virgules, les points, ou les parenthèses) doit être positionnée de manière logique et conforme à son usage habituel en anglais, renforçant ainsi l'aspect "langage naturel" du code COBOL.

Type de données élémentaires et valeurs de représentation en COBOL

Dans le langage COBOL, chaque donnée manipulée dans un programme est associée à une valeur, et cette valeur peut être exprimée sous forme d'un littéral (ou constante littérale). Un littéral est une donnée fixe, inscrite directement dans le code, qui peut être numérique ou alphanumérique, selon le type de variable à laquelle il est destiné. Ces valeurs sont essentielles, car elles permettent d'initialiser, de comparer ou d'assigner des données dans les instructions.

Les littéraux numériques sont très semblables aux nombres décimaux usuels que nous utilisons dans la vie quotidienne. Ils peuvent comporter jusqu'à 18 chiffres significatifs, ce qui permet de représenter de très grands nombres ou des données précises. Ces nombres peuvent être précédés d'un signe positif (+) ou négatif (-), selon leur nature. Il est également possible d'utiliser un point décimal (.) pour indiquer la position des décimales (remarquez que ce point correspond à la virgule utilisée dans les notations françaises). Quelques exemples de littéraux numériques valides en COBOL sont : 1.73, 0, -17, +250.

En plus des valeurs littérales explicites, COBOL propose un ensemble de constantes figuratives. Ces constantes représentent des valeurs standardisées, que l'on retrouve fréquemment dans les programmes, et que l'on peut utiliser pour remplir, initialiser ou comparer des champs. Ces constantes rendent le code plus lisible et facilitent certaines opérations. Voici un tableau explicatif :

Constante Figurative Type de Valeurs Représentées
ZERO, ZEROS, ZEROES Une ou plusieurs occurrences du chiffre zéro. Par exemple, "0", "00", "000" représentent tous la valeur zéro.
SPACE, SPACES Une ou plusieurs occurrences de caractères d'espace (blancs), comme " ", " ", " ". Utile pour effacer ou vider des zones texte.
HIGH-VALUE, HIGH-VALUES Désigne la plus haute valeur possible dans le jeu de caractères utilisé par la machine. Par exemple, "9", "99", "999". Cette valeur est souvent utilisée pour marquer la fin logique d'un champ.
LOW-VALUE, LOW-VALUES Désigne la plus basse valeur possible dans le même jeu de caractères. On peut la représenter par " ", " ", " ", selon la taille souhaitée. Elle est parfois utilisée pour signifier une absence ou une initialisation par défaut.
ALL littéral Permet de remplir une zone de données avec une répétition du même littéral. Par exemple, ALL "14" peut produire "14", "1414", "141414" selon la longueur du champ cible. Cette instruction est très utile pour les zones à motifs répétés.

Il est important de noter que ces constantes peuvent être utilisées dans toutes les parties du programme, notamment dans les instructions d'affectation (MOVE), dans les conditions (IF), ou pour initialiser des zones mémoire lors de la déclaration des structures de données.

Dans le langage de programmation COBOL, un littéral non numérique est une suite ordonnée de caractères entourée de guillemets doubles ("). Ces chaînes représentent des valeurs alphanumériques fixes, souvent utilisées dans les comparaisons, les messages affichés à l'écran, ou encore comme constantes de test dans les structures conditionnelles. Un littéral de ce type peut contenir n'importe quel caractère faisant partie de l'ensemble de caractères autorisé par le système sur lequel le programme s'exécute.

L'ensemble de caractères minimal garanti en COBOL doit inclure une liste de symboles et lettres couramment utilisés. Parmi ceux-ci, on retrouve :

Il est crucial de noter qu'un littéral non numérique doit être entièrement encadré par des guillemets. Et si l'on souhaite inclure un guillemet double à l'intérieur de la chaîne elle-même, il faut alors le doubler pour éviter toute confusion avec le guillemet fermant. Cela signifie que pour insérer un " à l'intérieur du littéral, il faut écrire "".

Voici quelques exemples concrets de littéraux non numériques valides :

"ABC"
"AáBáC"
"ILáDIT""BRAVO!"""

Dans le langage COBOL, les espaces ont une signification particulière lorsqu'ils apparaissent à l'intérieur d'un littéral non numérique. Cela signifie que deux chaînes de caractères qui semblent similaires peuvent, en réalité, être considérées comme différentes si la répartition des espaces n'est pas exactement la même. Par exemple, les deux littéraux "ABC" et "A B C" ne sont pas du tout équivalents, car le second contient des espaces entre les lettres, ce qui modifie sa structure interne et donc sa valeur effective dans le programme. En d'autres termes, chaque caractère, même un espace, compte dans la comparaison ou le traitement d'un littéral.

COBOL propose également un concept très utile appelé constante figurative. Une constante figurative est un mot clef spécial du langage permettant de représenter un type particulier de valeur littérale. Ces constantes permettent au programmeur de référencer des valeurs standardisées sans avoir à écrire explicitement chaque caractère. Elles sont très pratiques pour écrire du code plus lisible, plus clair, et plus facilement maintenable.

Parmi les constantes figuratives les plus utilisées, on retrouve ZERO, SPACE, HIGH-VALUE, LOW-VALUE, ou encore ALL. Chacune d'elles peut désigner une valeur particulière - par exemple ZERO représente un ou plusieurs zéros numériques, tandis que SPACE fait référence à un ou plusieurs espaces.

Il est important de noter que chaque constante figurative peut être écrite de plusieurs manières, souvent avec ou sans s final (exemple ZERO, ZEROS, ou ZEROES), ce qui permet une certaine flexibilité dans la syntaxe. Toutefois, leur interprétation dépend entièrement du contexte dans lequel elles sont utilisées. Une même constante figurative pourra représenter une valeur différente selon qu'elle est utilisée dans une instruction d'affichage, une initialisation de variable, ou une opération de comparaison. C'est pourquoi une bonne compréhension du rôle contextuel de ces constantes est essentielle pour écrire du code COBOL fonctionnel et fiable.

Noms, variables et déclarations en COBOL

Dans le langage de programmation COBOL, une variable représente une entité essentielle utilisée pour stocker des données modifiables au cours de l'exécution du programme. Plus précisément, une variable COBOL est constituée de deux éléments fondamentaux : un nom de donnée (également appelé identificateur) et une valeur associée, cette dernière pouvant évoluer dynamiquement selon le traitement effectué par le programme.

Le nom de donnée est un identifiant textuel qui permet au programmeur de référencer la variable de manière claire et unique dans le code. Ce nom peut être défini librement par le développeur, tant qu'il respecte certaines règles de syntaxe imposées par le langage. De telles variables sont dites user-defined, c'est-à-dire que leur nom est attribué manuellement par l'utilisateur du langage. Cela permet de rendre le code plus lisible et mieux organisé.

Cependant, tous les noms ne sont pas autorisés. En effet, le nom d'une variable doit être unique, afin d'éviter toute confusion lors de l'exécution, et ne doit en aucun cas apparaître dans la liste des mots réservés du langage COBOL. Ces mots réservés sont des termes prédéfinis ayant une signification particulière dans la syntaxe du langage (comme IF, ADD, PERFORM,...), et ne peuvent donc pas être réutilisés pour nommer des variables ou d'autres entités.

Il existe également des variables dites de type FILLER (en anglais : filler fields), servant à remplir ou réserver de l'espace dans une structure de données sans que cet espace soit accessible ou nommé. Le mot-clé FILLER est utilisé dans ce cas pour indiquer que la portion de mémoire correspondante n'a pas besoin d'un identifiant et ne sera pas utilisée explicitement dans le reste du programme. Les fillers sont utiles dans certaines situations, par exemple lors de la description de fichiers dont la mise en page ou la structure exige un espacement régulier ou des zones vides.

Voici la liste des mots réservés :

Dans le langage COBOL, la définition d'une variable repose en premier lieu sur l'attribution d'un nom explicite, aussi appelé nom de donnée, suivi d'une description formelle qui précise ses caractéristiques. Ce nom, essentiel à l'identification et à la manipulation des données, doit suivre une série de règles strictes imposées par la syntaxe du langage.

Un mot défini par le programmeur - c'est-à-dire un identifiant utilisé pour nommer une variable ou une procédure - doit être composé d'un ensemble continu de caractères pouvant inclure jusqu'à 30 symboles maximum. Ces symboles peuvent être :

Cependant, il est impératif que le trait d'union n'apparaisse ni au début, ni à la fin du mot. De plus, pour être valide, le nom d'une variable doit obligatoirement contenir au moins une lettre alphabétique, ce qui garantit qu'il ne puisse pas être confondu avec une valeur purement numérique. Exemples valides : SALAIRE-BRUT, X, N19, 19N.

En complément, COBOL utilise aussi des noms de procédure servant à étiqueter des sections, des paragraphes ou des blocs de traitement. Contrairement aux noms de variable, ces noms ne sont pas obligés d'inclure une lettre alphabétique. Ils servent principalement à identifier des parties de code à exécuter dans un ordre donné.

Un point intéressant est la possibilité d'utiliser des abréviations officielles dans certains mots-clés du langage. Par exemple, la commande CORR peut être utilisée comme une forme abrégée de CORRESPONDING, sans aucune altération de son sens ni de son comportement dans le programme.

Toutes les variables utilisées dans un programme COBOL doivent obligatoirement être déclarées dans la Data Division, étant la section du code spécifiquement dédiée à la définition des structures de données. Une variable peut exister :

Ces deux formes se présentent sous deux syntaxes possibles :

77 nom-de-donnée description.
niveau nom-de-donnée description.

Forme 1 - niveau 77 : Utilisée pour définir une variable indépendante, qui ne fait pas partie d'un ensemble plus large. Ce type de déclaration est simple et direct.

Forme 2 - niveau 01 à 49 : Employée pour définir une variable structurée, étant incluse dans une table, un enregistrement ou un autre regroupement hiérarchique. Le chiffre représentant le niveau détermine la place de la variable dans la hiérarchie de la structure.

Dans les deux cas, chaque déclaration se compose de trois éléments :

Principales clauses utilisées pour décrire une variable :

Clause Rôle ou signification
REDEFINES Permet à deux variables de partager le même emplacement mémoire, utile pour redéfinir un format.
JUSTIFIED Sert à aligner à droite le contenu d'une variable alphanumérique.
PICTURE Définit le format des données : nombre de caractères, types (numérique ou texte), et les règles de présentation comme les symboles de devise ou les zéros initiaux.
USAGE Spécifie la représentation interne de la donnée (par exemple : DISPLAY, COMP, etc.), ce qui influence sa performance et son traitement.
VALUE Permet d'initialiser la variable à une valeur précise au moment de l'exécution du programme.

Parmi toutes les clauses disponibles dans le langage COBOL pour la déclaration des variables, la clause PICTURE (souvent abrégée PIC) est sans doute la plus fondamentale et la plus déterminante. En effet, elle permet de définir avec précision la nature et le comportement attendu d'une variable au sein du programme.

La syntaxe générale de cette clause s'écrit de la manière suivante :

PICTURE [IS] chaîne

L'élément entre crochets (IS) est optionnel, ce qui signifie qu'on peut l'écrire ou l'omettre sans que cela n'altère le bon fonctionnement du programme. Son utilisation reste une question de style ou de clarté pour le programmeur, mais elle n'a pas d'impact technique.

Les variables alphanumériques en COBOL : définition et usage détaillé

Dans le langage COBOL, les variables dites alphanumériques sont des zones de mémoire destinées à entreposer des chaînes de caractères non numériques, c'est-à-dire des données textuelles composées principalement de lettres, d'espaces, voire de certains caractères spéciaux selon le contexte. Ces variables sont déclarées à l'aide de la clause PICTURE (ou PIC en version abrégée), permettant de définir avec précision la structure de la donnée.

Lorsqu'une variable est strictement alphanumérique, la clause PICTURE contiendra une séquence de lettres A, où chaque A représente un caractère alphabétique ou un espace (également appelé "blank"). Le nombre de A dans la clause indique la taille exacte de la variable, c'est-à-dire le nombre de positions mémoire qu'elle occupe, donc la longueur maximale de la chaîne qu'elle pourra contenir.

Par exemple, imaginons une variable nommée TITRE destinée à entreposer un intitulé de document ou de champ, et dont la taille maximale autorisée est de 15 caractères. On pourra alors la déclarer de l'une des deux manières suivantes, à condition qu'elle ne soit ni incluse dans une table ni dans une structure plus complexe :

77 TITRE PIC AAAAAAAAAAAAAAA.
77 TITRE PIC A(15).

Ces deux écritures sont parfaitement équivalentes. La première version explicite chaque caractère de manière répétitive, tandis que la seconde utilise une notation condensée grâce aux parenthèses, indiquant que le caractère A doit être répété 15 fois. Cette seconde forme est plus concise et plus lisible, surtout lorsque la longueur de la chaîne est importante.

Voici un tableau récapitulatif des principaux symboles utilisés dans les chaînes PICTURE, ainsi que leur signification respective. Ils permettent de définir différents types de variables et de préciser la nature des données qu'elles peuvent contenir :

Symbole PICTURE Description
A Représente un caractère alphabétique (de A à Z) ou un espace. Utilisé pour les chaînes textuelles.
B Correspond à un espace (blank). Peut être utilisé dans des formats édités.
S Indique la présence d'un signe (+ ou -) non imprimé. Généralement pour les valeurs numériques.
V Spécifie une virgule décimale implicite, qui ne s'affiche pas mais est utilisée dans les calculs.
X Désigne un caractère alphanumérique générique, incluant lettres, chiffres et certains symboles.
Z Représente un zéro masqué : il n'apparaît pas à l'impression si sa valeur est nulle.
9 Indique un chiffre numérique (de 0 à 9).
$ Insère un symbole monétaire (le dollar $) en début de valeur.
- Permet l'affichage conditionnel d'un signe négatif (-) ou d'un espace si la valeur est positive.

Les variables numériques en COBOL : structure, règles et exemples

En COBOL, une variable numérique est une zone mémoire destinée à contenir uniquement des valeurs numériques, utilisées principalement pour des opérations arithmétiques, des traitements de montants, ou des comptages. La clause PICTURE (abrégée PIC) joue un rôle fondamental dans la définition de ces variables, car elle permet de spécifier la taille, la précision, le signe éventuel et la position du point décimal.

La syntaxe classique d'une clause PICTURE pour une variable numérique est construite à partir d'une suite de chiffres 9, à laquelle on peut ajouter :

Chaque chiffre 9 représente une position de chiffre décimal. Le nombre total de 9 présents dans la clause indique donc combien de chiffres au total la variable peut contenir, indépendamment du fait qu'il s'agisse de chiffres avant ou après la virgule.

Prenons l'exemple de trois variables fréquemment rencontrées dans un programme de gestion : BRUT, I et NET.

Supposons que ces variables doivent permettre de stocker les données suivantes :

Leur déclaration COBOL serait alors :

77 BRUT      PIC 99999V99.
77 I         PIC 999.
77 NET       PIC S99999V99.

Les variables alphanumériques éditées en COBOL

En COBOL, une variable alphanumérique éditée est une zone de données qui permet d'afficher une combinaison précise de valeurs alphanumériques (lettres et chiffres) avec des caractères de mise en forme, tels que des espaces ou des symboles fixes. Cela permet de formater les sorties de manière lisible et structurée, notamment pour des documents imprimés, des rapports, ou encore des fiches de saisie.

La clef de cette définition repose sur la clause PICTURE, déterminant la forme exacte que doit prendre la valeur entreposée dans la variable. Contrairement aux variables alphanumériques simples (où seule une suite de caractères est acceptée), les variables alphanumériques éditées utilisent un mélange de symboles dans la clause PICTURE, permettant de fixer l'apparence de chaque position de caractère.

Voici les principaux caractères de format pouvant figurer dans une clause PICTURE pour ce type de variable :

Caractère Description
A Désigne une lettre alphabétique (A à Z).
X Représente un caractère alphanumérique libre (lettre, chiffre, ou espace).
9 Attend un chiffre numérique (de 0 à 9).
B Correspond à un espace fixe (blank), visible à l'affichage.

Ces symboles peuvent être utilisés seuls ou combinés dans une chaîne PICTURE, parfois accompagnés d'un facteur de répétition, par exemple A(10) signifiant 10 caractères alphabétiques successifs.

Imaginons qu'on souhaite déclarer une variable nommée TITRE dans un programme, en lui donnant une structure précise, comme dans l'exemple suivant :

77 TITRE  PIC 9999BA(10).

Variable numérique éditée

Dans le langage COBOL, une variable numérique dite "éditée" est définie au moyen d'une clause PICTURE contenant une combinaison spécifique de caractères de formatage. Ces caractères incluent principalement B, V, Z, P, 9, -, $, chacun ayant une fonction bien précise dans la représentation des données.

Certains de ces caractères ont été expliqués précédemment - notamment B (espace), V (indicateur de position du point décimal non imprimé), et 9 (chiffre numérique de 0 à 9). Ces conventions restent valables ici, mais de nouveaux éléments viennent s'y ajouter pour enrichir la manière dont les valeurs numériques sont affichées à l'écran ou sur papier.

Lorsqu'on veut supprimer l'affichage des zéros initiaux dans une valeur numérique - par exemple pour alléger la présentation d'un montant financier - on peut remplacer les 9 situés en début de champ par des Z. Cela permet de n'afficher que les chiffres significatifs, en remplaçant les zéros superflus par des espaces blancs lors de l'impression.

Le V, comme dans les variables numériques standards, sert à indiquer l'emplacement du point décimal. Toutefois, pour les variables éditées, il peut également être remplacé par un point (.) afin d'être effectivement visible lors de l'affichage ou de l'impression. Cela permet un formatage plus clair et explicite des valeurs contenant des décimales.

Le symbole $ peut être utilisé pour faire apparaître un signe dollar devant la partie entière d'une valeur monétaire. Il est généralement positionné juste avant les 9 ou les Z les plus à gauche dans la clause PICTURE. Si plusieurs $ sont utilisés à la place des chiffres en tête, alors ce symbole devient "flottant" : il apparaîtra automatiquement aligné à gauche du chiffre le plus significatif, en s'adaptant à la longueur effective de la valeur.

Autre détail important : en ajoutant un - en toute première position dans la chaîne PICTURE, on demande à COBOL d'afficher le signe négatif (si la valeur l'est), ou de laisser un espace si la valeur est positive. Ce symbole agit donc comme un équivalent du S dans les variables numériques simples, permettant de gérer les signes sans que ceux-ci ne soient systématiquement imprimés.

Prenons un exemple pratique. Si l'on souhaite que les variables BRUT et NET soient imprimées avec un point décimal visible, en supprimant les zéros inutiles au début de NET, et en affichant un signe dollar devant la valeur de BRUT, on pourra déclarer ces variables comme suit :

77 BRUT PIC $$$$$$.99.
77 NET  PIC -ZZZZZ.99.

Ainsi, si la variable BRUT contient la valeur 03571.52 et que NET contient -00025.53, l'affichage produit sera le suivant :

$3571.52
-   25.53

Le symbole dollar est positionné juste avant le premier chiffre significatif de BRUT, et les zéros initiaux sont masqués dans NET, remplacés par des espaces pour une meilleure lisibilité.

La clause USAGE

En complément de la clause PICTURE, la clause USAGE permet de préciser la manière dont une variable est représentée en mémoire, c'est-à-dire son format d'entreposage interne. Elle se présente sous la forme suivante :

[USAGE IS] {DISPLAY | COMPUTATIONAL | INDEX}

Les accolades indiquent qu'il faut faire un choix parmi les différentes options proposées.

Si l'on choisit DISPLAY, la variable sera stockée exactement comme elle est affichée : les caractères sont codés tels quels, ce qui est approprié pour des impressions lisibles ou des échanges avec l'utilisateur.

En revanche, COMPUTATIONAL (ou abrégé COMP) signifie que la variable est traitée comme un nombre pur, encodé sous forme binaire pour une meilleure efficacité lors des calculs arithmétiques. Ce type de représentation est donc conseillé pour des variables utilisées intensivement dans des opérations mathématiques.

Enfin, INDEX s'applique exclusivement aux variables servant à indexer des tables ou des structures de données, notamment dans les instructions SEARCH ou SET. Cela optimise la gestion interne de ces éléments.

À noter que si la clause USAGE est omise, COBOL considère automatiquement que l'usage est DISPLAY par défaut.

La clause VALUE

Pour initialiser une variable avec une valeur spécifique au début de l'exécution du programme, on utilise la clause VALUE, permettant d'attribuer un littéral dès la déclaration. Ce littéral peut être un nombre, une chaîne de texte, ou une constante symbolique.

La syntaxe générale est la suivante :

VALUE [IS] littéral

Par exemple, si on souhaite que les variables TITRE, I, et BRUT soient initialisées respectivement avec une chaîne de caractères, une valeur entière nulle, et un montant en devise, la déclaration COBOL pourrait s'écrire ainsi :

77 TITRE PIC X(15) VALUE "RAPPORT ANNUEL".
77 I     PIC 999   VALUE 0 COMP.
77 BRUT  PIC $$$$$$.99 VALUE " 3571.52".

Cela signifie que TITRE contiendra déjà le texte "RAPPORT ANNUEL" au démarrage, I commencera avec la valeur zéro sous format binaire, et BRUT sera initialisé à 3571.52 avec un affichage monétaire.

Tableaux et autres structures de données

En COBOL, il existe principalement deux manières d'associer plusieurs valeurs à une seule entité représentée par une variable. Ces deux méthodes sont les suivantes : la table (souvent appelée array dans d'autres langages de programmation comme Pascal, C, Java ou Python) et l'enregistrement (aussi connu sous le nom de record description entry). Ces deux mécanismes permettent de structurer l'information de manière organisée, mais ils répondent à des besoins différents.

Une table en COBOL représente un ensemble structuré de valeurs, toutes du même type de données. Elle peut être organisée selon une, deux ou même trois dimensions. On parle alors de table unidimensionnelle, bidimensionnelle ou tridimensionnelle, selon la complexité requise.

Exemple de table à une dimension

Prenons tout d'abord un exemple simple. Imaginons une table que nous appellerons A. Il s'agit ici d'un tableau à une seule dimension contenant cinq entrées. Chaque entrée est un entier positif codé sur trois chiffres.

À ses côtés, une autre table, nommée B, illustre un tableau bidimensionnel composé de cinq lignes, chacune contenant quatre valeurs, chaque valeur étant un entier codé sur deux chiffres.

La déclaration COBOL d'une table à une dimension ressemble à ceci :

 01 nom-de-la-table.
    02 nom-de-l-entree     PIC 9(3) OCCURS 5 TIMES.

Et voici une représentation imagée des tables A et B :

A
006
035
217
001
023
B
17 42 00 -10
18 03 00 -11
19 47 19 -12
20 48 49 22
00 00 -2 -3

Exemple de table à deux dimensions

Lorsqu'on souhaite modéliser une structure plus complexe, par exemple un tableau où chaque ligne contient plusieurs colonnes de données, on utilise une table à deux dimensions. Voici la structure typique de sa déclaration COBOL :

 01 nom-de-la-table.
    02 nom-de-ligne        OCCURS 5 TIMES.
       03 nom-de-l-entree  PIC 99 OCCURS 4 TIMES.

Chaque niveau ajoute une granularité supplémentaire : le niveau 02 représente les lignes, et le niveau 03 représente les colonnes au sein de chaque ligne.

Exemple de table à trois dimensions

Dans certains cas encore plus élaborés, il peut être nécessaire de manipuler des données dans un tableau à trois dimensions. Cela permet de représenter des volumes de données structurés par ligne, colonne et profondeur. La déclaration d'une telle structure en COBOL se fait ainsi :

 01 nom-de-la-table.
    02 nom-de-ligne         OCCURS N TIMES.
       03 nom-de-colonne    OCCURS M TIMES.
          04 nom-de-l-entree PIC X OCCURS P TIMES.

Détails communs à toutes les dimensions

Dans chacun de ces trois cas (une, deux ou trois dimensions), l'élément nom-de-la-table correspond au nom principal donné au tableau par le programmeur. Ce nom permet d'identifier la table dans son ensemble au sein du programme.

Les champs appelés description représentent les clauses qui décrivent les caractéristiques de chaque élément individuel du tableau. Il peut s'agir, par exemple, d'une clause PIC (comme PIC 9(3) pour un entier à trois chiffres). Ces descriptions sont écrites exactement de la même manière que pour une variable classique de niveau 77, c'est-à-dire une variable qui contient une seule valeur.

Les noms intermédiaires comme nom-de-ligne, nom-de-colonne et nom-de-l'entrée permettent de désigner précisément chaque dimension dans l'ordre où elles sont déclarées. Ils sont utilisés pour accéder aux éléments de la table de manière structurée et hiérarchique.

Enfin, la clause **OCCURS** joue un rôle crucial : elle permet de spécifier le nombre d'occurrences, c'est-à-dire le nombre d'éléments à inclure pour chaque niveau de dimension dans la table. Grâce à cette clause, il est possible de définir des tableaux de tailles fixes très clairement.

Dans chacun des trois cas évoqués, le terme «nom-de-la-table» désigne un identifiant de table défini explicitement par le programmeur. Ce nom est utilisé dans la structure de déclaration pour regrouper les éléments d'un tableau logique. Le mot «description» fait quant à lui référence à l'ensemble des clauses décrivant les caractéristiques d'un élément composant la table. Ces clauses comprennent notamment des spécifications comme la clause PICTURE, servant à définir le format et la nature des données contenues dans chaque élément de la table, tout comme on le ferait pour une variable indépendante de niveau 77 (n'acceptant qu'une seule valeur).

Les identifiants tels que «nom-de-ligne», «nom-de-colonne» ou encore «nom-de-l-entree» servent à désigner respectivement les lignes, les colonnes ou une cellule spécifique (ou "entrée") au sein de la table multidimensionnelle. Pour définir la taille, c'est-à-dire le nombre d'éléments contenus dans chaque dimension du tableau, on utilise la clause OCCURS. Celle-ci peut être utilisée sous deux formes principales :

OCCURS entier [TIMES] [INDEXED BY indices] (i)
OCCURS entier-1 TO entier-2 [TIMES]
    [DEPENDING ON nom-de-donnee]
    [INDEXED BY indices]
(ii)

Dans la première forme (i), le mot « entier » correspond à un nombre fixe, c'est-à-dire une valeur littérale définissant la quantité d'éléments dans la dimension indiquée. La clause TIMES est optionnelle mais permet d'expliciter davantage la logique de répétition. On peut également ajouter la clause INDEXED BY, permettant de définir une ou plusieurs variables d'index pour référencer les éléments à l'exécution.

Dans la seconde forme (ii), on indique une plage de valeurs à l'aide des bornes inférieure (entier-1) et supérieure (entier-2), définissant la variation du nombre d'éléments. Cette forme peut être dynamique si elle est accompagnée de la clause DEPENDING ON nom-de-donnée. Dans ce cas, c'est la valeur actuelle de «nom-de-donnee» déterminant, au moment de l'exécution, combien d'éléments sont réellement présents dans la table. Là encore, INDEXED BY permet d'associer une ou plusieurs variables d'index pour accéder aux éléments du tableau.

Prenons maintenant deux exemples simples de déclaration de tables pour illustrer les notions vues ci-dessus. Voici comment les tables A et B peuvent être définies en COBOL :

01 TABLE-A.  
   02 A PIC 999 OCCURS 5.  
 
01 TABLE-B.  
   02 LIGNE-B OCCURS 5.  
      03 B PIC S99 OCCURS 4.  

Dans cette structure, la table A contient cinq éléments numériques définis par une clause PIC 999, tandis que B est une table bidimensionnelle organisée en 5 lignes (LIGNE-B) de 4 colonnes contenant des entiers signés (PIC S99).

Il est important de souligner que les valeurs contenues dans les éléments A et B ne peuvent pas être initialisées directement au moment de la déclaration. Bien que la clause VALUE permette d'assigner une valeur initiale à une variable, elle ne peut être utilisée ici que si tous les éléments doivent être initialisés à la même valeur et à condition que le type d'utilisation (USAGE) soit défini comme DISPLAY (et non pas COMP ou INDEX). C'est donc généralement dans la Procedure Division que les tables sont initialisées par des instructions explicites.

Lorsqu'il s'agit d'une variable classique, on y fait simplement référence en mentionnant son nom dans la Procedure Division. Cependant, dans le cas d'un tableau, il existe deux méthodes principales pour référencer un élément selon que la table soit indexée ou non.

1. Si la table n'est pas indexée (c'est-à-dire que la clause INDEXED BY est absente de la déclaration), les éléments sont accédés en utilisant des indices (également appelés subscripts). La syntaxe est la suivante :

nom-de-l-entree (indice [, indice] [, indice])

Ici, «nom-de-l-entree» correspond au nom défini dans la déclaration de la table (dans nos exemples : A ou B). Le nombre d'indices à fournir dépend du nombre de dimensions de la table : un seul pour une table unidimensionnelle, deux pour une table à deux dimensions, etc. Il est essentiel de respecter la syntaxe COBOL, notamment en laissant un espace entre le nom de l'entrée et la parenthèse ouvrante, ainsi qu'entre chaque indice.

Les indices peuvent être soit des valeurs numériques littérales, soit des variables numériques contenant une valeur comprise dans les limites imposées par la clause OCCURS.

Par exemple :

2. Si la table est indexée, c'est-à-dire que la clause INDEXED BY est utilisée dans la déclaration, alors les éléments sont référencés non pas par des indices simples, mais par des index (des variables de type spécial en COBOL). La syntaxe de référence change alors ainsi&nbps;:

nom-de-l-entree (nom-d-index [{+/-} entier] [, nom-d-index [{+/-} entier]], ...)

Il doit y avoir autant de nom-d'index que de dimensions définies dans la table.

Supposons que nous redéclarations la table B de la manière suivante :

01 TABLE-B.  
   02 TABLE-B OCCURS 5 INDEXED BY I.  
      03 B OCCURS 4 PIC S99 INDEXED BY J.  

Le contenu logique de la table reste identique : une structure en 5 lignes et 4 colonnes, avec des entiers signés comme type de donnée. Cependant, la différence ici est que I et J sont maintenant des variables d'index déclarées comme telles, et qu'elles doivent contenir une position valide pour accéder à une entrée. Les intervalles de valeurs valides pour I et J sont respectivement de 1 à 5 et de 1 à 4.

Ainsi, l'expression B(I,J) fera référence à l'entrée située à la i-ème ligne et à la j-ème colonne. Avec des index, on peut même effectuer des décalages dans la référence : par exemple B(I+1,J-2) est une expression valide (à condition que les valeurs calculées restent dans les bornes autorisées). Cette souplesse n'est pas possible avec des indices classiques. Nous approfondirons cette distinction un peu plus loin.

Enfin, il est utile de rappeler qu'un enregistrement en COBOL est une structure regroupant plusieurs variables, généralement de types différents, sous une même entité logique. Voici un exemple de définition d'un enregistrement nommé PERSONNE, comprenant quatre champs distincts :

Champ Description
NOM Une chaîne alphanumérique de 25 caractères
NO-SS Un numéro de Sécurité Sociale, sous forme numérique sur 9 chiffres
BRUT Un salaire brut, valeur numérique avec un format compatible avec des montants jusqu'à 99999,99
PADRESSE Une chaîne alphanumérique de 40 caractères représentant l'adresse de la personne (le nom PADRESSE est choisi ici pour éviter d'utiliser le mot réservé ADRESSE)

Ce type de structure est très courant pour représenter des fiches, des enregistrements de base de données ou des blocs d'information logique dans les programmes COBOL.

En COBOL, lorsqu'on souhaite définir une variable structurée de type enregistrement, il est nécessaire d'utiliser des niveaux hiérarchiques, appelés niveaux de déclaration, indiqués par des numéros de niveau placés avant chaque nom de variable. Ces niveaux permettent de représenter la structure arborescente de l'enregistrement. Le champ principal, qui correspond à l'ensemble de la structure, est toujours défini avec le niveau 01. Ensuite, les champs internes, ou sous-composantes, sont déclarés avec des niveaux inférieurs (comme 02, 03,...), selon leur profondeur dans la hiérarchie.

Prenons un exemple concret : si l'on souhaite représenter une personne à l'aide d'un enregistrement nommé PERSONNE, celui-ci serait défini avec le niveau 01. Ensuite, ses champs élémentaires comme le nom (NOM), le numéro de sécurité sociale (NO-SS), le salaire brut (BRUT) ou l'adresse (PADRESSE) seraient définis avec le niveau 02. Ces sous-champs sont listés de gauche à droite, dans l'ordre de déclaration. Voici comment cette structure pourrait être décrite en COBOL :

     01 PERSONNE.
       02 NOM          PIC X(25).
       02 NO-SS        PIC 9(9).
       02 BRUT         PIC 9(5)V99.
       02 PADRESSE     PIC X(40).

On notera deux points importants ici : premièrement, chaque ligne de déclaration doit se terminer par un point (.) ; deuxièmement, seuls les champs élémentaires, c'est-à-dire ceux qui ne contiennent pas eux-mêmes d'autres champs, sont accompagnés d'une clause PICTURE (abrégée en PIC). Ces champs élémentaires correspondent aux feuilles d'un arbre hiérarchique.

Par ailleurs, un champ de niveau 02, comme NOM ou PADRESSE, peut tout à fait être redéfini comme une structure plus détaillée, c'est-à-dire qu'il peut lui-même devenir un groupe de champs. Par exemple, on peut décider de détailler NOM en trois sous-champs - le prénom, le deuxième prénom, et le nom de famille - en créant une structure intermédiaire IDENTITE. De même, l'adresse PADRESSE peut être divisée en plusieurs parties : rue, ville, état, et code postal. Voici à quoi ressemblerait alors la nouvelle définition plus structurée de l'enregistrement PERSONNE :

   01 PERSONNE.
     02 IDENTITE
       03 PRENOM      PIC X(10).
       03 SECOND      PIC X(5).
       03 NOM         PIC X(10).
     02 NO-SS         PIC 9(9).
     02 BRUT          PIC 9(5)V99.
     02 PADRESSE
       03 RUE         PIC X(17).
       03 VILLE       PIC X(12).
       03 ETAT        PIC X(6).
       03 CODEPOST    PIC 9(5).

Dans cette nouvelle version, IDENTITE et PADRESSE sont devenus des champs de groupe, tandis que PRENOM, SECOND, NOM, RUE, VILLE, ETAT et CODEPOST restent des champs élémentaires, car ce sont eux qui contiennent directement des données. Seuls ces derniers ont donc une clause PIC.

Lorsqu'on souhaite manipuler l'ensemble d'une variable structurée dans la Procedure Division, il suffit de référencer son nom principal, c'est-à-dire celui qui a le niveau 01 (dans notre cas, PERSONNE). C'est ce nom qui représente tout l'enregistrement. Il est essentiel que tous les noms de niveau 01 soient uniques au sein d'un même programme. En revanche, les sous-noms (comme NOM, PADRESSE, etc.) peuvent être répétés dans différentes structures. Cela signifie qu'il est parfaitement autorisé d'avoir plusieurs enregistrements contenant des champs portant le même nom, tant qu'ils ne partagent pas le même niveau 01. Voici un exemple où deux enregistrements, PERSONNE-A et PERSONNE-B, sont définis séparément mais ont des champs de même nom :

01 PERSONNE-A.
   02 NOM                  PIC X(25).
   02 NO-SS                PIC 9(9).
   02 BRUT                 PIC 9(5)V99.
   02 PADRESSE             PIC X(40).
01 PERSONNE-B.
   02 NOM                  PIC X(25).
   02 NO-SS                PIC 9(9).
   02 BRUT                 PIC 9(5)V99.
   02 PADRESSE             PIC X(40).

Dans un tel cas, si l'on souhaite accéder au champ NO-SS du premier enregistrement (PERSONNE-A), on devra le faire de manière explicite, en écrivant : NO-SS OF PERSONNE-A. De la même façon, pour accéder à ce champ dans PERSONNE-B, on écrira : NO-SS OF PERSONNE-B. Cette précision n'est requise que lorsque le nom du champ n'est pas unique dans le contexte. Si un champ n'existe qu'une seule fois dans tout le programme, on peut se contenter d'utiliser son nom seul, sans ambiguïté.

Enfin, COBOL permet également d'inclure des tables à l'intérieur d'un enregistrement, ce qui est très utile pour conserver des valeurs multiples d'un même type. Supposons que nous souhaitons enregistrer les cinq dernières adresses connues d'une personne, au lieu d'une seule adresse courante. On pourrait alors définir une table dans l'enregistrement PERSONNE de la manière suivante :

01 PERSONNE
   02 NOM          PIC X(25).
   02 MO-SS        PIC 9(9).
   02 BRUT         PIC 9(5)V99.
   02 PADRESSE     PIC X(40) OCCURS 5 TIMES.

Le mot clef OCCURS permet ici de spécifier que le champ PADRESSE est une table composée de cinq éléments, chacun ayant une structure de PIC X(40). On pourra ensuite accéder à chaque adresse individuelle à l'aide d'un indice ou d'un index, exactement comme on le ferait avec un tableau classique. Cela permet de stocker, de parcourir ou de modifier plusieurs valeurs du même champ au sein d'une seule et même structure.

Les instructions de base COBOL

Dans le cadre de cette page, notre objectif n'est pas de présenter de manière exhaustive l'ensemble des instructions COBOL disponibles dans le langage. Une telle entreprise, bien que possible, ne serait pas nécessairement pertinente ici. En effet, il nous paraît plus judicieux de concentrer notre attention sur les instructions les plus couramment utilisées en pratique, c'est-à-dire celles que l'on retrouve le plus fréquemment dans les programmes COBOL opérationnels.

Ainsi, pour alléger le propos et rester centré sur l'essentiel, nous exclurons volontairement de cette présentation certaines instructions que l'on rencontre rarement dans les applications standard. Parmi ces instructions mises de côté, on peut citer : ACCEPT, ALTER, CANCEL, DISABLE, ENABLE, ENTER, RECEIVE, START, SUPPRESS et USE. Bien que ces commandes fassent partie intégrante du langage COBOL, leur usage est plus ponctuel, voire spécifique à certains contextes ou environnements particuliers.

Pour vous aider à mieux visualiser l'ensemble des instructions que nous allons effectivement étudier dans ce fascicule, nous vous proposons ci-dessous un tableau récapitulatif. Celui-ci énumère les instructions sélectionnées et propose, pour chacune d'elles, une brève description de leur rôle et de leur usage principal :

Instruction Description
ADD Réalise des opérations arithmétiques d'addition et affecte le résultat à une variable ou à un élément d'un tableau.
SUBTRACT Soustrait une valeur à une autre, avec même principe d'affectation du résultat.
MULTIPLY Multiplie deux nombres et entrepose le résultat.
DIVIDE Effectue une division entre deux valeurs numériques.
COMPUTE Permet des calculs plus complexes avec plusieurs opérateurs.
CALL Transfère l'exécution à un sous-programme externe.
EXIT PROGRAM Termine un sous-programme et revient au programme principal.
CLOSE Ferme un fichier ouvert précédemment.
DELETE Supprime un enregistrement logique dans un fichier.
OPEN Ouvre un fichier pour une opération de lecture ou d'écriture.
READ Lit un enregistrement depuis un fichier.
REWRITE Réécrit un enregistrement dans un fichier après modification.
WRITE Insère un nouvel enregistrement dans un fichier.
COPY Permet l'insertion, lors de la compilation, d'un morceau de code source provenant d'une bibliothèque COBOL externe.
GENERATE Utilisé dans les programmes de reporting.
INITIATE Prépare la génération d'un rapport structuré.
TERMINATE Termine la génération d'un rapport.
GO TO Transfert de contrôle inconditionnel vers un autre bloc.
IF Exécute une ou plusieurs instructions en fonction d'un test.
PERFORM Appelle un paragraphe ou une section à exécuter.
INSPECT Analyse une chaîne de caractères pour y rechercher ou remplacer des éléments.
SEARCH Recherche dans une table ou un tableau.
SET Affecte une valeur à une variable ou à un index.
MERGE Fusionne deux fichiers déjà triés.
RELEASE Prépare des enregistrements pour un tri (tri par lots).
RETURN Renvoie un enregistrement d'un fichier dans une opération de type reporting.
SORT Trie un fichier selon un ou plusieurs critères définis.
MOVE Transfère des données d'un champ à un autre.
STRING Permet de concaténer plusieurs chaînes de caractères.
UNSTRING Découpe une chaîne en plusieurs parties selon un séparateur.

Toutes les instructions ne figurant pas dans ce tableau font l'objet d'une explication détaillée dans d'autres sections de cette page. Pour bien débuter notre apprentissage, revenons à un exemple que vous avez déjà rencontré dans les premières pages de ce fascicule : le programme AVERAGER.

Dans ce programme, vous avez pu observer plusieurs déclarations COBOL typiques, notamment des variables simples comme X ou AV, ainsi que des structures de type enregistrement comme A-LINE, toutes définies dans la Data Division.

Mais c'est dans la Procedure Division que se trouvent les véritables instructions de contrôle du programme. Cette division représente la partie procédurale du code, là où se déroule effectivement le traitement logique.

La Procedure Division peut être structurée en plusieurs sections. Chacune de ces sections peut ensuite être divisée en paragraphes, eux-mêmes composés d'instructions COBOL. Voici la hiérarchie typique que l'on peut observer :

Dans cette structure :

Dans notre exemple de programme, la Procedure Division contient deux paragraphes bien identifiés : l'un nommé INITIALIZE, et l'autre READ-LOOP. Ce sont deux blocs de traitement indépendants dans lesquels s'exécutent les instructions nécessaires à l'initialisation des données et à la lecture répétée de lignes d'entrée.

Expressions arithmétiques en COBOL

Les expressions arithmétiques jouent un rôle fondamental dans un programme COBOL, car elles permettent d'indiquer une séquence d'opérations mathématiques destinées à produire un résultat à partir de variables ou de constantes numériques. Elles interviennent notamment dans les instructions comme COMPUTE ou IF, où des calculs sont nécessaires pour prendre des décisions ou effectuer des affectations conditionnelles.

Une expression arithmétique peut se présenter sous plusieurs formes. En voici les principales :

Ces expressions font appel à un ensemble restreint d'opérateurs arithmétiques, ayant chacun une signification bien précise :

Opérateur arithmétique Signification
+ Addition
- Soustraction
* Multiplication
/ Division
** Élévation à une puissance

Ces opérateurs sont tous utilisés en notation infixée, ce qui signifie qu'ils s'insèrent entre deux opérandes (par exemple : A + B). Il est important de noter que chacun nécessite exactement deux opérandes, ce qui rend leur structure assez régulière.

Par exemple, si l'on écrit l'expression suivante :

H + 2

Cela indique que l'on souhaite ajouter la valeur contenue dans la variable H au nombre 2, ce dernier étant un littéral numérique. Voici un cas légèrement plus complexe :

     H + 2 + I
         ↑   ↑
         1   2

Dans cet exemple, on additionne d'abord H et 2, puis le résultat obtenu est additionné à I. Les numéros sous l'expression indiquent l'ordre d'évaluation, ici de gauche à droite, ce qui correspond au comportement par défaut des expressions COBOL (à quelques exceptions près, que nous verrons plus loin).

Cependant, COBOL applique une hiérarchie entre les opérateurs : toutes les opérations ne sont pas traitées avec la même priorité. Voici l'ordre dans lequel les opérations sont généralement exécutées :

Ce classement signifie que, même si l'ordre de lecture est de gauche à droite, les opérations les plus prioritaires sont effectuées en premier. Considérons cet exemple :

     H + 2 * I
         ↑   ↑
         2   1

Ici, la multiplication 2 * I est effectuée avant l'addition à H. Ainsi, même si le + est situé avant dans l'écriture, la priorité est donnée à l'opérateur *. Cette hiérarchie est cruciale pour éviter les erreurs de logique dans les calculs.

Heureusement, le programmeur peut surcharger cette priorité s'il le souhaite, grâce aux parenthèses. En entourant une expression, on force son évaluation avant les autres. Reprenons l'exemple précédent, mais en modifiant l'ordre d'exécution voulu :

     ( H + 2 ) * I
           ↑     ↑
           1     2

Ici, c'est d'abord la somme de H et 2 qui est effectuée, puis le résultat est multiplié par I. Le placement des parenthèses change complètement la logique du calcul. Le rôle des parenthèses est donc essentiel pour maîtriser l'ordre d'évaluation.

Enfin, il est important de rappeler que COBOL exige un espace (au moins un blanc) avant et après chaque opérateur. Cela signifie que les expressions 6-I et 6 - I ne sont pas équivalentes. Seule la deuxième est correcte, car dans la première, le tiret (-) est collé au 6, ce qui pourrait être interprété comme un nom de variable ou comme une erreur de syntaxe. En effet, COBOL est strict à ce sujet, et un espace manquant peut changer radicalement le sens de l'instruction.

Instructions arithmétiques en COBOL

COBOL propose un ensemble d'instructions arithmétiques permettant d'effectuer des opérations de base sur des valeurs numériques. Ces instructions sont au nombre de cinq : ADD, SUBTRACT, MULTIPLY, DIVIDE, et COMPUTE. Chacune de ces instructions permet de manipuler des données numériques selon des règles bien définies, tout en offrant des options supplémentaires pour gérer des cas particuliers.

Ces cinq instructions partagent deux options communes particulièrement utiles dans le cadre de calculs sensibles :

Nous reviendrons sur la signification et le rôle exact de ces deux options à la fin de cette section. Pour le moment, concentrons-nous sur les spécificités de l'instruction ADD, qui sert à réaliser des additions.

L'instruction ADD peut être écrite selon deux syntaxes distinctes, en fonction du résultat attendu ou de la manière dont les valeurs doivent être combinées et entreposées.

(i) Forme classique :

ADD liste-de-valeurs TO liste-d-identificateurs [ROUNDED] [SIZE ERROR].

Cette première forme permet d'additionner l'ensemble des éléments présents dans la liste-de-valeurs à chacun des éléments de la liste-d'identificateurs. Cela signifie que chaque variable ciblée verra sa valeur augmentée de la somme des valeurs listées.

Voici un exemple d'utilisation de cette première forme :

ADD I TO N

Dans ce cas, la liste-de-valeurs se réduit à un seul élément : la variable I. Elle est ajoutée à la variable N, figurant dans la liste-d-identificateurs. L'instruction effectue donc l'opération : N := N + I.

(ii) Forme avec GIVING :

ADD valeur, liste-de-valeurs GIVING liste-d-identificateurs [ROUNDED] [SIZE ERROR].

La seconde forme diffère de la première dans la mesure où le résultat de l'addition n'est pas ajouté à une variable existante, mais entreposé directement dans une ou plusieurs variables cibles, après le mot-clé GIVING.

L'exemple précédent peut être réécrit avec cette syntaxe :

ADD 1, N GIVING N

Dans cette version, la constante 1 et la valeur contenue dans la variable N sont additionnées, et le résultat est attribué directement à la variable N, remplaçant ainsi sa valeur initiale. Cela revient à calculer N := 1 + N.

L'instruction SUBTRACT en COBOL permet d'effectuer des opérations de soustraction sur des variables numériques. Comme pour l'instruction ADD, COBOL propose deux façons distinctes d'écrire SUBTRACT, selon que l'on souhaite modifier directement des variables existantes ou bien entreposer le résultat dans une ou plusieurs autres variables spécifiques.

Les deux formes syntaxiques prennent en compte les mêmes options que pour les autres opérations arithmétiques : ROUNDED, SIZE ERROR.

Ces options permettent respectivement d'arrondir le résultat ou de détecter une erreur de dépassement de taille, et seront expliquées en détail à la fin de cette section.

Voici les deux formes disponibles pour écrire l'instruction SUBTRACT :

SUBTRACT liste-de-valeurs FROM liste-d'identificateurs
[ROUNDED]
[option SIZE ERROR]
(i)
SUBTRACT liste-de-valeurs FROM identificateur
GIVING liste-d-identificateurs
[ROUNDED]
[option SIZE ERROR]
(ii)

Définition des éléments :

Dans la première syntaxe, le calcul s'effectue directement sur la variable cible : pour chaque identificateur présent dans la liste-d-identificateurs, on soustrait la somme de tous les éléments de la liste-de-valeurs à sa valeur actuelle. Le résultat est ensuite replacé dans cette même variable, écrasant ainsi son ancienne valeur.

Voici un exemple concret illustrant cette première forme :

SUBTRACT 1 FROM I

Dans cette instruction, la constante 1 est soustraite de la variable I, et le résultat est replacé dans I. Cela équivaut à faire l'opération suivante en Pascal :

  1. I := I - 1

Il est important de noter que si la liste-d-identificateurs contient plusieurs variables, la soustraction est appliquée séparément à chacune d'elles.

La seconde forme permet de conserver intactes les valeurs d'origine utilisées dans le calcul et de stocker le résultat dans une ou plusieurs autres variables. Contrairement à la première forme, la variable mentionnée après le mot-clef FROM n'est pas modifiée (sauf si elle apparaît également dans la liste-d-identificateurs).

Cette forme est structurée comme suit :

SUBTRACT liste-de-valeurs FROM identificateur GIVING liste-d'identificateurs

Le principe est le suivant : on calcule la soustraction entre la valeur de l'identificateur et la somme de la liste-de-valeurs, puis on place le résultat dans chaque élément de la liste-d'identificateurs.

Prenons un exemple pour clarifier cela :

SUBTRACT 1 FROM I GIVING H

Dans ce cas, on soustrait la valeur 1 de celle contenue dans la variable I, et le résultat est stocké dans la variable H. La variable I reste inchangée, à moins qu'elle ne figure également dans la liste après GIVING.

Cela revient à écrire l'opération suivante en Pascal :

  1. H := I - 1

Ainsi, cette forme est particulièrement utile lorsque l'on souhaite conserver la variable source intacte tout en exploitant le résultat du calcul dans une autre variable.

COBOL propose des instructions arithmétiques précises pour effectuer des opérations de multiplication et de division. Ces opérations s'écrivent respectivement à l'aide des mots-clefs MULTIPLY et DIVIDE. Elles peuvent être utilisées de manière flexible, avec ou sans l'option GIVING, selon que l'on souhaite ou non modifier une variable existante ou plutôt stocker le résultat dans une nouvelle variable.

Les formes standard de ces deux instructions sont les suivantes :

MULTIPLY valeur-1 BY valeur-2 [GIVING identificateur-3]
        [ROUNDED]
        [option SIZE ERROR]
DIVIDE valeur-1 BY valeur-2 GIVING identificateur-3 [ROUNDED]
        [REMAINDER identificateur-4]
        [option SIZE ERROR]

Les paramètres valeur-1 et valeur-2 peuvent être soit des valeurs littérales (exemple : 3, 10), soit des variables numériques. Ils représentent les opérandes à multiplier ou diviser.

Les identificateur-3 et identificateur-4 sont des variables numériques. Le premier est utilisé pour stocker le résultat principal de l'opération, tandis que le second (dans le cas de DIVIDE) peut être utilisé pour stocker le reste de la division, si nécessaire.

L'instruction MULTIPLY sert à calculer le produit de deux valeurs numériques. Si l'option GIVING est précisée, le résultat de la multiplication sera stocké dans la variable indiquée après ce mot-clé. Cela permet de conserver les variables d'origine inchangées.

Voici un exemple typique de cette utilisation :

MULTIPLY 3 BY H GIVING I

Dans cette instruction, la valeur 3 est multipliée par le contenu de la variable H, et le résultat est ensuite rangé dans la variable I. Ainsi, I contiendra le produit de 3 * H. Les variables 3 (littéral) et H (variable source) ne sont pas modifiées dans cette opération.

Cependant, il est tout à fait possible d'utiliser l'instruction MULTIPLY sans le mot-clef GIVING, auquel cas le résultat de la multiplication sera directement stocké dans la deuxième variable mentionnée (valeur-2). Il est donc impératif que cette seconde valeur soit une variable, car elle recevra le nouveau contenu.

Voici un exemple clair illustrant ce cas :

MULTIPLY 3 BY H

Ici, le produit de 3 * H est immédiatement enregistré dans H, écrasant la valeur précédente contenue dans cette variable. Cette forme est utile lorsqu'on veut modifier directement une variable en la multipliant par une constante ou une autre variable.

L'instruction COBOL DIVIDE permet d'effectuer une opération de division arithmétique entre deux éléments numériques. Son rôle est d'attribuer à une variable désignée par identificateur-3 le résultat de la division du premier opérande, nommé valeur-1, par le second, valeur-2. Si l'on souhaite également récupérer le reste de cette division (c'est-à-dire la portion résiduelle non divisible), on peut utiliser l'option REMAINDER, qui affectera cette valeur à une autre variable spécifiée, appelée identificateur-4. Voici un exemple illustrant l'utilisation combinée de GIVING et REMAINDER dans une instruction DIVIDE :

DIVIDE 5 BY 2 GIVING I REMAINDER J

L'exécution de cette ligne entraînera l'attribution de la valeur entière 2 à la variable I, tandis que la variable J recevra la valeur 1, représentant le reste de la division de 5 par 2.

Par ailleurs, COBOL propose également l'instruction COMPUTE, autorisant la réalisation d'opérations arithmétiques complexes (addition, soustraction, multiplication, division,...), tout en entreposant le résultat dans une variable. Cette instruction peut inclure une opération d'arrondi (ROUNDED) ainsi qu'une clause de gestion d'erreurs de taille (ON SIZE ERROR). Sa syntaxe générale est la suivante :

COMPUTE identificateur [ROUNDED] = expression arithmétique
 [ON SIZE ERROR instruction]

L'identificateur ici représente une variable numérique dans laquelle sera enregistré le résultat obtenu après l'évaluation complète de l'expression arithmétique. Cette méthode s'avère particulièrement utile pour simplifier les calculs dans un programme. Par exemple, dans le cas d'un programme de calcul de moyenne, au lieu d'utiliser une instruction ADD, on peut écrire :

COMPUTE SUMX = SUMX + X

Ceci permet d'ajouter la valeur de X à celle déjà contenue dans SUMX, de façon plus concise et flexible que les instructions arithmétiques classiques.

L'option ROUNDED, placée juste après le nom de la variable cible, permet d'arrondir le résultat au chiffre décimal le plus proche avant de l'y affecter. Cela est particulièrement pertinent pour des calculs monétaires ou lorsqu'une précision limitée est requise par la définition des variables. Considérons l'instruction MULTIPLY appliquée dans un contexte pratique, avec les déclarations suivantes :

77 HEURES PIC 9(2)V9.
77 TAUX   PIC 9V99.
77 BRUT   PIC 9(5)V99.

Ici, HEURES représente le nombre d'heures travaillées, TAUX le taux horaire, et BRUT le montant du salaire brut à calculer. Supposons maintenant qu'un ouvrier ait travaillé 37,5 heures à un taux horaire de 5,25 dollars. Pour calculer son salaire brut et l'arrondir au cent le plus proche, on utilisera :

MULTIPLY HEURES BY TAUX GIVING BRUT ROUNDED

Cette instruction produit une valeur arrondie de 196,88 $ (car 37,5 × 5,25 = 196,875, qui arrondi au cent donne 196,88). Si l'on avait omis le mot clef ROUNDED, la valeur affectée à BRUT aurait été 196,87 $, tronquée à deux décimales.

Une attention particulière doit être portée à la définition (c'est-à-dire au PICTURE) de la variable qui reçoit le résultat. Si le format de BRUT avait été défini plus restrictivement, par exemple PIC 9(2)V99, alors cette instruction aurait produit une erreur de format, aussi appelée "size error condition". Cela se produit lorsque le résultat de l'opération dépasse la capacité numérique maximale définie par le PICTURE. Dans de tels cas, si l'option ON SIZE ERROR n'est pas utilisée, le contenu final de la variable cible est imprévisible.

Pour sécuriser ce type d'opération et capturer une erreur éventuelle sans compromettre l'exécution du programme, on peut ajouter l'option ON SIZE ERROR, comme dans l'exemple suivant :

MULTIPLY TAUX BY HEURES GIVING BRUT
 ON SIZE ERROR GO TO MAUVAIS-BRUT

Ici, si le produit de TAUX et HEURES excède 99,99 (la limite autorisée par PIC 9(2)V99), l'exécution de l'instruction MULTIPLY n'affectera pas BRUT. Le programme sera automatiquement redirigé vers le paragraphe MAUVAIS-BRUT, prévu pour gérer cette erreur de dépassement de format. Cette méthode permet une gestion robuste des exceptions arithmétiques, tout en assurant la continuité du traitement.

L'instruction MOVE

L'instruction MOVE en COBOL est utilisée pour affecter une valeur spécifique à une ou plusieurs variables. Elle permet de transférer des données d'un emplacement mémoire à un autre, tout en tenant compte des types et formats des champs impliqués. Sa syntaxe générale est la suivante :

MOVE valeur TO liste-d-identificateurs

Dans cette structure, le mot clef valeur peut désigner soit une constante (littéral), soit une variable, tandis que liste-d-identificateurs représente une série de noms de variables séparés par des virgules et des espaces. L'effet de l'instruction est simple : la valeur spécifiée est copiée dans chacune des variables de la liste, dans l'ordre.

Par exemple, dans un programme COBOL calculant une moyenne, on peut trouver l'instruction suivante :

MOVE "VRAIE MOYENNE = " TO MSG

Ici, le texte littéral "TRUE AVERAGE = " est affecté à la variable MSG.

Il est important de noter que les éléments désignés par valeur et par liste-d-identificateurs peuvent également être des objets structurés, c'est-à-dire des groupes contenant plusieurs sous-champs. Dans ce cas, toutes les structures impliquées doivent être identiques en forme et en composition (même nombre et types de sous-champs dans le même ordre). Si cette condition est remplie, l'instruction MOVE est équivalente à une série d'instructions MOVE individuelles appliquées à chaque paire de sous-champs correspondants.

Lorsqu'on utilise MOVE avec des variables élémentaires (non structurées), toutes les variables impliquées doivent appartenir à la même catégorie de données. Cela signifie qu'elles doivent être soit toutes numériques, soit toutes non numériques (par exemple alphanumériques, alphanumériques éditées,...).

Prenons l'exemple suivant :

MOVE 1 TO N

Dans ce cas, 1 est une valeur numérique, et N doit être lui aussi un champ numérique. Si ce n'est pas le cas, une erreur peut survenir, ou COBOL pourrait effectuer une conversion automatique, selon le compilateur utilisé.

En effet, chaque fois que la valeur source et la variable de destination ont des clauses PICTURE différentes, une conversion de format est automatiquement effectuée avant l'affectation. Cette conversion dépend du type de données :

Pour les valeurs numériques, la conversion s'effectue en alignant les chiffres sur la virgule décimale. Si nécessaire, des zéros sont ajoutés, ou des chiffres en excès sont tronqués, soit au début du nombre, soit dans la partie décimale, selon la clause PICTURE du champ cible.

Pour les valeurs alphanumériques, la conversion consiste uniquement à ajuster la longueur de la chaîne. Si la chaîne est trop longue, les caractères excédentaires sont supprimés à droite. Si elle est trop courte, des espaces sont ajoutés à droite pour combler la différence.

Les exemples suivants illustrent clairement le comportement de l'instruction MOVE dans différents cas de figure :

Valeur à affecter PICTURE de destination Résultat après MOVE
3.19 9V9 3.1
V99 19
99V99 03.19
"TEXTE" X(4) "TEXT"
X(5) "TEXTE"
X(6) "TEXTE " (rempli)

Il est essentiel de comprendre que ces conversions ne sont appliquées que lorsque les objets sont élémentaires. Lorsque la valeur source et la variable cible sont des structures (groupes), COBOL n'effectue aucune vérification des clauses PICTURE, ni conversion implicite. Le contenu est copié tel quel, comme s'il s'agissait d'un simple bloc de mémoire à transférer. Cela signifie que le comportement peut être imprévisible si les structures ne sont pas compatibles.

Prenons l'exemple suivant, où deux structures C et D sont définies comme suit :

01 C.
   02 C1 PIC X.
   02 C2 PIC X.
 
01 D.
   02 D1 PIC X(3).
   02 D2 PIC X(3).

Et supposons qu'on exécute l'instruction suivante :

MOVE "TEXTE" TO C, D

Dans ce cas, le contenu de la chaîne "TEXTE" est copié dans les deux structures, champ par champ, sans tenir compte de la taille exacte des champs. Le résultat sera :

Champ Contenu après le MOVE
C1 T
C2 E
D1 TEX
D2 TE (avec espace)

Ce comportement montre bien que le MOVE appliqué à des groupes ignore totalement les clauses PICTURE des champs internes. Par conséquent, il est impératif de s'assurer que les structures source et destination ont des définitions strictement compatibles, sous peine d'avoir des résultats incohérents.

Instructions STRING et UNSTRING

Les instructions STRING et UNSTRING permettent au langage COBOL d'effectuer des manipulations de chaînes de caractères, offrant ainsi des fonctionnalités utiles pour assembler ou découper des données non numériques. L'instruction STRING est utilisée pour concaténer (c'est-à-dire assembler) plusieurs valeurs non numériques, souvent appelées chaînes, en une seule chaîne continue. À l'inverse, l'instruction UNSTRING permet d'effectuer l'opération opposée : elle décompose une chaîne en plusieurs sous-chaînes de caractères, selon des règles de délimitation définies.

Voici la syntaxe générale de ces deux instructions :

STRING liste-de-valeurs-1 [DELIMITED [BY] { valeur-a | SIZE }]
     [, liste-de-valeurs-2 [DELIMITED [BY] { valeur-2 | SIZE }]]
     ...
     INTO identificateur [WITH POINTER ptr]
     [ON OVERFLOW instruction]
UNSTRING identificateur [DELIMITED [BY] liste-de-délimiteurs]
     INTO liste-d-identificateurs
     [ON OVERFLOW instruction]

Description des éléments :

Fonctionnement de l'instruction STRING

L'exécution de STRING consiste à prendre les différents éléments contenus dans les listes de valeurs (dans l'ordre où ils sont mentionnés), à les concaténer, puis à stocker le résultat final dans la variable cible (identificateur). Ce remplissage se fait de gauche à droite, caractère après caractère.

Si le contenu total à insérer dépasse la capacité définie par le PICTURE de la variable cible, alors une erreur de type OVERFLOW (dépassement de capacité) est déclenchée. Si la clause ON OVERFLOW est présente, l'instruction qu'elle contient sera exécutée immédiatement pour gérer cette erreur. Sinon, le comportement dépend de l'environnement d'exécution, mais le programme peut se poursuivre avec un contenu tronqué.

Dans le cas contraire, si la concaténation génère une chaîne plus courte que la taille disponible dans la variable de destination, alors les caractères restants dans cette dernière (ceux situés à droite de la fin de la nouvelle chaîne) restent inchangés.

Options DELIMITED BY

Deux options de délimitation sont disponibles :

Utilisation de WITH POINTER

L'option WITH POINTER ptr permet de spécifier une position précise dans la variable de destination à partir de laquelle l'écriture doit commencer. La valeur actuelle de ptr (qui doit être une variable numérique) détermine l'emplacement du premier caractère inséré. Cela permet par exemple d'enchaîner plusieurs instructions STRING en remplissant progressivement une même chaîne cible.

Fonctionnement de l'instruction UNSTRING

L'instruction UNSTRING fonctionne selon un principe inverse. Elle sert à découper une chaîne de caractères contenue dans une variable (identificateur) en plusieurs sous-chaînes, qui seront stockées dans les variables spécifiées dans liste-d'identificateurs.

Le découpage est basé sur des délimiteurs spécifiés dans la clause DELIMITED BY. Ces délimiteurs peuvent être des chaînes de caractères fixes ou des variables contenant ces chaînes. Plusieurs délimiteurs peuvent être indiqués en les séparant avec le mot OR.

Chaque fois qu'un délimiteur est rencontré dans la chaîne source, COBOL extrait les caractères précédents et les place dans la variable suivante de la liste de destination. L'instruction s'arrête dès que toutes les variables de la liste ont été remplies ou que la chaîne source est entièrement traitée.

Si un dépassement se produit - par exemple si la chaîne d'origine contient plus de segments que de variables de destination, ou qu'un segment dépasse la taille autorisée par son PICTURE - alors la clause ON OVERFLOW, si elle est présente, sera exécutée pour gérer cette situation.

L'instruction INSPECT en COBOL

L'instruction INSPECT enrichit les capacités du langage COBOL en matière de traitement de chaînes de caractères. Elle permet d'analyser, de rechercher, de compter, et même de remplacer des séquences de caractères à l'intérieur d'une chaîne existante. Grâce à cette instruction, il devient possible d'identifier précisément des occurrences de sous-chaînes au sein d'un champ alphanumérique, d'en mesurer le nombre, et, si nécessaire, de les substituer par d'autres chaînes. C'est donc un outil polyvalent pour manipuler dynamiquement des données textuelles.

La forme générale de l'instruction INSPECT est la suivante :

INSPECT identificateur-1
    TALLYING id-2 FOR { ALL valeur-1 | LEADING valeur-1 | CHARACTERS }
        [BEFORE { INITIAL valeur-2 | AFTER valeur-2 }]
    REPLACING { ALL valeur-3 | LEADING valeur-3 | FIRST valeur-3 }
        BY valeur-4
        [BEFORE { INITIAL valeur-5 | AFTER valeur-5 }]

Définition des composantes :

Fonctionnement de TALLYING

La clause TALLYING permet de compter soit des occurrences de sous-chaînes spécifiques, soit des caractères. Cette opération ne modifie pas le contenu de identificateur-1, mais met à jour la valeur de id-2.

Il existe trois variantes principales de cette clause :

Clauses optionnelles BEFORE et AFTER

On peut restreindre la zone d'analyse en précisant un point de départ ou d'arrêt avec les options suivantes :

Ces options permettent d'affiner la recherche ou le comptage à une portion ciblée de la chaîne source.

Fonctionnement de REPLACING

La clause REPLACING modifie directement le contenu de identificateur-1 en remplaçant certaines parties identifiées selon les critères suivants :

Clauses BEFORE et AFTER avec REPLACING

Comme pour TALLYING, on peut restreindre la zone d'action du remplacement :

Comportement général de l'instruction INSPECT

Lorsqu'on exécute une instruction INSPECT, le comportement dépend des options choisies. Si seule la clause TALLYING est présente, la chaîne source (identificateur-1) reste inchangée, et seule la variable compteur (id-2) est modifiée. Cette dernière doit être initialisée auparavant, ailleurs dans le programme COBOL, car INSPECT ne le fait pas automatiquement.

Si la clause REPLACING est utilisée, alors identificateur-1 est modifié en mémoire, les remplacements s'appliquant selon les options choisies. Une instruction INSPECT valide doit inclure au moins l'une des deux clauses principales (TALLYING ou REPLACING), et peut en contenir les deux simultanément.

Cette instruction est particulièrement utile dans les traitements de données textuelles où l'on doit valider, reformater, ou nettoyer des chaînes, par exemple pour :

Les instructions SEARCH et SET en COBOL

Alors que l'instruction INSPECT est conçue pour rechercher des occurrences précises de chaînes de caractères au sein d'autres chaînes, l'instruction SEARCH est spécifiquement utilisée pour effectuer des recherches dans des structures de données tabulaires, c'est-à-dire dans des tableaux. Cette instruction est utile lorsqu'on souhaite localiser une valeur particulière au sein d'une table déclarée en COBOL. Elle est souvent utilisée en combinaison avec l'instruction SET, permettant de manipuler les indices associés aux tables, en les affectant, en les incrémentant ou en les décrémentant selon les besoins du programme.

Ces deux instructions jouent un rôle fondamental dans le traitement des données structurées sous forme de tableaux. Voici leur syntaxe générale :

SEARCH identificateur-1 [VARYING index]
       [AT END instruction-1]
       WHEN condition instruction-2
Instruction SEARCH
SET liste-d-index TO valeur
               UP BY valeur
             DOWN BY valeur
Instruction SET

Dans cette syntaxe :

Lorsqu'une instruction SEARCH est exécutée, COBOL parcourt séquentiellement les éléments de la table identificateur-1, en faisant varier un index interne (ou celui spécifié via VARYING). Ce processus se poursuit jusqu'à ce que la condition indiquée soit satisfaite ou que la fin du tableau soit atteinte. Si la condition est remplie, instruction-2 est exécutée immédiatement. Si la fin du tableau est atteinte sans trouver de correspondance, et si l'option AT END est utilisée, alors instruction-1 est exécutée. Sinon, le contrôle passe simplement à l'instruction suivante du programme.

Quant à l'instruction SET, elle est utilisée pour manipuler la position d'un ou plusieurs indices. Par exemple :

Exemple pratique

Considérons un exemple classique d'utilisation de ces instructions, dans lequel on cherche à identifier la première occurrence de la valeur 0 dans une table appelée TABLE-A. Voici tout d'abord comment cette table est déclarée en COBOL, ainsi que l'index I utilisé pour y accéder :

01 TABLE-A.
   02 A PIC S99 OCCURS 5 INDEXED BY I.

Ici, la variable A est définie comme un tableau de cinq éléments numériques signés à deux chiffres (S99), et l'index I est implicitement déclaré par l'utilisation de INDEXED BY.

Supposons maintenant que la table contienne les valeurs suivantes :

A : 43 19 -5 0 -19

Ces données sont entreposées séquentiellement dans les cinq emplacements du tableau A, de l'index 1 à 5.

L'objectif est de parcourir la table A pour trouver la première cellule contenant un zéro. Cela se programme de la manière suivante en COBOL :

SET I TO 1.
SEARCH TABLE-A
   AT END GO TO PAS-DE-ZERO
   WHEN A(I) = 0 GO TO ZERO-TROUVE.

Voici ce que fait ce fragment de code :

Ce type de traitement est courant dans les programmes COBOL manipulant des tableaux de données, qu'il s'agisse d'enquêter sur une valeur précise, d'effectuer des calculs conditionnels, ou encore de manipuler dynamiquement des pointeurs d'accès dans des structures OCCURS.

L'instruction GO TO en COBOL

Dans un programme COBOL, les instructions sont généralement exécutées dans l'ordre exact où elles apparaissent dans la Procedure Division. Ce déroulement linéaire est la norme de base, à moins qu'une instruction spécifique ne vienne modifier le cours naturel de l'exécution du programme. Parmi ces instructions de contrôle de flux, GO TO occupe une place centrale, car elle permet d'effectuer des sauts directs d'un point à un autre dans le code, interrompant ainsi l'enchaînement séquentiel des instructions.

L'instruction GO TO existe sous deux formes principales, chacune ayant une sémantique particulière :

GO TO nom-de-procédure (i)
GO TO liste-de-noms-de-procédures DEPENDING ON identificateur (ii)

L'optionnel mot-clé ON peut être ajouté après DEPENDING sans en changer la signification.

Dans ces deux formes :

Fonctionnement de la forme (i) :

Lorsqu'un GO TO de forme simple (sans DEPENDING) est rencontré, le programme transfère immédiatement le contrôle à la première instruction de la première phrase du paragraphe (ou de la section) indiqué par nom-de-procédure. C'est une redirection inconditionnelle et instantanée vers un point précis du code.

Exemple :

GO TO BOUCLE

Dans cet exemple, l'exécution du programme sautera directement à la première instruction du paragraphe nommé BOUCLE, sans évaluer aucune condition. Ce type de saut est simple, mais potentiellement risqué s'il est utilisé sans discipline, car il peut rendre le programme difficile à lire ou à maintenir.

Fonctionnement de la forme (ii) :

La seconde forme, avec DEPENDING ON, permet de rendre le saut conditionnel et dynamique. L'instruction utilise la valeur entière contenue dans identificateur pour déterminer quel paragraphe de la liste devra être exécuté. Si l'identificateur contient la valeur 1, le contrôle est transféré au premier paragraphe de la liste ; si c'est 2, au second, et ainsi de suite.

Si la valeur de l'identificateur ne correspond à aucun index valide dans la liste des procédures (par exemple si elle est inférieure à 1 ou supérieure au nombre de noms dans la liste), alors aucun saut n'est effectué et l'exécution se poursuit normalement, avec l'instruction suivante dans l'ordre séquentiel du code.

Ce mécanisme permet une certaine forme de branchement conditionnel basé sur des variables, et peut se rapprocher, dans l'intention, d'une structure de type switch-case dans d'autres langages de programmation modernes.

L'instruction STOP en COBOL

L'instruction STOP en COBOL est utilisée pour provoquer l'arrêt immédiat de l'exécution d'un programme. Elle représente un point d'arrêt volontaire dans le flux de contrôle du programme, et marque la fin de l'exécution logique à l'endroit où elle est rencontrée. Elle s'écrit de manière très simple et directe, sous la forme suivante :

STOP RUN

Cette syntaxe est à la fois claire et sans ambiguïté : elle indique au compilateur que le programme doit s'arrêter complètement et que plus aucune instruction ne doit être exécutée après ce point. L'effet est immédiat : l'exécution prend fin, les ressources éventuellement allouées sont libérées, et le contrôle est retourné au système d'exploitation ou à l'environnement de traitement dans lequel le programme a été lancé.

Contrairement à ce que l'on pourrait penser, l'instruction STOP RUN n'a pas l'obligation d'être placée en toute fin du code source ou à la toute dernière ligne de la Procedure Division. Elle peut apparaître à n'importe quel endroit logique du programme, là où l'on souhaite provoquer un arrêt total et définitif de l'exécution. Ainsi, il est tout à fait possible, et même courant, de rencontrer plusieurs instructions STOP RUN réparties dans différents blocs de code ou paragraphes, selon les besoins fonctionnels du programme.

Par exemple, un programme pourrait contenir une instruction STOP RUN dans un paragraphe principal à la toute fin du traitement normal, mais aussi d'autres STOP RUN dans des paragraphes gérant des cas d'erreur ou des situations exceptionnelles, afin de stopper proprement l'exécution lorsqu'un problème est détecté.

Dans le cas de notre programme Moyenne, qui calcule une moyenne de valeurs numériques, il n'y a qu'une seule instruction STOP RUN, et celle-ci est placée à la fin du premier paragraphe du code. Cela signifie que lorsque le traitement principal est terminé, et que toutes les opérations nécessaires ont été exécutées, le programme s'arrête normalement à cet endroit.

À noter que même si une seule instruction STOP RUN suffit à interrompre le programme, on peut très bien en utiliser plusieurs si différentes branches logiques du code nécessitent un arrêt immédiat selon certaines conditions.

Une condition en COBOL peut être formulée selon plusieurs formats, comme illustré ci-dessous :

identificateur IS [NOT] NUMERIC
                        ALPHABETIC

Dans ce contexte, «identificateur» désigne le nom d'une variable utilisée dans le programme, typiquement avec un usage de type DISPLAY. Le résultat de cette condition dépend du contenu de la variable testée : si celui-ci correspond au critère, l'évaluation retourne la valeur booléenne true, sinon elle retourne false.

Prenons un exemple simple pour illustrer cela : imaginons une variable appelée NOM, à laquelle on a assigné la chaîne de caractères "FIRE YOUR GUNS". Si on évalue les deux conditions suivantes :

NOM IS NUMERIC
NOM IS ALPHABETIC

Les deux conditions retourneront la valeur false. Pourquoi ? Parce que la chaîne de caractères "FIRE YOUR GUNS" ne représente pas un nombre valide (elle échoue donc le test IS NUMERIC), et elle contient un espace (et potentiellement d'autres caractères non alphabétiques selon l'encodage), ce qui rend le test IS ALPHABETIC invalide également.

Les conditions programmées sont utiles lorsqu'on souhaite savoir si une variable élémentaire satisfait une certaine propriété prédéfinie. On peut spécifier ce genre de condition directement dans la définition des variables, en utilisant ce que l'on appelle un « nom-de-condition », ou clause de niveau 88. Cela se fait immédiatement après la déclaration de la variable concernée, comme suit :

88 nom-de-condition liste-de-clauses-VALUE.

Dans cette construction, nom-de-condition est un identifiant librement choisi par le programmeur pour désigner une certaine valeur ou une intervalle de valeurs de la variable à laquelle il est lié. La clause liste-de-clauses-VALUE représente une ou plusieurs conditions, chacune séparée par une virgule suivie d'un espace. Chaque clause peut prendre deux formes possibles :

Les littéraux peuvent être numériques ou alphanumériques, mais doivent correspondre au format PICTURE de la variable déclarée. Voyons maintenant un exemple concret avec une variable nommée BRUT :

 02 BRUT               PIC 9(5)V99.                                                                         
    88 PAIE-MIN             VALUES 0 THROUGH 5000.                                                          
    88 PAIE-MOY             VALUES 6000.                                                                    
    88 PAIE-MAX             VALUES 20000 THROUGH 99999.

Ici, nous avons défini trois conditions nommées : PAIE-MIN, PAIE-MOY et PAIE-MAX. Chacune d'elles est associée à une valeur ou à un intervalle de valeurs précise de la variable BRUT. Cela permet d'exprimer très clairement le sens des données, tout en facilitant les tests.

Par exemple, si la variable BRUT contient la valeur 25400.00, alors les évaluations suivantes donneront :

En plus des conditions de type valeur ou alphabétique, il existe également des conditions de signe, utilisées spécifiquement pour les données numériques. Elles permettent de vérifier si une valeur est positive, négative ou nulle :

expression arithmétique IS [NOT] POSITIVE
                                  NEGATIVE
                                  ZERO

Enfin, on peut également combiner plusieurs conditions dans une même instruction en utilisant les opérateurs logiques AND et OR. Par exemple, une expression comme C1 AND C2 sera vraie uniquement si les deux conditions C1 et C2 sont vraies. Inversement, C1 OR C2 sera vraie si au moins une des deux conditions est vraie.

Attention à l'ordre de priorité : l'opérateur AND est prioritaire par rapport à OR. Ainsi, l'expression C1 OR C2 AND C3 est interprétée comme C1 OR (C2 AND C3) et non pas (C1 OR C2) AND C3. Pour forcer l'ordre d'évaluation souhaité, on utilise bien sûr des parenthèses.

Une instruction IF en COBOL peut être formulée de deux manières :

IF condition instruction-1
IF condition instruction-1 ELSE instruction-2

Dans les deux cas, l'exécution commence par l'évaluation de la condition. Si celle-ci retourne true, alors c'est instruction-1 étant exécutée. Sinon, dans la forme avec ELSE, c'est instruction-2 étant exécutée. Chaque instruction peut être simple ou composée, à condition de ne contenir au maximum qu'une seule instruction conditionnelle imbriquée.



Dernière mise à jour : Samedi, le 19 avril 2025