COBOL (COmmon Business-Oriented Language) nasce nel 1959 per iniziativa del DoD statunitense e del comitato CODASYL. È il linguaggio più longevo in ambito business/finanziario; si stima che oltre il 70% delle transazioni finanziarie globali tocchi codice COBOL.
| Versione | Anno | Standard | Novità Principali |
|---|---|---|---|
| COBOL-60 | 1960 | CODASYL (informale) | Prima specifica. 4 divisioni, PICTURE, MOVE, ADD/SUBTRACT, READ/WRITE. Fixed format (schede perforate). Nessun IF annidato, nessun PERFORM inline. |
| COBOL-61 / -61 Ext. | 1961–63 | CODASYL revisioni | Aggiunta SORT, Report Writer, tabelle OCCURS. Correzioni alla specifica originale. |
| COBOL-68 | 1968 | ANSI X3.23-1968 | Primo standard ANSI ufficiale. Inter-program communication (CALL). EXAMINE (predecessore di INSPECT). Struttura definita in 3 livelli (nucleo, tabelle, I/O sequenziale). |
| COBOL-74 | 1974 | ANSI X3.23-1974 | File I/O indexed e relative (ISAM). PERFORM ... UNTIL. INSPECT completo (TALLYING, REPLACING, CONVERTING). DELETE/REWRITE su file indexed. STRING/UNSTRING. Moduli funzionali (11 moduli opzionali). |
| COBOL-85 | 1985 | ANSI X3.23-1985 / ISO 1989:1985 | Rivoluzione strutturale: scope terminators (END-IF, END-PERFORM, END-READ, ecc.), PERFORM inline, EVALUATE (switch), NOT AT END/INVALID KEY, CONTINUE, INITIALIZE, reference modification var(start:len), nested programs. De facto standard per decenni. |
| COBOL 2002 | 2002 | ISO/IEC 1989:2002 | OO COBOL (CLASS-ID, METHOD-ID, OBJECT REFERENCE, INVOKE). Free-format source. User-defined functions. TYPEDEF. Locale support (NATIONAL/UTF-16). Boolean data type. Binary/alphanumeric truncation. VALIDATE statement. Molte feature rimaste non implementate nei compilatori. |
| COBOL 2014 | 2014 | ISO/IEC 1989:2014 | Dynamic tables (OCCURS DYNAMIC). ALLOCATE/FREE (heap memory). Float IEEE (FLOAT-SHORT, FLOAT-LONG, FLOAT-EXTENDED). FUNCTION-POINTER / PROGRAM-POINTER. Conditional compilation (>>DEFINE, >>IF). RAISE / RESUME exception handling. JSON/XML GENERATE/PARSE. RETRY su I/O. |
| COBOL 202x | ~2025 | ISO/IEC 1989 (in sviluppo) | In corso: miglioramenti OO, UTF-8 nativo, iteratori moderni, miglioramenti ai container, allineamento con pratiche moderne. |
| Dialetto / Compilatore | Piattaforma | Standard | Estensioni Caratteristiche |
|---|---|---|---|
| IBM Enterprise COBOL | z/OS (mainframe) | COBOL 85 + estensioni | COMP-5, XML GENERATE/PARSE, DB2 embedded SQL, CICS (EXEC CICS), JCL integration, EBCDIC nativo, AMODE 31/64. De facto standard mainframe. |
| IBM COBOL for AIX/Linux | AIX, Linux on Z | COBOL 2002 parziale | Simile a Enterprise COBOL, ma su Unix. Supporta DB2, CICS TX. ASCII nativo. |
| Micro Focus COBOL (ora Rocket Software) |
Windows, Linux, Unix | COBOL 2002 + 2014 parziale | COMP-X, COMP-5, screen handling avanzato, .NET/JVM interop, embedded SQL, XML/JSON. IDE Visual COBOL. Gestione mainframe migration. Il più completo su piattaforme distribuite. |
| GnuCOBOL (ex OpenCOBOL) |
Linux, macOS, Windows, BSD | COBOL 85 + 2002/2014 parziale | Open source (GPL). Compila COBOL → C → eseguibile nativo. BINARY-CHAR/SHORT/LONG/DOUBLE, FLOAT-SHORT/LONG/EXTENDED, SCREEN SECTION con ncurses, COMP-X, interop C nativa. Flag -std=ibm|mf|cobol2014 per compatibilità. |
| ACUCOBOL-GT (Micro Focus) |
Multi-piattaforma | COBOL 85 + estensioni | GUI nativa, thin client, runtime interpretato. Usato in ambito PMI. ACCEPT/DISPLAY estesi con controlli grafici. Ora parte di Micro Focus extend. |
| Fujitsu NetCOBOL | Windows, Linux, Solaris | COBOL 2002 parziale | Supporto Unicode nativo, PowerCOBOL (visual IDE), form printing, .NET interop, Web services. Usato in Giappone e Asia. |
| RM/COBOL (Micro Focus) |
Multi-piattaforma | COBOL 85 | Runtime interpretato leggero. Popolare nelle PMI americane anni '80-'90. Ora parte di Micro Focus. |
| COBOL-IT | Linux, Unix, Windows | COBOL 85 + 2002 parziale | Compilatore commerciale alternativo. Compatibile con IBM/MF. Supporto embedded SQL (Oracle, DB2). |
| Feature | IBM Ent. | Micro Focus | GnuCOBOL | Standard |
|---|---|---|---|---|
| COMP-3 (packed decimal) | Sì | Sì | Sì | PACKED-DECIMAL |
| COMP-5 (native binary) | Sì | Sì | Sì | No (estensione) |
| COMP-X (unsigned binary) | No | Sì | Sì | No (estensione) |
| SCREEN SECTION | No | Sì | Sì (ncurses) | COBOL 2002+ |
| Embedded SQL (EXEC SQL) | DB2 nativo | Sì (preprocessore) | No (via OCESQL) | No |
| CICS (EXEC CICS) | Sì | Sì (emulato) | No | No |
| OO COBOL (CLASS-ID) | Parziale | Sì | Parziale | COBOL 2002+ |
| XML/JSON GENERATE | Sì | Sì | JSON sì, XML parziale | COBOL 2014 |
| FLOAT-SHORT/LONG | COMP-1/2 | Sì | Sì | COBOL 2014 |
| Free format | Enterprise V6+ | Sì | Sì | COBOL 2002+ |
| ALLOCATE/FREE | No | Parziale | No | COBOL 2014 |
| Codifica default | EBCDIC | ASCII | ASCII | Impl. defined |
-std=ibm copre ~85% della sintassi IBM.
Per copertura completa, Micro Focus è lo standard de facto nella mainframe modernization.
Un programma COBOL è strutturato gerarchicamente: Program → Division → Section → Paragraph → Sentence → Statement.
*> Template minimo GnuCOBOL >>SOURCE FORMAT FREE IDENTIFICATION DIVISION. PROGRAM-ID. nome-programma. AUTHOR. Nome Autore. INSTALLATION. Nome computer. DATE-WRITTEN. 01 Jan 2025. DATE-COMPILED. 01 Jan 2025. SECURITY. Confidential. ENVIRONMENT DIVISION. CONFIGURATION SECTION. SOURCE-COMPUTER. Nome computer. OBJECT-COMPUTER. Nome computer MEMORY SIZE dimensione-memoria [CHARACTERS | WORDS | MODULES] PROGRAM COLLATING SEQUENCE IS nome-alfabeto *> Stabilisce l'ordine di "valore" dei caratteri (MERGE e SORT) SEGMENT-LIMIT IS limite. SPECIAL-NAMES. *> Classificazioni personalizzate CLASS nome IS val1, val2, ... DECIMAL-POINT IS COMMA CURRENCY SIGN IS carattere ALPHABET nome-alfabeto IS [ASCII | EBCDIC | NATIVE | STANDARD-1/2]. REPOSITORY. FUNCTION ALL INTRINSIC. INPUT-OUTPUT SECTION. FILE-CONTROL. *> Associazione file I-O-CONTROL. DATA DIVISION. FILE SECTION. *> Descrittori FD/SD WORKING-STORAGE SECTION. *> Variabili globali del programma LOCAL-STORAGE SECTION. *> Variabili locali (reinizializzate ad ogni CALL) LINKAGE SECTION. *> Parametri passati da programma chiamante SCREEN SECTION. *> Definizioni schermi interattivi PROCEDURE DIVISION [USING param1 param2] [RETURNING ret]. DECLARATIVES. *> Gestione degli errori END DECLARATIVES. *> Logica del programma STOP RUN. END PROGRAM nome-programma.
| Divisione | Scopo | Sezioni principali |
|---|---|---|
IDENTIFICATION | Metadati del programma | PROGRAM-ID, AUTHOR, DATE-WRITTEN, SECURITY |
ENVIRONMENT | Ambiente HW/SW, file | CONFIGURATION, INPUT-OUTPUT |
DATA | Definizione dati | FILE, WORKING-STORAGE, LOCAL-STORAGE, LINKAGE, SCREEN |
PROCEDURE | Logica elaborazione | Paragrafi, Sezioni, Statements |
| Col. | Uso |
|---|---|
| 1-6 | Numero sequenza (punch card) |
| 7 | * commento, - continuazione, / form feed |
| 8-11 | Area A: DIVISION, SECTION, FD, livello 01/77 |
| 12-72 | Area B: istruzioni, livelli 02-49 |
| 73-80 | Identificazione (ignorato) |
>>SOURCE FORMAT FREE *> riga 1 *> o in alternativa: cobc -free ...
*> ovunque nella riga.| Simbolo | Significato | Esempio | Note |
|---|---|---|---|
9 | Cifra numerica (0-9) | PIC 9(4) | 4 cifre intere |
X | Qualsiasi carattere | PIC X(20) | Stringa alfanumerica |
A | Solo lettere e spazi | PIC A(10) | Alfabetico |
S | Segno (±) | PIC S9(4) | Prefix, non occupa byte extra a meno di SIGN SEPARATE |
V | Punto decimale virtuale | PIC 9(4)V99 | Non memorizza il punto fisicamente |
P | Scaling position | PIC 9PPP | Moltiplicazione/divisione per 10n |
N | DBCS national char | PIC N(10) | Caratteri nazionali (DBCS) |
1 | Bit (boolean) | PIC 1 | Con USAGE BIT |
01 Nome PIC X(30) VALUE "Mario". 01 Eta PIC 99 VALUE 0. 01 Stipendio PIC 9(6)V99 VALUE ZEROS. 01 Temperatura PIC S9(3)V9. 01 Codice PIC X(8). 01 Lettera PIC A VALUE 'A'.
*> Segno incorporato (default) 01 N1 PIC S9(4). *> Segno come carattere separato 01 N2 PIC S9(4) SIGN LEADING SEPARATE. 01 N3 PIC S9(4) SIGN TRAILING SEPARATE. *> +0012 oppure 0012+
| Livello | Uso |
|---|---|
01 | Record (Group item o Elementary item) |
02-49 | Campi subordinati (Group o Elementary) |
66 | RENAMES — rinomina range di campi |
77 | Elementary item standalone (non in gruppo) |
78 | Costante (GnuCOBOL: 78 PI VALUE 3.14159) |
88 | Condition name — valori speciali per condizioni booleane |
01 Cliente. 02 IDCliente PIC 9(5). 02 NomeCliente. 03 Cognome PIC X(20). 03 Nome PIC X(20). 02 DataNascita. 03 Giorno PIC 99. 03 Mese PIC 99. 03 Anno PIC 9(4). *> FILLER: campo senza nome (placeholder) 02 FILLER PIC X(5) VALUE SPACES. *> CONSTANT (GnuCOBOL) 01 MAX-SIZE CONSTANT AS 100. 78 PI-VALUE VALUE 3.14159265. *> RENAMES (66) 01 DataRec. 02 Anno PIC 9(4). 02 Mese PIC 99. 02 Giorno PIC 99. 66 MeseGiorno RENAMES Mese THRU Giorno.
| Figurativa | Significato |
|---|---|
ZERO / ZEROS / ZEROES | Caratteri '0': riempie PIC 9 con zero numerico, PIC X con carattere '0' |
SPACE / SPACES | Tutti i caratteri = spazio |
HIGH-VALUE / HIGH-VALUES | Valore massimo del tipo (x'FF') |
LOW-VALUE / LOW-VALUES | Valore minimo del tipo (x'00') |
QUOTE / QUOTES | Carattere doppio apice |
ALL "x" | Ripete il carattere x fino a riempire |
NULL / NULLS | Puntatore null (per USAGE POINTER) |
MOVE ZEROS TO Stipendio. MOVE SPACES TO Nome. MOVE HIGH-VALUES TO EOF-Flag. MOVE ALL "*" TO SeparatorLine. *> Letterali numerici e alfanumerici MOVE 42 TO Numero. MOVE "ciao" TO Testo. MOVE 3.14 TO PiGreco. *> Esadecimale MOVE X"41" TO CarattereA. *> Booleano (BIT) MOVE B"1010" TO Flags.
| USAGE | Alias | Rappresentazione | Note |
|---|---|---|---|
DISPLAY | default | EBCDIC/ASCII zoned decimal | 1 byte per cifra, stampa diretta |
COMPUTATIONAL | COMP | Binario (dipende dal compilatore) | GnuCOBOL = binario nativo |
COMP-1 | — | Float a singola precisione (32-bit IEEE 754) | Equivalente a float C |
COMP-2 | — | Float a doppia precisione (64-bit IEEE 754) | Equivalente a double C |
COMP-3 | PACKED-DECIMAL | Decimale compresso (BCD): 2 cifre per byte | Comune nei mainframe IBM |
COMP-4 | BINARY | Binario intero puro | 2, 4 o 8 byte secondo PIC |
COMP-5 | — | Binario nativo (endianness host) | Usa tutti i bit, non solo quelli definiti in PIC |
COMP-6 | — | Packed decimal senza segno | Come COMP-3 ma unsigned |
COMP-X | — | Dipendente dal compilatore/mainframe | Vedi sezione dedicata ↓ |
POINTER | — | Puntatore di memoria (4 o 8 byte) | Per interop C |
FUNCTION-POINTER | — | Puntatore a funzione | Per callback C |
OBJECT REFERENCE | — | Riferimento oggetto OO | Solo OO COBOL |
01 ContBin PIC 9(4) USAGE BINARY. *> int16 01 ContBin4 PIC 9(9) USAGE BINARY. *> int32 01 ValFloat USAGE COMP-1. *> float C 01 ValDouble USAGE COMP-2. *> double C 01 ValPacked PIC S9(7)V99 USAGE COMP-3. *> packed dec 01 Puntatore USAGE POINTER. *> void* C
1-4 cifre → 2 byte | 5-9 cifre → 4 byte | 10-18 cifre → 8 byte
COMP-X è una clausola USAGE specifica di GnuCOBOL e Micro Focus. Il comportamento dipende dal contesto:
| Dichiarazione | Byte | Range | Equiv. C |
|---|---|---|---|
PIC X(1) COMP-X | 1 | 0 – 255 | uint8_t |
PIC X(2) COMP-X | 2 | 0 – 65535 | uint16_t |
PIC X(4) COMP-X | 4 | 0 – 4294967295 | uint32_t |
PIC X(8) COMP-X | 8 | 0 – 264-1 | uint64_t |
| Dichiarazione | Byte | Note |
|---|---|---|
PIC 9(1) COMP-X | 1 | 0-255, come COMP-5 ma unsigned forced |
PIC 9(4) COMP-X | 2 | 0-65535 |
PIC 9(9) COMP-X | 4 | 0-4294967295 |
PIC 9(18) COMP-X | 8 | 0-18446744073709551615 |
| Tipo | Descrizione |
|---|---|
USAGE BINARY-CHAR | 1 byte signed (int8_t) |
USAGE BINARY-CHAR UNSIGNED | 1 byte unsigned (uint8_t) |
USAGE BINARY-SHORT | 2 byte signed (int16_t) |
USAGE BINARY-SHORT UNSIGNED | 2 byte unsigned (uint16_t) |
USAGE BINARY-LONG | 4 byte signed (int32_t) |
USAGE BINARY-LONG UNSIGNED | 4 byte unsigned (uint32_t) |
USAGE BINARY-DOUBLE | 8 byte signed (int64_t) |
USAGE BINARY-DOUBLE UNSIGNED | 8 byte unsigned (uint64_t) |
USAGE FLOAT-SHORT | 32-bit IEEE 754 (float) |
USAGE FLOAT-LONG | 64-bit IEEE 754 (double) |
USAGE FLOAT-EXTENDED | 80/128-bit extended (long double) |
*> Esempio pratico: buffer di byte per interop C 01 RawByte PIC X(1) COMP-X VALUE 0. 01 Word16 PIC X(2) COMP-X. 01 DWord32 PIC X(4) COMP-X. 01 QWord64 PIC X(8) COMP-X. 01 Cnt8s USAGE BINARY-CHAR. *> int8_t 01 Cnt8u USAGE BINARY-CHAR UNSIGNED. *> uint8_t 01 IntVal USAGE BINARY-LONG. *> int32_t 01 BigVal USAGE BINARY-DOUBLE. *> int64_t 01 FltVal USAGE FLOAT-LONG. *> double
-fcomp-version o test espliciti.| Simbolo | Effetto | Esempio | Input → Output |
|---|---|---|---|
Z | Sopprime zero a sinistra (sostituisce con spazio) | ZZZ9 | 0012 → " 12" |
* | Riempie zero a sinistra con asterisco | ***9 | 0012 → "**12" |
$ | Simbolo valuta mobile | $$,$$$,$$9.99 | 1234.56 → "$1,234.56" |
+ | Mostra segno + o - | +9(4) | +1234 → "+1234" |
- | Mostra - se negativo, spazio se positivo | -(5) | -42 → " -42" |
, | Inserisce virgola | 9,999 | 1234 → "1,234" |
. | Punto decimale fisico | 9(4).99 | 1234.56 → "1234.56" |
/ | Inserisce slash | 99/99/9999 | 12212024 → "12/21/2024" |
B | Inserisce spazio | 99B99 | 1234 → "12 34" |
0 | Inserisce zero letterale in posizione | 990099 | 1234 → "120034" |
CR | Stampa CR se negativo | 9(6).99CR | -100 → " 100.00CR" |
DB | Stampa DB se negativo | 9(6).99DB |
01 StartNum PIC 9(8)V99 VALUE 1234.56. 01 Formattato PIC $$,$$$,$$9.99. *> $1,234.56 01 Data PIC 99/99/9999. *> 12/21/2024 01 SenzaZeri PIC ZZZZ9.99. *> 1234.56 (no leading zeros) MOVE StartNum TO Formattato DISPLAY Formattato.
REDEFINES permette di accedere alla stessa area di memoria con layout diversi (simile a union in C). Il campo ridefinito e quello originale condividono gli stessi byte fisici: scrivere in uno modifica l'altro.
| Regola | Dettaglio |
|---|---|
| Stesso livello | Il campo REDEFINES deve avere lo stesso numero di livello del campo originale |
| Dimensione | Il campo ridefinente non deve essere piu' grande dell'originale (puo' essere uguale o piu' piccolo) |
| Ordine | La clausola REDEFINES deve seguire immediatamente il campo originale (senza campi intermedi allo stesso livello) |
| No VALUE | Un campo con REDEFINES non puo' avere clausola VALUE (lo standard lo vieta; alcuni compilatori lo tollerano) |
| No su livello 01 in FILE SECTION | In FILE SECTION, i record 01 sono gia' ridefinizioni implicite dello stesso buffer |
| No su 66, 77, 88 | REDEFINES non e' applicabile ai livelli speciali |
| REDEFINES multipli | Piu' campi possono ridefinire lo stesso campo originale (catena di REDEFINES) |
*> Stesso storage, visto come testo o come numero 01 DataGrezza PIC X(8). 01 DataNum REDEFINES DataGrezza PIC 9(8). 01 DataStruct REDEFINES DataGrezza. 02 Anno PIC 9(4). 02 Mese PIC 99. 02 Giorno PIC 99. *> MOVE "20241225" TO DataGrezza *> DISPLAY Anno -> "2024" *> DISPLAY DataNum -> 20241225 *> Union-style: interpretare lo stesso dato come int o float 01 RawArea PIC X(4). 01 IntView REDEFINES RawArea USAGE BINARY-LONG. 01 FloatView REDEFINES RawArea USAGE FLOAT-SHORT. *> REDEFINES in strutture di gruppo (subordinati) 01 Indirizzo. 02 CodicePostale PIC X(5). 02 CPStrutturato REDEFINES CodicePostale. 03 Regione PIC XX. 03 Comune PIC X(3). 02 Citta PIC X(30).
*> Tecnica classica per inizializzare una tabella con valori noti 01 MesiTable. 02 MesiData. 03 FILLER PIC X(9) VALUE "Gennaio ". 03 FILLER PIC X(9) VALUE "Febbraio ". 03 FILLER PIC X(9) VALUE "Marzo ". 03 FILLER PIC X(9) VALUE "Aprile ". *> ... (12 FILLER totali) 02 FILLER REDEFINES MesiData. 03 NomeMese PIC X(9) OCCURS 12 TIMES. *> DISPLAY NomeMese(3) -> "Marzo "
FILLER e' un campo anonimo (senza nome referenziabile) che occupa spazio nel record ma non e' indirizzabile direttamente nel codice. Usi principali:
| Uso | Descrizione | Esempio |
|---|---|---|
| Spaziatura nei record | Padding tra campi per allineamento o formato fisso | 02 FILLER PIC X(5) VALUE SPACES. |
| Aree riservate | Byte riservati per future espansioni del tracciato | 02 FILLER PIC X(20). |
| Costanti in tabelle | Dati pre-caricati (vedi pattern REDEFINES sopra) | 03 FILLER PIC X(10) VALUE "Testo". |
| Label in SCREEN SECTION | Testo fisso sullo schermo non referenziabile | 02 FILLER VALUE "Titolo". |
| Record di output | Separatori e decorazioni nelle righe di stampa | 02 FILLER PIC X VALUE "/". |
*> Record con FILLER per formato tracciato fisso 01 RecordFisso. 02 RF-Codice PIC 9(5). 02 FILLER PIC X(3) VALUE SPACES. *> separatore 02 RF-Nome PIC X(30). 02 FILLER PIC X(12). *> riservato 02 RF-Importo PIC 9(7)V99. *> Da COBOL-85: la parola FILLER e' opzionale 01 RecordModerno. 02 PIC X(5) VALUE SPACES. *> FILLER implicito 02 RM-Nome PIC X(20).
INITIALIZE Record WITH FILLER. Analogamente, MOVE CORRESPONDING ignora i FILLER.I livelli 88 definiscono nomi di condizione associati a un campo genitore. Non occupano memoria propria: sono alias booleani che testano se il genitore contiene determinati valori. Sono l'equivalente COBOL degli enum e dei flag booleani dei linguaggi moderni.
| Forma | Significato | Esempio |
|---|---|---|
VALUE literal | Singolo valore | 88 Attivo VALUE 1. |
VALUE lit1, lit2, ... | Lista di valori (OR implicito) | 88 Errore VALUE 'E', 'F', 'G'. |
VALUE lit1 THRU lit2 | Range continuo (estremi inclusi) | 88 Valido VALUE 1 THRU 99. |
VALUES ARE lit1 THRU lit2, lit3 | Range + valori singoli combinati | 88 OK VALUES ARE 'A' THRU 'F', 'X'. |
VALUE FALSE IS literal | Valore assegnato con SET ... TO FALSE | 88 Flag VALUE 'Y' FALSE 'N'. |
*> Booleano semplice (flag On/Off) 01 WS-EOF PIC 9 VALUE 0. 88 EOF-Reached VALUE 1. 88 Not-EOF VALUE 0. *> Stato con valori multipli (lista) 01 Stato PIC X. 88 StApertura VALUE 'A'. 88 StChiusura VALUE 'C'. 88 StErrore VALUE 'E', 'F', 'G'. *> StErrore e' TRUE se Stato = 'E' OR 'F' OR 'G' *> Range continuo con THRU 01 Voto PIC 99. 88 Insufficiente VALUE 0 THRU 17. 88 Sufficiente VALUE 18 THRU 23. 88 Buono VALUE 24 THRU 27. 88 Ottimo VALUE 28 THRU 30. 88 VotoValido VALUE 0 THRU 30. *> Range combinato con valori singoli 01 CodiceResp PIC X(2). 88 RespOK VALUES ARE "00", "02", "04". 88 RespWarning VALUES ARE "10" THRU "19". 88 RespError VALUES ARE "20" THRU "49", "99". *> FALSE IS: permette SET ... TO FALSE 01 WS-Switch PIC X VALUE 'N'. 88 Attivato VALUE 'Y' FALSE 'N'. *> Su campo alfanumerico (HIGH-VALUES per EOF) 01 WS-Flag PIC X. 88 EOF-Flag VALUE HIGH-VALUES.
SET condizione TO TRUE scrive nel campo genitore il primo valore della lista VALUE. E' il modo idiomatico COBOL per modificare lo stato di un flag senza conoscere il valore concreto.
*> SET ... TO TRUE: assegna il primo VALUE al genitore SET EOF-Reached TO TRUE. *> WS-EOF diventa 1 SET StApertura TO TRUE. *> Stato diventa 'A' SET StErrore TO TRUE. *> Stato diventa 'E' (primo della lista) SET Sufficiente TO TRUE. *> Voto diventa 18 (inizio del range) *> SET ... TO FALSE: richiede clausola FALSE IS nella definizione SET Attivato TO FALSE. *> WS-Switch diventa 'N' *> ERRORE se FALSE IS non dichiarato: SET StApertura TO FALSE
*> Test diretto: il livello 88 e' gia' una condizione booleana IF EOF-Reached DISPLAY "Fine file" END-IF. *> Negazione IF NOT StApertura DISPLAY "Non in stato aperto" END-IF. *> In EVALUATE TRUE (pattern switch idiomatico) EVALUATE TRUE WHEN Insufficiente DISPLAY "Bocciato" WHEN Sufficiente DISPLAY "Sufficiente" WHEN Buono DISPLAY "Buono" WHEN Ottimo DISPLAY "Ottimo" END-EVALUATE. *> In condizione di loop PERFORM UNTIL EOF-Reached READ InputFile AT END SET EOF-Reached TO TRUE NOT AT END PERFORM ProcessaRecord END-READ END-PERFORM. *> Validazione input con range ACCEPT Voto FROM CONSOLE. IF NOT VotoValido DISPLAY "Voto non valido (0-30)" END-IF.
• Un livello 88 non ha PIC proprio — eredita il tipo dal genitore.
•
SET x TO TRUE assegna il primo valore della clausola VALUE al campo genitore.•
SET x TO FALSE e' legale solo se la definizione include FALSE IS.• Un campo puo' avere un numero illimitato di livelli 88 associati.
• THRU segue l'ordinamento collating sequence (EBCDIC o ASCII) per i campi alfanumerici.
• I livelli 88 sono il meccanismo standard per evitare magic numbers nel codice COBOL.
La LOCAL-STORAGE SECTION, introdotta in COBOL 2002, e' una sezione della DATA DIVISION che dichiara variabili reinizializzate automaticamente ad ogni invocazione del programma (tramite CALL). La differenza fondamentale con la WORKING-STORAGE e' il ciclo di vita dei dati.
| Caratteristica | WORKING-STORAGE | LOCAL-STORAGE |
|---|---|---|
| Persistenza | I dati persistono tra CALL successive allo stesso programma | I dati vengono reinizializzati (ai VALUE) ad ogni CALL |
| Allocazione | Statica: allocata una volta al primo caricamento | Dinamica: allocata/deallocata ad ogni invocazione (stack-like) |
| VALUE iniziale | Assegnato solo alla prima esecuzione (o dopo CANCEL) | Assegnato ad ogni esecuzione |
| Senza VALUE | Contenuto indefinito (di solito zero-filled dalla prima volta) | Contenuto indefinito ad ogni invocazione |
| Thread safety | Condivisa tra thread (non thread-safe) | Ogni thread ha la propria copia (thread-safe) |
| Visibilita' | Visibile per tutta la durata del programma in memoria | Visibile solo durante l'esecuzione corrente |
| Uso tipico | Contatori persistenti, tabelle, configurazione, record buffer | Variabili temporanee, contatori locali, flag di invocazione |
DATA DIVISION. FILE SECTION. *> FD / SD WORKING-STORAGE SECTION. *> Dati persistenti tra CALL 01 WS-CallCount PIC 9(5) VALUE 0. *> inizializzato 1 volta LOCAL-STORAGE SECTION. *> Dati reinizializzati ad ogni CALL 01 LS-Temp PIC X(50) VALUE SPACES. *> SPACES ad ogni CALL 01 LS-Counter PIC 9(3) VALUE 0. *> 0 ad ogni CALL 01 LS-NoValue PIC X(10). *> INDEFINITO ad ogni CALL LINKAGE SECTION. *> Parametri dal chiamante
IDENTIFICATION DIVISION. PROGRAM-ID. CONTATORE. DATA DIVISION. WORKING-STORAGE SECTION. 01 WS-Count PIC 9(3) VALUE 0. LOCAL-STORAGE SECTION. 01 LS-Count PIC 9(3) VALUE 0. PROCEDURE DIVISION. ADD 1 TO WS-Count. ADD 1 TO LS-Count. DISPLAY "WS: " WS-Count " LS: " LS-Count. EXIT PROGRAM. *> Risultato dopo 3 CALL consecutive: *> CALL 1: WS: 001 LS: 001 *> CALL 2: WS: 002 LS: 001 (LS reinizializzato!) *> CALL 3: WS: 003 LS: 001 (LS reinizializzato!)
| Scenario | Sezione consigliata | Motivazione |
|---|---|---|
| Sottoprogramma chiamato piu' volte | LOCAL-STORAGE | Ogni invocazione parte da uno stato pulito, senza residui dalla CALL precedente |
| Programma multi-thread (COBOL in server application) | LOCAL-STORAGE | Ogni thread ottiene la propria copia indipendente |
| Contatore che deve accumularsi tra CALL | WORKING-STORAGE | I dati devono persistere |
| Tabella di lookup caricata una sola volta | WORKING-STORAGE | Evita di ricaricare ad ogni invocazione |
| Buffer temporaneo in un sottoprogramma | LOCAL-STORAGE | Garantisce un buffer pulito ad ogni chiamata |
MOVE sorgente TO dest1 [dest2 ...]. MOVE CORRESPONDING src TO dest. *> Sposta campi con stesso nome MOVE "Mario" TO Nome. MOVE 100 TO Eta, Conta. MOVE ZEROS TO Totale. MOVE SPACES TO Linea. *> MOVE per Group item: copia raw MOVE RecordA TO RecordB.
• Numerico → Numerico: allineamento al punto decimale; cifre in eccesso troncate a sinistra (interi) e a destra (decimali)
• Alfa → Alfa: allineamento a sinistra, troncamento a destra o padding con SPACES a destra
• Numerico → Alfa: converte in stringa, allineamento a sinistra
• Alfa → Numerico: converte se il contenuto è numerico valido, altrimenti risultato indefinito
• Group → Group: copia byte-per-byte (alphanumeric), nessuna conversione di tipo
*> Troncamento numerico: PIC 9(3) contiene max 999 MOVE 12345 TO Campo3Dig. *> risultato: 345 (troncato a sx) *> Troncamento decimale: PIC 9(3)V99 MOVE 3.14159 TO CampoDec. *> risultato: 003.14 (troncato a dx) *> Troncamento alfanumerico: PIC X(5) MOVE "Hello World" TO Corto. *> risultato: "Hello" (troncato a dx) MOVE "Hi" TO Corto. *> risultato: "Hi " (padding spazi)
| Sorgente ↓ / Dest → | Alphanumeric | Numeric display | Numeric edited | Alpha edited | Group |
|---|---|---|---|---|---|
| Alphanumeric | OK | OK (se numerico) | OK (se numerico) | OK | OK |
| Numeric display | OK | OK | OK | OK | OK |
| Numeric edited | OK | NO | NO | OK | OK |
| Alpha edited | OK | NO | NO | OK | OK |
| Group | OK | OK (come alfa) | OK (come alfa) | OK | OK |
*> MOVE CORR copia solo i campi con NOME identico 01 RecordA. 02 Nome PIC X(20) VALUE "Mario". 02 Eta PIC 99 VALUE 30. 02 Codice PIC X(5) VALUE "AB123". 01 RecordB. 02 Nome PIC X(20). 02 Eta PIC 99. 02 Indirizzo PIC X(30). MOVE CORRESPONDING RecordA TO RecordB. *> Copia solo Nome e Eta (nomi in comune) *> Codice ignorato (non esiste in RecordB) *> Indirizzo non toccato (non esiste in RecordA) *> FILLER ignorato sempre da MOVE CORRESPONDING
ADD A TO B. *> B = B+A ADD A TO B GIVING C. *> C = A+B ADD A, B, C TO D. *> D = A+B+C+D SUBTRACT A FROM B. *> B = B-A SUBTRACT A FROM B GIVING C. *> C = B-A MULTIPLY A BY B. *> B = A*B MULTIPLY A BY B GIVING C. *> C = A*B DIVIDE A INTO B. *> B = B/A DIVIDE A INTO B GIVING C *> C=B/A REMAINDER R. *> R=B mod A
COMPUTE C = A + B. COMPUTE C = A - B. COMPUTE C = A * B. COMPUTE C = A / B. COMPUTE C = A ** 2. *> potenza COMPUTE C = (A + B) * D. COMPUTE C ROUNDED = A / B. ADD 1 TO C ON SIZE ERROR DISPLAY "Overflow" END-ADD.
STRING Str1 DELIMITED BY SIZE Str2 DELIMITED BY SPACE Str3 DELIMITED BY "#" INTO Dest [WITH POINTER Ptr] [ON OVERFLOW ...] END-STRING.
UNSTRING Sorgente DELIMITED BY "," OR " " INTO Parte1, Parte2 [DELIMITER IN DelChar] [COUNT IN NumChar] [WITH POINTER Ptr] [TALLYING IN Count] [ON OVERFLOW ...] END-UNSTRING.
FUNCTION UPPER-CASE(Str) *> tutto maiuscolo FUNCTION LOWER-CASE(Str) *> tutto minuscolo FUNCTION LENGTH(Str) *> lunghezza in caratteri FUNCTION TRIM(Str [LEADING|TRAILING]) *> rimozione spazi FUNCTION REVERSE(Str) *> inverti stringa FUNCTION CONCATENATE(S1, S2) *> join (GnuCOBOL) FUNCTION SUBSTITUTE(Str, Da, A) *> replace FUNCTION NUMVAL(Str) *> stringa → numero FUNCTION NUMVAL-C(Str [,Symbol]) *> stringa valuta → num FUNCTION CHAR(N) *> numero → ASCII char FUNCTION ORD(Ch) *> char → posizione
*> Conta caratteri INSPECT Str TALLYING Count1 FOR CHARACTERS Count2 FOR ALL 'e' Count3 FOR LEADING ' '. *> Sostituisce caratteri INSPECT Str REPLACING ALL 'a' BY '@' LEADING ' ' BY '0' FIRST 'X' BY 'Y' CHARACTERS BY '*'. *> Combina TALLYING e REPLACING INSPECT Str TALLYING Cnt FOR ALL 'e' REPLACING ALL 'e' BY '3'. *> CONVERTING (mappatura carattere per carattere) INSPECT Str CONVERTING "aeiou" TO "AEIOU". *> ─── BEFORE / AFTER INITIAL ─── *> Limita l'azione a una porzione della stringa *> Conta le 'a' solo PRIMA della prima virgola INSPECT Str TALLYING Cnt FOR ALL 'a' BEFORE INITIAL ','. *> Conta le 'a' solo DOPO la prima virgola INSPECT Str TALLYING Cnt FOR ALL 'a' AFTER INITIAL ','. *> Sostituisci spazi con zeri solo prima del primo '.' INSPECT NumStr REPLACING LEADING ' ' BY '0' BEFORE INITIAL '.'. *> Conversione case solo dopo un separatore INSPECT Str CONVERTING "abcdefghijklmnopqrstuvwxyz" TO "ABCDEFGHIJKLMNOPQRSTUVWXYZ" AFTER INITIAL ":".
INITIALIZE imposta i campi ai valori di default per tipo: SPACES per alfanumerici, ZEROS per numerici. Molto più sicuro di MOVE SPACES su un intero gruppo.
*> Inizializza tutti i campi di un record ai default INITIALIZE Cliente. *> Equivale a: MOVE SPACES TO ogni PIC X, MOVE ZEROS TO ogni PIC 9 *> Inizializza solo i campi alfanumerici INITIALIZE Cliente REPLACING ALPHANUMERIC DATA BY SPACES. *> Inizializza solo i numerici con un valore specifico INITIALIZE Tabella REPLACING NUMERIC DATA BY -1. *> INITIALIZE con ALL (COBOL 2002+): resetta anche FILLER INITIALIZE Record1 WITH FILLER. *> Categorie disponibili per REPLACING: *> ALPHABETIC, ALPHANUMERIC, NUMERIC, *> ALPHANUMERIC-EDITED, NUMERIC-EDITED, *> NATIONAL, DBCS *> DEFAULT (COBOL 2014+): usa i VALUE dichiarati nei campi INITIALIZE Cliente TO VALUE. *> Ripristina i VALUE originali dalla definizione in DATA DIVISION
INITIALIZE TabRec è più sicuro di MOVE SPACES TO TabRec che corrompe i campi numerici.IF Eta > 18 DISPLAY "Maggiorenne" ELSE IF Eta = 18 DISPLAY "Appena maggiorenne" ELSE DISPLAY "Minore" END-IF END-IF. *> Operatori di confronto *> = EQUAL TO *> > GREATER THAN *> < LESS THAN *> >= GREATER THAN OR EQUAL TO *> <= LESS THAN OR EQUAL TO *> NOT EQUAL TO *> AND, OR, NOT (logici) *> IS NUMERIC / ALPHABETIC *> IS ALPHABETIC-UPPER/LOWER *> ─── Class Conditions ─── IF Campo IS NUMERIC *> solo 0-9, +, -, . IF Campo IS ALPHABETIC *> solo A-Z, a-z, spazi IF Campo IS ALPHABETIC-UPPER IF Campo IS ALPHABETIC-LOWER IF Campo IS NOT NUMERIC *> ─── Sign Conditions ─── IF Saldo IS POSITIVE *> > 0 IF Saldo IS NEGATIVE *> < 0 IF Saldo IS ZERO *> = 0 IF Saldo IS NOT ZERO *> ─── Abbreviated Conditions ─── *> Invece di: IF A = 1 OR A = 2 OR A = 3 IF A = 1 OR 2 OR 3 DISPLAY "Valido". *> Invece di: IF A > 5 AND A < 10 IF A > 5 AND < 10 DISPLAY "Nel range".
EVALUATE TRUE WHEN IsPrime DISPLAY "Primo" WHEN IsOdd DISPLAY "Dispari" WHEN IsEven DISPLAY "Pari" WHEN OTHER DISPLAY "Default" END-EVALUATE. EVALUATE Scelta ALSO Modo WHEN 1 ALSO 'A' PERFORM ParagA WHEN 2 ALSO ANY PERFORM ParagB WHEN 3 THRU 5 ALSO ANY PERFORM ParagC END-EVALUATE.
*> Chiama un paragrafo PERFORM NomeParagrafo. PERFORM NomeParagrafo THRU AltroParagrafo. *> Ripeti N volte PERFORM 5 TIMES DISPLAY "Loop" END-PERFORM. *> While (test prima) PERFORM UNTIL Indice > 10 ADD 1 TO Indice END-PERFORM. *> Do-While (test dopo) PERFORM WITH TEST AFTER UNTIL Indice > 10 ADD 1 TO Indice END-PERFORM. *> For loop PERFORM VARYING I FROM 1 BY 1 UNTIL I > 10 DISPLAY I END-PERFORM. *> For loop annidato PERFORM VARYING I FROM 1 BY 1 UNTIL I > 3 AFTER J FROM 1 BY 1 UNTIL J > 3 DISPLAY I " " J END-PERFORM. *> PERFORM con paragrafo esterno e VARYING PERFORM StampaRiga VARYING I FROM 1 BY 1 UNTIL I > 5.
GO TO Paragrafo. *> DEPENDING ON: switch su variabile GO TO Para1, Para2, Para3 DEPENDING ON Scelta. *> EXIT: uscita da paragrafo/sezione EXIT PARAGRAPH. *> esce dal paragrafo corrente EXIT PROGRAM. *> ritorna al chiamante EXIT SECTION. *> esce dalla sezione corrente STOP RUN. *> termina il programma *> ─── ALTER (COBOL-68/74 — OBSOLETO) ─── *> Modifica a runtime la destinazione di un GO TO Dispatch. GO TO DefaultHandler. DefaultHandler. DISPLAY "Nessun handler". SpecialHandler. DISPLAY "Handler speciale". *> Cambia la destinazione di Dispatch ALTER Dispatch TO PROCEED TO SpecialHandler. *> Ora GO TO in Dispatch salta a SpecialHandler
Gravity (fall-through): in COBOL, l'esecuzione scorre sequenzialmente da un paragrafo al successivo, senza fermarsi. Un paragrafo non è una funzione: senza STOP RUN, GO TO o EXIT, il controllo "cade" nel paragrafo seguente.
PROCEDURE DIVISION. Main. DISPLAY "Inizio". PERFORM CalcolaIVA. DISPLAY "Fatto". STOP RUN. *> SENZA questo, cade in CalcolaIVA! CalcolaIVA. COMPUTE TotaleIVA = Imponibile * 1.22. *> Senza STOP RUN sopra, dopo Main il controllo *> cadrebbe qui per gravity, eseguendo CalcolaIVA *> DUE VOLTE: una via PERFORM, una via fall-through. Stampa. DISPLAY "Totale: " TotaleIVA. *> Dopo CalcolaIVA, cade qui per gravity
| Meccanismo | Comportamento | Ritorno |
|---|---|---|
PERFORM Para | Esegue il paragrafo e ritorna al chiamante | Automatico alla fine del paragrafo |
PERFORM Para THRU ParaFine | Esegue da Para a ParaFine incluso, poi ritorna | Alla fine di ParaFine |
| Gravity (fall-through) | L'esecuzione scorre sequenzialmente senza ritorno | Nessuno — continua al paragrafo successivo |
GO TO Para | Salto incondizionato, non ritorna | Nessuno |
*> Una SECTION raggruppa più paragrafi SezioneUno SECTION. ParagA. DISPLAY "A". *> Cade in ParagB per gravity ParagB. DISPLAY "B". EXIT SECTION. *> Esce dalla sezione *> PERFORM SezioneUno esegue TUTTI i paragrafi *> della sezione (ParagA + ParagB) e poi ritorna.
*> Array 1D — subscript parte da 1! 01 Tabella1. 02 Amico PIC X(15) OCCURS 5 TIMES. *> Array 2D 01 TabClienti. 02 Cliente OCCURS 10 TIMES. 03 CNome PIC X(20). 03 CEmail PIC X(40). *> Tabella con INDEX esplicito 01 OrdineTab. 02 Prodotto OCCURS 5 TIMES INDEXED BY I. 03 ProdNome PIC X(10). 03 ProdSize OCCURS 3 TIMES INDEXED BY J. 04 TipoTaglia PIC A. *> OCCURS con range variabile (ODO) 01 MaxItems PIC 99 VALUE 10. 01 ListaDin. 02 Elem PIC X(10) OCCURS 1 TO 20 TIMES DEPENDING ON MaxItems. *> Accesso a elementi MOVE 'Joy' TO Amico(1). DISPLAY Amico(2). SET I J TO 1. MOVE 'S' TO TipoTaglia(I, J). SET I UP BY 1. *> incremento index SET I DOWN BY 1. *> decremento index *> Tabella con ASCENDING/DESCENDING KEY (per SEARCH ALL) 01 CodTab. 02 CodEntry OCCURS 100 TIMES ASCENDING KEY IS CodID INDEXED BY KI. 03 CodID PIC 9(5). 03 CodDesc PIC X(30).
SET I TO 1. SEARCH Prodotto AT END DISPLAY "Non trovato" WHEN ProdNome(I) = 'Blue' DISPLAY "Trovato" END-SEARCH.
*> Richiede ASCENDING/DESCENDING KEY SEARCH ALL CodEntry AT END DISPLAY "Codice non trovato" WHEN CodID(KI) = Cerca DISPLAY CodDesc(KI) END-SEARCH.
*> 1. La tabella DEVE dichiarare ASCENDING/DESCENDING KEY 01 TabCodici. 02 CodEntry OCCURS 100 TIMES ASCENDING KEY IS CodID INDEXED BY KI. 03 CodID PIC 9(5). 03 CodDesc PIC X(20). *> 2. I dati DEVONO essere pre-ordinati sulla KEY *> SEARCH ALL non ordina: esegue ricerca binaria *> su dati che ASSUME siano già ordinati. *> Dati non ordinati → risultati imprevedibili! *> 3. La WHEN può usare SOLO = (non > o <) *> 4. Non serve SET prima di SEARCH ALL (l'indice *> è gestito automaticamente dall'algoritmo binario) *> 5. Condizioni multiple: solo AND, mai OR SEARCH ALL CodEntry AT END DISPLAY "Non trovato" WHEN CodID(KI) = Cerca AND CodDesc(KI) = DescCerca DISPLAY "Trovato" END-SEARCH.
*> SORT: ordina un file tramite file di lavoro SORT WorkFile ON ASCENDING KEY WIDNum [ON DESCENDING KEY WNome] USING OrgFile GIVING SortedFile. *> SORT con INPUT/OUTPUT PROCEDURE SORT WorkFile ON ASCENDING KEY WIDNum INPUT PROCEDURE IS ReadAndFilter OUTPUT PROCEDURE IS WriteOutput. *> MERGE: unisce file già ordinati MERGE WorkFile ON ASCENDING KEY WIDNum USING File1, File2 GIVING NewFile. *> RELEASE (dentro INPUT PROCEDURE) → aggiunge record al sort RELEASE WStudData FROM StudData. *> RETURN (dentro OUTPUT PROCEDURE) → legge record dal sort RETURN WorkFile INTO StudData AT END MOVE 'Y' TO Done.
Le procedure permettono di filtrare/trasformare i record prima e dopo l'ordinamento.
SORT WorkFile ON ASCENDING KEY WIDNum INPUT PROCEDURE IS FiltraInput OUTPUT PROCEDURE IS ScriviOutput. *> ─── INPUT PROCEDURE: legge, filtra e passa al sort ─── FiltraInput. OPEN INPUT OrgFile. PERFORM UNTIL EOF READ OrgFile AT END SET EOF TO TRUE END-READ IF NOT EOF IF Stato = "A" *> filtra: solo attivi RELEASE WStudData FROM StudData END-IF END-IF END-PERFORM. CLOSE OrgFile. *> ─── OUTPUT PROCEDURE: legge dal sort e scrive ─── ScriviOutput. OPEN OUTPUT SortedFile. PERFORM UNTIL SortDone RETURN WorkFile INTO StudData AT END SET SortDone TO TRUE END-RETURN IF NOT SortDone ADD 1 TO RecCount *> conteggio WRITE OutRec FROM StudData END-IF END-PERFORM. CLOSE SortedFile.
La gestione file in COBOL si articola su tre livelli distribuiti tra le divisioni. Comprendere la relazione tra questi livelli e' fondamentale per qualsiasi programma batch o transazionale.
| Livello | Dove | Clausola | Scopo |
|---|---|---|---|
| 1. Associazione logica | ENVIRONMENT DIVISION → INPUT-OUTPUT SECTION → FILE-CONTROL | SELECT | Associa un nome-file logico COBOL a un file fisico esterno, e dichiara organizzazione, modalita' di accesso e chiavi |
| 2. Descrizione record | DATA DIVISION → FILE SECTION | FD / SD | Definisce la struttura (layout) dei record del file: campi, tipi, dimensioni |
| 3. Operazioni I/O | PROCEDURE DIVISION | OPEN, READ, WRITE, REWRITE, DELETE, START, CLOSE | Esegue le operazioni fisiche di lettura/scrittura |
INPUT-OUTPUT SECTION. FILE-CONTROL. SELECT [OPTIONAL] nome-file-logico ASSIGN TO "percorso-fisico" *> o variabile WS ORGANIZATION IS tipo-org *> SEQUENTIAL | LINE SEQUENTIAL | INDEXED | RELATIVE ACCESS MODE IS tipo-accesso *> SEQUENTIAL | RANDOM | DYNAMIC [RECORD KEY IS campo-chiave] *> solo INDEXED [ALTERNATE RECORD KEY IS campo [WITH DUPLICATES]] *> solo INDEXED [RELATIVE KEY IS campo] *> solo RELATIVE [FILE STATUS IS ws-status] *> PIC XX per controllo errori [LOCK MODE IS tipo-lock] *> MANUAL | AUTOMATIC | EXCLUSIVE .
FILE SECTION. FD nome-file-logico *> DEVE corrispondere al nome nel SELECT [BLOCK CONTAINS n RECORDS] *> blocco fisico (performance I/O) [RECORD CONTAINS n CHARACTERS] *> lunghezza record fissa [RECORD IS VARYING IN SIZE FROM min TO max CHARACTERS DEPENDING ON ws-len] *> record a lunghezza variabile [LABEL RECORDS ARE STANDARD] *> label tape (obsoleto, ma richiesto in alcuni dialect) [DATA RECORD IS nome-record] *> informativo [LINAGE IS n LINES] *> per file di stampa [REPORT IS nome-report] *> per Report Writer . *> Segue la definizione dei record (uno o piu' 01) 01 NomeRecord. 02 Campo1 PIC ... 02 Campo2 PIC ... *> SD: Sort/merge file Descriptor (per file di lavoro SORT) SD WorkFile. 01 WorkRecord. 02 WKey PIC 9(5). 02 WData PIC X(75).
Il legame e' basato sul nome-file-logico: il nome usato nel SELECT deve corrispondere esattamente a quello nell'FD. La SELECT definisce come si accede al file; la FD definisce cosa contiene il file.
*> ─── ENVIRONMENT DIVISION ─── FILE-CONTROL. SELECT ClienteFile *> nome logico (1) ASSIGN TO "clienti.idx" *> file fisico ORGANIZATION IS INDEXED *> tipo organizzazione ACCESS MODE IS DYNAMIC *> modalita' di accesso RECORD KEY IS CL-ID *> chiave primaria (campo nel record FD) FILE STATUS IS WS-FS. *> ─── DATA DIVISION ─── FILE SECTION. FD ClienteFile *> stesso nome logico (1) RECORD CONTAINS 80 CHARACTERS. 01 ClienteRecord. 02 CL-ID PIC 9(5). *> questa e' la RECORD KEY 02 CL-Nome PIC X(30). 02 CL-Saldo PIC S9(7)V99. 02 FILLER PIC X(36).
| ORGANIZATION | Struttura | Accesso consentito | Uso tipico |
|---|---|---|---|
SEQUENTIAL | Record in sequenza binaria (record-length header) | Solo SEQUENTIAL | File batch, comunicazione inter-programma |
LINE SEQUENTIAL | Righe di testo delimitate da newline (CR/LF) | Solo SEQUENTIAL | File di testo, log, CSV, interfaccia con Unix |
INDEXED | Record con indice B-tree su una o piu' chiavi | SEQUENTIAL, RANDOM, DYNAMIC | Anagrafe, archivi, tabelle di lookup |
RELATIVE | Record identificati da numero di posizione (slot) | SEQUENTIAL, RANDOM, DYNAMIC | Hash table su disco, buffer circolare |
| ACCESS MODE | Significato | Operazioni |
|---|---|---|
SEQUENTIAL | I record vengono letti/scritti nell'ordine in cui sono memorizzati | READ (next), WRITE (append), REWRITE (in-place) |
RANDOM | Accesso diretto tramite chiave (INDEXED) o numero relativo (RELATIVE) | READ (per chiave), WRITE, REWRITE, DELETE |
DYNAMIC | Combinazione: permette sia accesso sequenziale che random nello stesso OPEN | READ, READ NEXT, WRITE, REWRITE, DELETE, START |
| Verbo | INPUT | OUTPUT | I-O | EXTEND |
|---|---|---|---|---|
READ | Si' | No | Si' | No |
WRITE | No | Si' | Si' (solo INDEXED/RELATIVE) | Si' |
REWRITE | No | No | Si' | No |
DELETE | No | No | Si' | No |
START | Si' | No | Si' | No |
OPTIONAL nel SELECT permette di aprire un file inesistente senza errore (FILE STATUS "05"): il runtime lo crea vuoto. Senza OPTIONAL, un OPEN INPUT su file inesistente genera FILE STATUS "35" (file not found).Il paragrafo I-O-CONTROL nella INPUT-OUTPUT SECTION specifica informazioni sul buffering, la condivisione di aree di memoria tra file, e il checkpoint/restart. E' opzionale ma importante per le ottimizzazioni I/O nei batch mainframe.
ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL. SELECT FileA ASSIGN TO "filea.dat". SELECT FileB ASSIGN TO "fileb.dat". I-O-CONTROL. *> clausole di controllo I/O
| Clausola | Sintassi | Descrizione |
|---|---|---|
SAME RECORD AREA | SAME RECORD AREA FOR file1, file2 | I file condividono lo stesso buffer di record in memoria. Un READ su uno sovrascrive il buffer dell'altro. Ottimizza la memoria quando si elaborano file uno alla volta. |
SAME AREA | SAME AREA FOR file1, file2 | I file condividono sia il buffer I/O che il record area. Piu' restrittivo: i file non possono essere aperti contemporaneamente. |
SAME SORT AREA | SAME SORT AREA FOR sort-file1, sort-file2 | I file di lavoro SORT condividono la stessa area di lavoro. Utile quando i SORT sono eseguiti in sequenza, non in parallelo. |
SAME SORT-MERGE AREA | SAME SORT-MERGE AREA FOR sm1, sm2 | Analogo a SAME SORT AREA, per file di MERGE. |
MULTIPLE FILE | MULTIPLE FILE TAPE CONTAINS file1, file2 | Piu' file logici risiedono sulla stessa unita' nastro. Rilevante in ambito mainframe legacy. |
APPLY WRITE-ONLY | APPLY WRITE-ONLY ON file1 | Ottimizzazione: il buffer viene scritto su disco solo quando e' pieno (IBM). Riduce le operazioni I/O fisiche. |
RERUN | RERUN ON file EVERY n RECORDS OF file2 | Checkpoint/restart: salva lo stato ogni N record elaborati. Permette di riprendere un batch interrotto dal punto dell'ultimo checkpoint. |
I-O-CONTROL. *> Condivisione buffer: File1 e File2 usano la stessa area record *> (non possono essere letti contemporaneamente) SAME RECORD AREA FOR File1, File2. *> Checkpoint ogni 1000 record elaborati (mainframe) RERUN ON CheckFile EVERY 1000 RECORDS OF InputFile. *> Ottimizzazione scrittura (IBM) APPLY WRITE-ONLY ON OutputFile.
FILE-CONTROL. SELECT ClienteFile ASSIGN TO "clienti.dat" ORGANIZATION IS LINE SEQUENTIAL ACCESS IS SEQUENTIAL [FILE STATUS IS WS-FileStatus].
| Codice | Significato |
|---|---|
| 00 | OK |
| 10 | End of file |
| 22 | Chiave duplicata |
| 23 | Chiave non trovata |
| 30 | Errore I/O permanente |
| 35 | File non trovato |
| 41 | File già aperto |
| 42 | File non aperto |
| 47 | File non aperto in INPUT |
| 48 | File non aperto in OUTPUT |
*> Scrittura OPEN OUTPUT ClienteFile. MOVE 1 TO IDNum. WRITE ClienteData [FROM WSCliente] [AFTER ADVANCING 1 LINE] [INVALID KEY DISPLAY "Errore"] END-WRITE. CLOSE ClienteFile. *> Lettura OPEN INPUT ClienteFile. PERFORM UNTIL EOF = 'Y' READ ClienteFile [INTO WSCliente] AT END MOVE 'Y' TO EOF NOT AT END DISPLAY WSCliente END-READ END-PERFORM. CLOSE ClienteFile. *> Append OPEN EXTEND ClienteFile. WRITE ClienteData. CLOSE ClienteFile.
FILE-CONTROL. SELECT ClienteFile ASSIGN TO "clienti.idx" ORGANIZATION IS INDEXED ACCESS MODE IS RANDOM *> o DYNAMIC o SEQUENTIAL RECORD KEY IS IDNum [ALTERNATE RECORD KEY IS Cognome WITH DUPLICATES] FILE STATUS IS FS. *> Aggiunta (WRITE) OPEN I-O ClienteFile. MOVE 99 TO IDNum. WRITE ClienteData INVALID KEY DISPLAY "ID duplicato" END-WRITE. *> Lettura per chiave (RANDOM) MOVE 5 TO IDNum. READ ClienteFile INVALID KEY DISPLAY "Non trovato" END-READ. *> Aggiornamento REWRITE ClienteData INVALID KEY DISPLAY "Errore" END-REWRITE. *> Cancellazione DELETE ClienteFile INVALID KEY DISPLAY "Non trovato" END-DELETE. *> Lettura sequenziale (ACCESS DYNAMIC) START ClienteFile KEY GREATER THAN IDNum INVALID KEY DISPLAY "Errore" END-START. READ ClienteFile NEXT RECORD INTO WSCliente AT END MOVE 'Y' TO EOF END-READ.
Organizzazione RELATIVE: ogni record ha un numero relativo (posizione). Accesso diretto per numero, utile per tabelle di lookup su disco.
FILE-CONTROL. SELECT SlotFile ASSIGN TO "slot.dat" ORGANIZATION IS RELATIVE ACCESS MODE IS DYNAMIC *> o SEQUENTIAL o RANDOM RELATIVE KEY IS WS-Slot FILE STATUS IS WS-FS. DATA DIVISION. FILE SECTION. FD SlotFile. 01 SlotRecord PIC X(80). WORKING-STORAGE SECTION. 01 WS-Slot PIC 9(4). 01 WS-FS PIC XX. PROCEDURE DIVISION. OPEN I-O SlotFile. *> Scrittura diretta nello slot 5 MOVE 5 TO WS-Slot. MOVE "Dati slot 5" TO SlotRecord. WRITE SlotRecord INVALID KEY DISPLAY "Slot occupato" END-WRITE. *> Lettura diretta per slot MOVE 3 TO WS-Slot. READ SlotFile INVALID KEY DISPLAY "Slot vuoto" END-READ. *> Cancellazione DELETE SlotFile INVALID KEY DISPLAY "Errore" END-DELETE. *> Lettura sequenziale (ACCESS DYNAMIC) MOVE 1 TO WS-Slot. START SlotFile KEY NOT LESS THAN WS-Slot INVALID KEY DISPLAY "Errore" END-START. READ SlotFile NEXT RECORD AT END DISPLAY "Fine" END-READ. CLOSE SlotFile.
| Confronto | SEQUENTIAL | RELATIVE | INDEXED |
|---|---|---|---|
| Accesso | Solo sequenziale | Per numero record | Per chiave alfanumerica |
| Chiave | Nessuna | Numero relativo (PIC 9) | Campo nel record |
| DELETE | No | Sì | Sì |
| REWRITE | Sì (stessa lunghezza) | Sì | Sì |
| Buchi | No | Sì (slot vuoti) | No |
| Uso tipico | Log, batch | Lookup fisso, hash | Database, anagrafe |
Il Report Writer (RW) automatizza intestazioni, piè pagina, subtotali e impaginazione. Richiede REPORT SECTION nella DATA DIVISION e verbi INITIATE/GENERATE/TERMINATE.
FILE-CONTROL. SELECT ReportFile ASSIGN TO "report.txt". FILE SECTION. FD ReportFile REPORT IS VenditeReport.
REPORT SECTION. RD VenditeReport CONTROLS ARE FINAL WS-Regione PAGE LIMIT IS 60 LINES HEADING 1 FIRST DETAIL 5 LAST DETAIL 55 FOOTING 58. *> PAGE HEADING — stampato in cima a ogni pagina 01 TYPE PAGE HEADING. 02 LINE 1. 03 COLUMN 1 PIC X(20) VALUE "REPORT VENDITE". 03 COLUMN 60 PIC X(8) SOURCE WS-Data. 02 LINE 3. 03 COLUMN 1 PIC X(10) VALUE "Regione". 03 COLUMN 15 PIC X(10) VALUE "Prodotto". 03 COLUMN 30 PIC X(10) VALUE "Importo". *> CONTROL HEADING — all'inizio di ogni gruppo 01 TYPE CONTROL HEADING WS-Regione. 02 LINE PLUS 1. 03 COLUMN 1 PIC X(20) SOURCE WS-Regione. *> DETAIL — riga di dettaglio per ogni GENERATE 01 RigaDettaglio TYPE DETAIL. 02 LINE PLUS 1. 03 COLUMN 15 PIC X(15) SOURCE WS-Prodotto. 03 COLUMN 30 PIC $$$,$$9.99 SOURCE WS-Importo. *> CONTROL FOOTING — alla fine di ogni gruppo (subtotale) 01 TYPE CONTROL FOOTING WS-Regione. 02 LINE PLUS 1. 03 COLUMN 20 PIC X(10) VALUE "Subtot:". 03 COLUMN 30 PIC $$$,$$9.99 SUM WS-Importo. *> REPORT FOOTING (FINAL) — totale generale 01 TYPE CONTROL FOOTING FINAL. 02 LINE PLUS 2. 03 COLUMN 20 PIC X(10) VALUE "TOTALE:". 03 COLUMN 30 PIC $$$$,$$9.99 SUM WS-Importo. *> PAGE FOOTING — piè pagina 01 TYPE PAGE FOOTING. 02 LINE 58. 03 COLUMN 30 PIC X(7) VALUE "Pagina ". 03 COLUMN 37 PIC Z9 SOURCE PAGE-COUNTER.
PROCEDURE DIVISION. OPEN OUTPUT ReportFile. INITIATE VenditeReport. *> inizializza contatori e report PERFORM UNTIL EOF READ InputFile AT END SET EOF TO TRUE END-READ GENERATE RigaDettaglio *> produce una riga, gestisce automaticamente *> page break, heading, footing, subtotali END-PERFORM. TERMINATE VenditeReport. *> stampa gli ultimi footing e totali CLOSE ReportFile.
| Tipo | Quando viene stampato |
|---|---|
REPORT HEADING | Una volta, all'inizio del report (dopo INITIATE) |
PAGE HEADING | In cima a ogni pagina |
CONTROL HEADING | Quando il valore di un campo di controllo cambia |
DETAIL | Per ogni GENERATE |
CONTROL FOOTING | Alla fine di un gruppo di controllo (subtotali) |
PAGE FOOTING | In fondo a ogni pagina |
REPORT FOOTING | Una volta, alla fine del report (dopo TERMINATE) |
*> Pattern alternativo con WRITE / ADVANCING 01 PrintLine PIC X(80). 01 LineCount PIC 99 VALUE ZERO. 88 NuovaPagina VALUE 60 THRU 99. WRITE PrintLine FROM Intestazione AFTER ADVANCING PAGE. WRITE PrintLine FROM LineaDettaglio AFTER ADVANCING 1 LINE. WRITE PrintLine FROM Separatore BEFORE ADVANCING 2 LINES.
| Clausola | Dove | Effetto |
|---|---|---|
GROUP INDICATE | Campo in DETAIL | Il campo viene stampato solo alla prima riga del gruppo (poi viene soppresso). Utile per evitare ripetizioni del nome regione su ogni riga. |
RESET ON | Campo con SUM | Specifica quando azzerare un accumulatore. Default: si azzera al cambio del controllo associato al footing. RESET ON FINAL mantiene il totale per l'intero report. |
USE BEFORE REPORTING | DECLARATIVES | Procedura invocata prima della stampa di un gruppo RD. Permette logica personalizzata (calcoli, soppressione condizionale via SUPPRESS PRINTING). |
SUPPRESS PRINTING | Dentro USE BEFORE REPORTING | Impedisce la stampa del gruppo corrente (soppressione condizionale di righe). |
*> GROUP INDICATE: stampa la regione solo sulla prima riga 01 RigaDettaglio TYPE DETAIL. 02 LINE PLUS 1. 03 COLUMN 1 PIC X(15) SOURCE WS-Regione GROUP INDICATE. *> solo alla prima riga del gruppo 03 COLUMN 20 PIC X(15) SOURCE WS-Prodotto. 03 COLUMN 40 PIC $$$,$$9.99 SOURCE WS-Importo. *> RESET ON: accumulatore che NON si azzera a ogni gruppo 01 TYPE CONTROL FOOTING WS-Regione. 02 LINE PLUS 1. 03 COLUMN 20 PIC X(12) VALUE "Subtot:". 03 COLUMN 40 PIC $$$,$$9.99 SUM WS-Importo. 03 COLUMN 55 PIC $$$,$$9.99 SUM WS-Importo RESET ON FINAL. *> totale progressivo, mai azzerato
*> USE BEFORE REPORTING: logica custom prima della stampa DECLARATIVES. Controllo-Dettaglio SECTION. USE BEFORE REPORTING RigaDettaglio. Controllo-Dettaglio-Para. IF WS-Importo = 0 SUPPRESS PRINTING *> non stampare righe con importo zero END-IF. END DECLARATIVES.
*> Compila: cobc -m GETSUM.cob IDENTIFICATION DIVISION. PROGRAM-ID. GETSUM. DATA DIVISION. LINKAGE SECTION. 01 LNum1 PIC 9. 01 LNum2 PIC 9. 01 LSum PIC 99. PROCEDURE DIVISION USING LNum1 LNum2 LSum. COMPUTE LSum = LNum1 + LNum2. EXIT PROGRAM.
*> Compila: cobc -x main.cob CALL 'GETSUM' USING Num1, Num2, Sum1. *> BY REFERENCE (default): modifiche visibili CALL 'PROC' USING BY REFERENCE Var1. *> BY CONTENT: copia; modifiche non visibili CALL 'PROC' USING BY CONTENT Var1. *> BY VALUE: passa valore diretto (per C) CALL 'PROC' USING BY VALUE 42. *> RETURNING: valore di ritorno CALL 'FUNZ' USING Param RETURNING Risultato. *> ON EXCEPTION: gestione errore CALL 'MODULO' USING Dati ON EXCEPTION DISPLAY "Modulo mancante" END-CALL.
Il modulo viene caricato a runtime (dynamic linking). Il nome è risolto al momento dell'esecuzione. Richiede .so / .dll visibile.
CALL "nome-modulo" USING Arg1 Arg2. *> Oppure con variabile 01 NomeModulo PIC X(20) VALUE "CALCOLA". CALL NomeModulo USING Dati. *> Risolto a runtime
Il modulo viene incorporato al momento della link (static linking). Richiede che tutti i moduli siano compilati insieme o linkati con -lnome.
*> Modo 1: flag compilatore (preferito) cobc -x -fstatic-call main.cob MODULO.cob *> Modo 2: direttiva nel sorgente (GnuCOBOL) >>CALL-CONVENTION STATIC CALL "CALCOLA" USING Dati. *> Modo 3: con REPOSITORY (OO/moderni) REPOSITORY. FUNCTION MiaFunzione AS "mia-funzione" IS STATIC.
| Caratteristica | Dinamica | Statica |
|---|---|---|
| Nome call | Letterale o variabile | Solo letterale noto a compile time |
| Linking | Runtime (dlopen) | Compile time (ld) |
| Velocità | Più lenta (risoluzione runtime) | Più veloce (no overhead) |
| Flessibilità | Alta (plug-in, moduli dinamici) | Bassa (binario monolitico) |
| Flag cobc | default | -fstatic-call |
CANCEL "nome-modulo". *> Forza rilascio dalla memoria e reinizializza *> le variabili globali del modulo alla prossima CALL
*> printf / puts 01 MsgBuf PIC X(80) VALUE "Ciao mondo!\n\x00". CALL "puts" USING BY REFERENCE MsgBuf. CALL "printf" USING BY REFERENCE MsgBuf. *> malloc / free 01 BufPtr USAGE POINTER. 01 BufSize USAGE BINARY-LONG. MOVE 1024 TO BufSize. CALL "malloc" USING BY VALUE BufSize RETURNING BufPtr. CALL "free" USING BY VALUE BufPtr. *> strlen 01 StrLen USAGE BINARY-LONG. CALL "strlen" USING BY REFERENCE MsgBuf RETURNING StrLen. *> memcpy 01 SrcBuf PIC X(100). 01 DstBuf PIC X(100). 01 BufLen USAGE BINARY-LONG VALUE 100. CALL "memcpy" USING BY REFERENCE DstBuf BY REFERENCE SrcBuf BY VALUE BufLen. *> getenv 01 EnvPtr USAGE POINTER. 01 EnvName PIC X(20) VALUE "HOME\x00". CALL "getenv" USING BY REFERENCE EnvName RETURNING EnvPtr. *> system (shell command) 01 Cmd PIC X(80) VALUE "ls -l\x00". CALL "system" USING BY REFERENCE Cmd.
*> CBL_OC_GETENV / CBL_OC_SETENV (GnuCOBOL native) CALL "CBL_OC_GETENV" USING BY REFERENCE EnvName BY REFERENCE EnvValue. *> CBL_GC_FORK (solo Unix) CALL "CBL_GC_FORK" RETURNING PID. *> Accesso a memoria tramite puntatore 01 RawPtr USAGE POINTER. 01 ValAdr USAGE BINARY-LONG BASED. SET ADDRESS OF ValAdr TO RawPtr. DISPLAY ValAdr. *> deref del puntatore
*> open / read / write / close 01 FD-Sys USAGE BINARY-LONG. 01 Flags USAGE BINARY-LONG VALUE 0. *> O_RDONLY=0 01 Mode USAGE BINARY-LONG VALUE 0. 01 FilePath PIC X(40) VALUE "/etc/hostname\x00". CALL "open" USING BY REFERENCE FilePath BY VALUE Flags BY VALUE Mode RETURNING FD-Sys. 01 Buffer PIC X(256). 01 BufLen USAGE BINARY-LONG VALUE 256. 01 BytesRd USAGE BINARY-LONG. CALL "read" USING BY VALUE FD-Sys BY REFERENCE Buffer BY VALUE BufLen RETURNING BytesRd. CALL "close" USING BY VALUE FD-Sys.
\x00 (null byte). Compilare con cobc -x prog.cob -lc (di solito implicito).CLASS-ID. todolist. DATA DIVISION. CLASS-STORAGE SECTION. 01 ListName PIC X(20). PROCEDURE DIVISION. FACTORY. METHOD-ID. new. DATA DIVISION. LINKAGE SECTION. 01 LName PIC X(20). PROCEDURE DIVISION USING LName RETURNING SELF. MOVE LName TO ListName. INVOKE SUPER "new" RETURNING SELF. END METHOD new. END FACTORY. END CLASS todolist.
REPOSITORY. CLASS TodoCls AS "todolist". DATA DIVISION. WORKING-STORAGE SECTION. 01 WkTodo USAGE OBJECT REFERENCE TodoCls. PROCEDURE DIVISION. *> Crea istanza INVOKE TodoCls "new" USING BY CONTENT "La mia lista" RETURNING WkTodo. *> Chiama metodo INVOKE WkTodo "PrintToDos". *> Distruggi oggetto INVOKE WkTodo "finalize".
CLASS-ID. Contatore. DATA DIVISION. CLASS-STORAGE SECTION. 01 Valore PIC 9(5) VALUE ZERO. PROCEDURE DIVISION. FACTORY. METHOD-ID. new. PROCEDURE DIVISION RETURNING SELF. INVOKE SUPER "new" RETURNING SELF. END METHOD new. END FACTORY. OBJECT. *> Metodi di istanza (non FACTORY) METHOD-ID. Incrementa. PROCEDURE DIVISION. ADD 1 TO Valore. END METHOD Incrementa. METHOD-ID. GetValore. DATA DIVISION. LINKAGE SECTION. 01 LVal PIC 9(5). PROCEDURE DIVISION RETURNING LVal. MOVE Valore TO LVal. END METHOD GetValore. END OBJECT. END CLASS Contatore.
*> Classe derivata che eredita da Contatore CLASS-ID. ContatoreMax INHERITS Contatore. DATA DIVISION. CLASS-STORAGE SECTION. 01 MaxVal PIC 9(5) VALUE 100. PROCEDURE DIVISION. OBJECT. *> Override del metodo Incrementa METHOD-ID. Incrementa OVERRIDE. PROCEDURE DIVISION. IF Valore < MaxVal INVOKE SUPER "Incrementa" END-IF. END METHOD Incrementa. END OBJECT. END CLASS ContatoreMax.
*> Definizione di un'interfaccia INTERFACE-ID. Stampabile. PROCEDURE DIVISION. METHOD-ID. Stampa. PROCEDURE DIVISION. END METHOD Stampa. END INTERFACE Stampabile. *> Classe che implementa l'interfaccia CLASS-ID. Documento IMPLEMENTS Stampabile. *> DEVE fornire implementazione di Stampa
| Concetto | Costrutto COBOL | Note |
|---|---|---|
| Classe | CLASS-ID | Contiene FACTORY (metodi di classe) e OBJECT (metodi di istanza) |
| Costruttore | METHOD-ID. new in FACTORY | Deve chiamare INVOKE SUPER "new" |
| Metodo istanza | METHOD-ID in OBJECT | Accede a CLASS-STORAGE |
| Ereditarietà | INHERITS | Singola ereditarietà; override con OVERRIDE |
| Interfaccia | INTERFACE-ID | Contratto puro; IMPLEMENTS nella classe |
| Polimorfismo | USAGE OBJECT REFERENCE | Riferimento generico: USAGE OBJECT REFERENCE Stampabile |
| Distruttore | INVOKE obj "finalize" | Rilascio manuale dell'oggetto |
| Tipo C | COBOL (USAGE) | COBOL (PIC) | Byte |
|---|---|---|---|
int8_t | USAGE BINARY-CHAR | PIC S9(3) | 1 |
uint8_t | USAGE BINARY-CHAR UNSIGNED | PIC 9(3) | 1 |
int16_t | USAGE BINARY-SHORT | PIC S9(5) | 2 |
uint16_t | USAGE BINARY-SHORT UNSIGNED | PIC 9(5) | 2 |
int32_t | USAGE BINARY-LONG | PIC S9(9) | 4 |
uint32_t | USAGE BINARY-LONG UNSIGNED | PIC 9(9) | 4 |
int64_t | USAGE BINARY-DOUBLE | PIC S9(18) | 8 |
uint64_t | USAGE BINARY-DOUBLE UNSIGNED | PIC 9(18) | 8 |
float | USAGE FLOAT-SHORT o COMP-1 | N/A (no PIC) | 4 |
double | USAGE FLOAT-LONG o COMP-2 | N/A | 8 |
long double | USAGE FLOAT-EXTENDED | N/A | 16 |
char[n] | — | PIC X(n) | n |
char* (null-term) | USAGE POINTER | PIC X(n) + \x00 | ptr size |
void* | USAGE POINTER | — | 4/8 |
size_t | USAGE BINARY-LONG UNSIGNED (32-bit)USAGE BINARY-DOUBLE UNSIGNED (64-bit) | PIC 9(10) / PIC 9(18) | 4/8 |
bool (C99) | PIC 9(1) o PIC 1 USAGE BIT | PIC 9 | 1 |
*> Esempio pratico 01 CIntVal USAGE BINARY-LONG. *> int32_t 01 CUIntVal USAGE BINARY-LONG UNSIGNED. *> uint32_t 01 CFloat USAGE FLOAT-SHORT. *> float 01 CDouble USAGE FLOAT-LONG. *> double 01 CString PIC X(64). *> char[64] 01 CPtr USAGE POINTER. *> void*
// C
typedef struct {
int32_t id;
char nome[32];
float saldo;
uint8_t flag;
} Cliente;
*> COBOL equivalente 01 Cliente. 02 ID USAGE BINARY-LONG. 02 Nome PIC X(32). 02 Saldo USAGE FLOAT-SHORT. 02 Flag USAGE BINARY-CHAR UNSIGNED.
// C
union Dato {
int32_t intero;
float reale;
char bytes[4];
};
*> COBOL 01 DatoRaw PIC X(4). 01 DatoInt REDEFINES DatoRaw USAGE BINARY-LONG. 01 DatoFloat REDEFINES DatoRaw USAGE FLOAT-SHORT.
// C
typedef enum {
APERTO = 0,
CHIUSO = 1,
ERRORE = 2
} Stato;
*> COBOL 01 StatoCod USAGE BINARY-LONG VALUE 0. 88 APERTO VALUE 0. 88 CHIUSO VALUE 1. 88 ERRORE VALUE 2. *> Uso: SET APERTO TO TRUE. *> IF CHIUSO DISPLAY "Chiuso".
01 MioPtr USAGE POINTER. 01 IntTarget USAGE BINARY-LONG BASED. *> BASED = allocato via puntatore 01 FunzPtr USAGE FUNCTION-POINTER. *> Ottenere l'indirizzo di una variabile SET MioPtr TO ADDRESS OF IntTarget. *> Usare il puntatore (deref) SET ADDRESS OF IntTarget TO MioPtr. DISPLAY IntTarget. *> NULL check IF MioPtr = NULL DISPLAY "Puntatore nullo" END-IF. *> Puntatore a funzione (callback) SET FunzPtr TO ENTRY "MiaFunzione". CALL FunzPtr USING Parametro.
// C
int32_t valori[10];
valori[0] = 42;
valori[9] = 100;
*> COBOL (subscript parte da 1!) 01 TabellaValori. 02 Valore USAGE BINARY-LONG OCCURS 10 TIMES. MOVE 42 TO Valore(1). MOVE 100 TO Valore(10).
// C
int32_t matrice[3][4];
matrice[1][2] = 7;
*> COBOL 01 Matrice. 02 Riga OCCURS 3 TIMES INDEXED BY I. 03 Cella USAGE BINARY-LONG OCCURS 4 TIMES INDEXED BY J. SET I TO 2. SET J TO 3. MOVE 7 TO Cella(I, J).
*> Stringa COBOL → C null-terminated 01 CobolStr PIC X(30) VALUE "Ciao mondo". 01 CStr PIC X(31). *> +1 per \0 MOVE SPACES TO CStr. MOVE CobolStr TO CStr. *> Scrivere manualmente il terminatore null MOVE X"00" TO CStr(FUNCTION LENGTH( FUNCTION TRIM(CobolStr)) + 1 : 1). *> In alternativa con INSPECT INSPECT CStr REPLACING TRAILING SPACES BY LOW-VALUES. *> Stringa C → COBOL (pulizia null e padding) INSPECT CStr REPLACING ALL X"00" BY SPACE. *> Reference modification (substring) *> variabile(start : lunghezza) DISPLAY CobolStr(1 : 4). *> "Ciao" MOVE CobolStr(6 : 5) TO Parte2. *> "mondo"
X"00" alla fine della stringa.La SCREEN SECTION permette di costruire interfacce testuali interattive (TUI) tipo terminal. Richiede libreria curses/PDCurses. Compilare con cobc -x -lncurses prog.cob.
| Clausola | Effetto |
|---|---|
BLANK SCREEN | Cancella tutto lo schermo |
BLANK LINE | Cancella la riga corrente |
LINE n | Posizione riga (1-based) |
COLUMN n | Posizione colonna (1-based) |
LINE PLUS n | Riga relativa (+n dalla corrente) |
COLUMN PLUS n | Colonna relativa |
VALUE "testo" | Testo fisso sullo schermo |
FROM variabile | Output: legge da variabile working-storage |
TO variabile | Input: scrive in variabile working-storage |
USING variabile | Input+Output (FROM+TO insieme) |
PIC X(n) | Formato campo input |
FOREGROUND-COLOR n | Colore testo (0-7: nero,rosso,verde,giallo,blu,magenta,ciano,bianco) |
BACKGROUND-COLOR n | Colore sfondo |
HIGHLIGHT | Testo evidenziato/grassetto |
LOWLIGHT | Testo dimmerato |
REVERSE-VIDEO | Inversione colori |
UNDERLINE | Sottolineato |
BLINK | Lampeggiante |
BELL | Segnale acustico |
SECURE | Input nascosto (password) |
REQUIRED | Campo obbligatorio |
FULL | Deve riempire tutto il campo |
AUTO | Avanza automaticamente al campo successivo |
NO ECHO | Non mostra l'input digitato |
ERASE EOL | Cancella fino a fine riga |
ERASE EOS | Cancella fino a fine schermo |
SCROLL DOWN | Scorrimento verso il basso |
SIZE n | Dimensione campo (alternativa a PIC) |
UPPER | Converte input in maiuscolo |
LOWER | Converte input in minuscolo |
| Num | Colore | Num | Colore |
|---|---|---|---|
| 0 | Nero (BLACK) | 4 | Rosso (RED) |
| 1 | Blu (BLUE) | 5 | Magenta (MAGENTA) |
| 2 | Verde (GREEN) | 6 | Giallo (YELLOW) |
| 3 | Ciano (CYAN) | 7 | Bianco (WHITE) |
DATA DIVISION. WORKING-STORAGE SECTION. 01 WS-Nome PIC X(30). 01 WS-Eta PIC 99. 01 WS-Password PIC X(20). 01 WS-Scelta PIC 9. SCREEN SECTION. 01 SchermoPrincipale BACKGROUND-COLOR 1 *> sfondo blu FOREGROUND-COLOR 7. *> testo bianco *> Sfondo e titolo 02 BLANK SCREEN. *> Titolo centrato riga 1 02 LINE 1 COLUMN 30 VALUE "=== GESTIONE CLIENTI ===" FOREGROUND-COLOR 6 *> giallo HIGHLIGHT. *> Label 02 LINE 4 COLUMN 5 VALUE "Nome: " FOREGROUND-COLOR 7. *> Campo input 02 LINE 4 COLUMN 12 PIC X(30) USING WS-Nome FOREGROUND-COLOR 3 *> ciano BACKGROUND-COLOR 0 *> nero REQUIRED AUTO. *> Età 02 LINE 5 COLUMN 5 VALUE "Eta: ". 02 LINE 5 COLUMN 12 PIC 99 USING WS-Eta FOREGROUND-COLOR 6 AUTO. *> Password con oscuramento 02 LINE 6 COLUMN 5 VALUE "Pass: ". 02 LINE 6 COLUMN 12 PIC X(20) TO WS-Password SECURE FOREGROUND-COLOR 6. *> Riga separatore 02 LINE 8 COLUMN 1 PIC X(80) VALUE ALL "-" FOREGROUND-COLOR 5. *> Messaggio stato 02 LINE 22 COLUMN 1 VALUE "F1=Aiuto F3=Esci INVIO=Conferma" REVERSE-VIDEO. *> Schermo di sola visualizzazione 01 SchermoOutput. 02 BLANK SCREEN. 02 LINE 5 COLUMN 10 VALUE "Risultato: ". 02 LINE 5 COLUMN 22 PIC X(40) FROM WS-Nome HIGHLIGHT. PROCEDURE DIVISION. *> Visualizza e gestisce input DISPLAY SchermoPrincipale. ACCEPT SchermoPrincipale. *> Solo visualizzazione DISPLAY SchermoOutput. *> Posizionamento diretto (senza SCREEN SECTION) DISPLAY "Testo" AT LINE 10 COLUMN 5 FOREGROUND-COLOR 2. *> ACCEPT con posizionamento ACCEPT WS-Scelta AT LINE 10 COLUMN 20.
DISPLAY nomeschermo per visualizzare e ACCEPT nomeschermo per acquisire input. Le clausole FROM (solo output), TO (solo input), USING (input+output) determinano il flusso dati.DISPLAY "Testo". DISPLAY Var1 " " Var2. DISPLAY "Msg" WITH NO ADVANCING. DISPLAY "Msg" UPON CONSOLE. DISPLAY "Err" UPON STDERR. *> Con posizionamento (curses) DISPLAY "Testo" AT 0510 *> riga 05, col 10 FOREGROUND-COLOR 2 BACKGROUND-COLOR 0.
ACCEPT Variabile. ACCEPT Variabile FROM DATE. *> YYMMDD ACCEPT Variabile FROM DATE YYYYMMDD. ACCEPT Variabile FROM TIME. *> HHMMSScc ACCEPT Variabile FROM DAY. *> YYDDD ACCEPT Variabile FROM DAY-OF-WEEK. *> 1=Lun ACCEPT Variabile FROM COMMAND-LINE. ACCEPT Variabile FROM ENVIRONMENT "HOME". *> Con posizionamento ACCEPT Variabile AT LINE 5 COLUMN 10.
cobc [opzioni] file.cob [file2.cob ...] [-l libreria]
| Flag | Effetto |
|---|---|
-x | Compila in eseguibile autonomo |
-m | Compila in modulo (.so/.dll) dinamico |
-o nome | Specifica nome file output |
-free | Source format free (senza vincoli di colonna) |
-fixed | Source format fixed (default) |
-std=cobol2014 | Standard COBOL 2014 |
-std=ibm | Compatibilità IBM mainframe |
-std=mf | Compatibilità Micro Focus |
-fstatic-call | Forza tutte le CALL a essere statiche |
-fdebugging-line | Abilita linee di debug (D in col.7) |
-debug | Abilita runtime checks complete |
-g | Simboli di debug (per gdb) |
-O / -O2 | Ottimizzazione |
-Wall | Tutti i warning |
-I dir | Directory per COPY (copybooks) |
-L dir | Directory librerie |
-l nome | Linka libreria |
-v | Verbose (mostra comandi eseguiti) |
-save-temps | Mantieni file intermedi (.c generato) |
# Compila ed esegui cobc -x hello.cob ./hello # Free format esplicito cobc -x -free hello.cob # Con output rinominato cobc -x -o programma hello.cob # Solo il C generato (debug compilazione) cobc -C hello.cob cat hello.c
# Tutto in un colpo (statico) cobc -x main.cob GETSUM.cob UTILS.cob
# Compila i moduli come shared library cobc -m GETSUM.cob # → GETSUM.so cobc -m UTILS.cob # → UTILS.so # Compila il main (le CALL verranno risolte a runtime) cobc -x main.cob # → main ./main # cerca GETSUM.so, UTILS.so in COB_LIBRARY_PATH
# Compila oggetti C cobc -C GETSUM.cob # genera GETSUM.c gcc -c GETSUM.c -o GETSUM.o $(cob-config --cflags) # Link finale cobc -x -fstatic-call main.cob GETSUM.o
| Variabile | Scopo |
|---|---|
COB_LIBRARY_PATH | Percorsi per moduli .so a runtime |
COB_COPY_DIR | Directory per COPY books |
COB_CONFIG_DIR | Directory configurazione compilatore |
COB_SCREEN_EXCEPTIONS | Abilita gestione eccezioni schermo |
COB_EXCEPTION_PROCEDURE | Procedura gestore eccezioni |
*> COPY include un file .cpy o .cob come testo COPY STDDEF. *> cerca STDDEF.cpy in COB_COPY_DIR COPY "include/common.cpy" REPLACING ==PREFISSO== BY ==WS==. *> sostituzione testo
# Compilare con libmath, libncurses, ecc. cobc -x prog.cob -lm -lncurses # Libreria custom statica cobc -x prog.cob -L/usr/local/lib -lmialib
# Linking con libreria dinamica cobc -x prog.cob -ldl # libdl per dlopen export LD_LIBRARY_PATH=/path/to/libs:$LD_LIBRARY_PATH ./prog
*> Per usare funzioni da libm (math.h) 01 Angolo USAGE FLOAT-LONG. 01 Coseno USAGE FLOAT-LONG. MOVE 1.5707963 TO Angolo. CALL "cos" USING BY VALUE Angolo RETURNING Coseno. CALL "sin" USING BY VALUE Angolo RETURNING Risultato. CALL "sqrt" USING BY VALUE Valore RETURNING Radice. CALL "pow" USING BY VALUE Base Esp RETURNING Pot. CALL "fabs" USING BY VALUE Num RETURNING Abs. CALL "floor" USING BY VALUE Num RETURNING Floor. CALL "ceil" USING BY VALUE Num RETURNING Ceil. *> Compilare: cobc -x prog.cob -lm
COBC = cobc
COBFLAGS= -x -free -Wall -debug
LIBS = -lncurses -lm
all: mioprog
mioprog: main.cob modulo1.cob modulo2.cob
$(COBC) $(COBFLAGS) -o $@ $^ $(LIBS)
modulo1.so: modulo1.cob
$(COBC) -m -free modulo1.cob
clean:
rm -f mioprog *.so *.o *.c
Il metodo più comune: controllare il FILE STATUS dopo ogni operazione I/O.
FILE-CONTROL. SELECT ClienteFile ASSIGN TO "clienti.dat" FILE STATUS IS WS-FS. WORKING-STORAGE SECTION. 01 WS-FS PIC XX. 88 FS-OK VALUE "00". 88 FS-EOF VALUE "10". 88 FS-NOTFND VALUE "23". 88 FS-DUPKEY VALUE "22". OPEN INPUT ClienteFile. IF NOT FS-OK DISPLAY "Errore apertura: " WS-FS STOP RUN END-IF.
| Codice | Categoria | Significato |
|---|---|---|
00 | Successo | Operazione completata con successo |
02 | Successo | READ riuscita, chiave duplicata presente (alternate key) |
04 | Successo | Lunghezza record diversa da quella attesa |
05 | Successo | OPEN su file opzionale inesistente (creato) |
10 | EOF | Fine file raggiunta (AT END) |
14 | EOF | READ sequenziale: numero relativo troppo grande |
21 | Errore chiave | Chiave fuori sequenza (sequential write su indexed) |
22 | Errore chiave | Chiave duplicata su WRITE |
23 | Errore chiave | Record non trovato (READ/START/DELETE) |
24 | Errore chiave | Boundary violation (disco pieno, record troppo grande) |
30 | Errore permanente | Errore I/O generico permanente |
34 | Errore permanente | Boundary violation (file sequenziale) |
35 | Errore permanente | OPEN su file non esistente (non opzionale) |
37 | Errore permanente | OPEN modo non supportato dal dispositivo |
38 | Errore permanente | OPEN su file chiuso con LOCK |
39 | Errore permanente | Attributi file conflittuali |
41 | Errore logico | OPEN su file già aperto |
42 | Errore logico | CLOSE su file non aperto |
43 | Errore logico | READ/REWRITE senza READ precedente (random/dynamic) |
44 | Errore logico | REWRITE: dimensione record cambiata (sequenziale) |
46 | Errore logico | READ sequenziale fallita: nessun record valido corrente |
47 | Errore logico | READ su file non aperto in INPUT o I-O |
48 | Errore logico | WRITE su file non aperto in OUTPUT, I-O o EXTEND |
49 | Errore logico | DELETE/REWRITE su file non aperto in I-O |
9x | Impl. defined | Errori specifici del compilatore/sistema operativo |
Le DECLARATIVES sono sezioni speciali nella PROCEDURE DIVISION che vengono invocate automaticamente dal runtime quando si verifica un errore I/O, una condizione di debug, o una label di report. Devono essere dichiarate prima di qualsiasi altro codice nella PROCEDURE DIVISION, racchiuse tra DECLARATIVES. e END DECLARATIVES.
| Forma USE | Trigger | Scopo |
|---|---|---|
USE AFTER STANDARD ERROR PROCEDURE ON file-name | Errore I/O su un file specifico | Gestione errori per singolo file |
USE AFTER STANDARD ERROR PROCEDURE ON INPUT | Errore I/O su qualsiasi file aperto in INPUT | Gestore generico per categoria di apertura |
USE AFTER STANDARD ERROR PROCEDURE ON OUTPUT | Errore I/O su qualsiasi file aperto in OUTPUT | Idem per OUTPUT |
USE AFTER STANDARD ERROR PROCEDURE ON I-O | Errore I/O su qualsiasi file aperto in I-O | Idem per I-O |
USE AFTER STANDARD ERROR PROCEDURE ON EXTEND | Errore I/O su qualsiasi file aperto in EXTEND | Idem per EXTEND |
USE FOR DEBUGGING ON procedure-name | Ingresso nel paragrafo/sezione monitorata | Debug (richiede WITH DEBUGGING MODE) |
USE BEFORE REPORTING identifier | Prima di stampare un gruppo nel Report Writer | Logica personalizzata nella stampa report |
PROCEDURE DIVISION. DECLARATIVES. *> Handler per errori su un file specifico Errore-Clienti SECTION. USE AFTER STANDARD ERROR PROCEDURE ON ClienteFile. Errore-Clienti-Para. DISPLAY "Errore I/O su ClienteFile: " WS-FS. EVALUATE WS-FS WHEN "35" DISPLAY "File non trovato" WHEN "30" DISPLAY "Errore I/O permanente" WHEN "41" DISPLAY "File gia' aperto" WHEN OTHER DISPLAY "Errore non previsto" END-EVALUATE. STOP RUN. *> Handler generico per TUTTI i file in INPUT Errore-Input SECTION. USE AFTER STANDARD ERROR PROCEDURE ON INPUT. Errore-Input-Para. DISPLAY "Errore lettura generico: " WS-FS. *> Handler per debug su un paragrafo (richiede DEBUGGING MODE) Debug-Calcolo SECTION. USE FOR DEBUGGING ON CalcolaIVA. Debug-Calcolo-Para. DISPLAY "[DEBUG] Entrato in CalcolaIVA" DISPLAY " Riga: " DEBUG-LINE DISPLAY " Nome: " DEBUG-NAME. END DECLARATIVES. *> ─── Dopo END DECLARATIVES: logica normale ─── Main-Logic SECTION. Main-Para. OPEN INPUT ClienteFile. *> Se OPEN fallisce, il runtime chiama *> automaticamente Errore-Clienti SECTION PERFORM UNTIL EOF-Reached READ ClienteFile AT END SET EOF-Reached TO TRUE END-READ END-PERFORM. CLOSE ClienteFile. STOP RUN.
| Regola | Dettaglio |
|---|---|
| Posizione obbligatoria | Subito dopo PROCEDURE DIVISION, prima di qualsiasi paragrafo o sezione non-declarativa |
| Ogni USE in una SECTION | Ogni clausola USE deve essere in una SECTION dedicata con almeno un paragrafo |
| Precedenza: specifico > generico | Se esiste sia un handler per ON ClienteFile che per ON INPUT, viene invocato quello specifico per il file |
| Flusso dopo l'handler | Se l'handler non esegue STOP RUN o GOBACK, il controllo ritorna all'istruzione successiva a quella che ha causato l'errore |
| No PERFORM verso declarative | Non si puo' chiamare una sezione DECLARATIVE con PERFORM dal codice normale |
| Coesistenza con INVALID KEY | Se il verbo ha INVALID KEY, la DECLARATIVE non viene invocata per quell'operazione (INVALID KEY ha precedenza) |
READ ClienteFile AT END SET EOF-Flag TO TRUE NOT AT END PERFORM ProcessaRecord END-READ. WRITE ClienteData INVALID KEY DISPLAY "Chiave duplicata o errore" NOT INVALID KEY ADD 1 TO RecordCount END-WRITE.
ADD A TO B ON SIZE ERROR DISPLAY "Overflow aritmetico!" MOVE ZEROS TO B NOT ON SIZE ERROR CONTINUE END-ADD. COMPUTE Result = X / Y ON SIZE ERROR DISPLAY "Divisione per zero o overflow" END-COMPUTE.
CALL "MODULO-ESTERNO" USING Dati ON EXCEPTION DISPLAY "Modulo non trovato o errore nel caricamento" NOT ON EXCEPTION DISPLAY "Chiamata riuscita" END-CALL.
*> Exception handling moderno (supporto limitato nei compilatori) *> RAISE: solleva un'eccezione RAISE EXCEPTION EC-DATA-INCOMPATIBLE. *> >>TURN: attiva il monitoraggio di eccezioni specifiche >>TURN EC-SIZE CHECKING ON >>TURN EC-BOUND CHECKING ON >>TURN EC-DATA CHECKING ON *> RESUME: dentro un handler, riprende l'esecuzione *> RESUME AT NEXT STATEMENT — riprende dal punto successivo *> all'istruzione che ha causato l'eccezione *> Esempio: handler con RESUME DECLARATIVES. Err-Bound SECTION. USE AFTER EXCEPTION CONDITION EC-BOUND. Err-Bound-Para. DISPLAY "Indice fuori range". RESUME AT NEXT STATEMENT. *> continua dopo l'errore END DECLARATIVES.
| Categoria | Trigger |
|---|---|
EC-ALL | Tutte le eccezioni (catch-all) |
EC-ARGUMENT | Argomento non valido a funzione intrinseca |
EC-BOUND | Subscript o indice fuori range |
EC-DATA | Dato incompatibile o corrotto |
EC-FLOW | Flusso irregolare (fall-through di paragrafo, ecc.) |
EC-I-O | Errore I/O generico |
EC-OVERFLOW | Overflow stringa (STRING/UNSTRING) |
EC-PROGRAM | Errore nel caricamento programma (CALL) |
EC-RANGE | Valore fuori range |
EC-SIZE | Overflow aritmetico o divisione per zero |
EC-SORT-MERGE | Errore durante SORT o MERGE |
EC-STORAGE | Memoria insufficiente (ALLOCATE) |
Da COBOL-85 è possibile annidare programmi all'interno di un programma contenitore. Ogni programma annidato ha il proprio scope di dati. Alternativa a CALL con moduli separati.
IDENTIFICATION DIVISION. PROGRAM-ID. ProgrammaEsterno. DATA DIVISION. WORKING-STORAGE SECTION. 01 Risultato PIC 9(6) VALUE ZEROS. 01 Dato1 PIC 9(3) VALUE 100. 01 Dato2 PIC 9(3) VALUE 200. PROCEDURE DIVISION. CALL "Calcolatore" USING Dato1 Dato2 Risultato. DISPLAY "Risultato: " Risultato. STOP RUN. *> ─── Programma annidato ─── IDENTIFICATION DIVISION. PROGRAM-ID. Calcolatore. DATA DIVISION. WORKING-STORAGE SECTION. 01 Temporaneo PIC 9(6). LINKAGE SECTION. 01 L-A PIC 9(3). 01 L-B PIC 9(3). 01 L-Result PIC 9(6). PROCEDURE DIVISION USING L-A L-B L-Result. COMPUTE L-Result = L-A + L-B. END PROGRAM Calcolatore. END PROGRAM ProgrammaEsterno.
*> COMMON: il programma annidato è visibile anche dai fratelli PROGRAM-ID. Utilita IS COMMON. *> INITIAL: il programma viene reinizializzato ad ogni CALL PROGRAM-ID. Contatore IS INITIAL. *> Tutte le variabili tornano al VALUE originale ad ogni invocazione *> GLOBAL: variabili visibili nei programmi annidati 01 SharedData PIC X(50) IS GLOBAL. *> I programmi figli possono accedere a SharedData senza LINKAGE
| Funzione | Descrizione |
|---|---|
ABS(n) | Valore assoluto |
SQRT(n) | Radice quadrata |
INTEGER(n) | Troncamento a intero |
INTEGER-PART(n) | Parte intera |
FRACTION-PART(n) | Parte decimale |
MOD(n,d) | Modulo |
REM(n,d) | Resto |
MAX(a,b,...) | Massimo |
MIN(a,b,...) | Minimo |
MEAN(a,b,...) | Media |
MEDIAN(a,b,...) | Mediana |
SUM(a,b,...) | Somma |
VARIANCE(a,...) | Varianza |
STANDARD-DEVIATION | Dev. standard |
EXP(n) | e^n |
LOG(n) | log naturale |
LOG10(n) | log base 10 |
SIN(n) | Seno (radianti) |
COS(n) | Coseno |
TAN(n) | Tangente |
ASIN(n) | Arcoseno |
ACOS(n) | Arcocoseno |
ATAN(n) | Arcotangente |
PI | Valore π |
RANDOM([seed]) | Numero casuale 0-1 |
| Funzione | Descrizione |
|---|---|
CURRENT-DATE | Data+ora corrente (21 char) |
WHEN-COMPILED | Data compilazione (21 char) |
DATE-OF-INTEGER(n) | Numero giorno → YYYYMMDD |
INTEGER-OF-DATE(d) | YYYYMMDD → numero giorno |
DAY-OF-INTEGER(n) | Numero giorno → YYYYDDD |
INTEGER-OF-DAY(d) | YYYYDDD → numero giorno |
| Funzione | Descrizione |
|---|---|
LENGTH(s) | Lunghezza stringa |
UPPER-CASE(s) | Maiuscolo |
LOWER-CASE(s) | Minuscolo |
REVERSE(s) | Inversa |
TRIM(s) | Rimuove spazi |
NUMVAL(s) | Stringa → numero |
CHAR(n) | Numero → char |
ORD(c) | Char → numero |
ORD-MAX | Max ordinale del set |
ORD-MIN | Min ordinale del set |
*> Uso FUNCTION COMPUTE R = FUNCTION SQRT(9). MOVE FUNCTION CURRENT-DATE TO DataOra. DISPLAY FUNCTION UPPER-CASE(Nome). COMPUTE X = FUNCTION PI. *> FUNCTION come statement di USE ENVIRONMENT DIVISION. CONFIGURATION SECTION. REPOSITORY. FUNCTION ALL INTRINSIC. *> → poi si può usare senza "FUNCTION": COMPUTE X = SQRT(2).
I registri speciali sono variabili predefinite dal compilatore, disponibili senza dichiarazione in WORKING-STORAGE.
| Registro | Tipo | Descrizione |
|---|---|---|
RETURN-CODE | PIC S9(4) COMP | Codice di ritorno del programma o dell'ultimo CALL. Visibile al sistema operativo dopo STOP RUN. |
SORT-STATUS | PIC 9(4) | Stato dell'ultima operazione SORT/MERGE. 0 = successo. |
SORT-RETURN | PIC S9(4) COMP | Alias di SORT-STATUS in alcuni dialetti (IBM). |
LINAGE-COUNTER | PIC 9(n) | Numero riga corrente in un file con clausola LINAGE. Gestito automaticamente da WRITE ADVANCING. |
PAGE-COUNTER | PIC 9(n) | Contatore pagine nel Report Writer. Incrementato automaticamente. |
LINE-COUNTER | PIC 9(n) | Contatore righe nel Report Writer. |
NUMBER-OF-CALL-PARAMETERS | PIC 9(2) COMP | Numero di parametri passati all'ultima CALL (GnuCOBOL). |
COB-CRT-STATUS | PIC 9(4) | Stato dell'ultimo ACCEPT da schermo. Tasti funzione: 1001=F1, 1002=F2, ecc. (GnuCOBOL). |
WHEN-COMPILED | PIC X(21) | Data/ora di compilazione. |
*> RETURN-CODE: comunicazione tra programmi CALL "VALIDATORE" USING Dati. IF RETURN-CODE NOT = 0 DISPLAY "Validazione fallita, codice: " RETURN-CODE END-IF. *> Impostare il return code per il chiamante MOVE 0 TO RETURN-CODE. STOP RUN. *> il sistema vede exit code 0 *> GOBACK al posto di STOP RUN (nei sottoprogrammi) MOVE 4 TO RETURN-CODE. GOBACK. *> ritorna al chiamante, RC=4 *> SORT-STATUS: controllo dopo SORT SORT WorkFile ON ASCENDING KEY WKey USING InFile GIVING OutFile. IF SORT-STATUS NOT = 0 DISPLAY "Errore SORT: " SORT-STATUS END-IF. *> NUMBER-OF-CALL-PARAMETERS (GnuCOBOL) *> Utile per parametri opzionali in sottoprogrammi IF NUMBER-OF-CALL-PARAMETERS < 3 MOVE SPACES TO LParam3 *> default se non passato END-IF. *> COB-CRT-STATUS: rilevare tasti funzione (GnuCOBOL) *> Richiede: SET ENVIRONMENT "COB_SCREEN_EXCEPTIONS" TO "Y" ACCEPT WS-Campo AT LINE 5 COLUMN 10. EVALUATE COB-CRT-STATUS WHEN 0 CONTINUE *> Enter WHEN 1001 PERFORM Aiuto *> F1 WHEN 1003 STOP RUN *> F3 = Esci WHEN 2005 CONTINUE *> PgDn END-EVALUATE.
Permette di accedere a una porzione di un campo alfanumerico senza definire sottocampi. Sintassi: campo(posizione : lunghezza). Posizione parte da 1.
01 Frase PIC X(20) VALUE "HELLO WORLD". *> Estrazione substring DISPLAY Frase(1 : 5). *> "HELLO" DISPLAY Frase(7 : 5). *> "WORLD" *> Lunghezza opzionale: dal punto fino alla fine DISPLAY Frase(7 :). *> "WORLD " (fino alla fine) *> Modifica in-place MOVE "CIAO" TO Frase(1 : 4). *> "CIAOO WORLD" *> Posizione e lunghezza possono essere variabili 01 Pos PIC 99 VALUE 3. 01 Len PIC 99 VALUE 4. DISPLAY Frase(Pos : Len). *> 4 caratteri dalla posizione 3 *> Su campi di gruppo (trattati come alfanumerici) 01 DataGrezza PIC X(8) VALUE "20241225". DISPLAY DataGrezza(1 : 4). *> "2024" (anno) DISPLAY DataGrezza(5 : 2). *> "12" (mese) DISPLAY DataGrezza(7 : 2). *> "25" (giorno) *> Con FUNCTION LENGTH per calcoli dinamici MOVE "!" TO Frase(FUNCTION LENGTH(Frase) : 1). *> Mette "!" nell'ultima posizione
-debug in GnuCOBOL si ottiene un errore runtime. Verificare sempre i limiti quando posizione/lunghezza sono variabili.COBOL 2014 introduce la gestione dinamica della memoria, finora assente nel linguaggio. Queste feature hanno supporto limitato nei compilatori.
*> Tabella con dimensione allocata a runtime 01 TabDinamica. 02 NumElementi PIC 9(5). 02 Elemento PIC X(20) OCCURS DYNAMIC CAPACITY IN NumElementi. *> Ridimensiona a runtime ALLOCATE 100 CHARACTERS RETURNING Elemento. *> oppure ALLOCATE Elemento.
*> ALLOCATE: alloca memoria dinamica 01 Ptr USAGE POINTER. 01 Buffer PIC X(1024) BASED. *> Alloca e associa a una variabile BASED ALLOCATE Buffer RETURNING Ptr. *> Alloca N caratteri generici ALLOCATE 4096 CHARACTERS RETURNING Ptr ON EXCEPTION DISPLAY "Memoria insufficiente". *> FREE: rilascia memoria allocata FREE Ptr. *> Dopo FREE, Ptr è NULL e Buffer non è più accessibile
| Feature | OCCURS n TIMES | OCCURS ... TO ... DEPENDING ON | OCCURS DYNAMIC |
|---|---|---|---|
| Dimensione | Fissa a compile time | Variabile, con range fisso | Variabile, senza limite fisso |
| Memoria | Allocata staticamente | Allocata per il max | Allocata a runtime |
| Standard | COBOL-68+ | COBOL-85+ | COBOL 2014+ |
| Supporto GnuCOBOL | Pieno | Pieno | Parziale (3.x+) |
Da COBOL 2002/2014: direttive del preprocessore per includere/escludere codice a compile time. Sintassi: >> in colonna 7+ (free) o colonna 7 (fixed).
*> Definizione costante di compilazione >>DEFINE VERSIONE AS 2 >>DEFINE DEBUG-MODE AS 1 >>DEFINE PIATTAFORMA AS "LINUX" *> Condizionale semplice >>IF DEBUG-MODE = 1 DISPLAY "[DEBUG] Valore: " Variabile. >>END-IF *> IF / ELSE >>IF PIATTAFORMA = "LINUX" CALL "system" USING BY REFERENCE CmdLinux. >>ELSE CALL "system" USING BY REFERENCE CmdWindows. >>END-IF *> Verifica se definito >>IF VERSIONE IS DEFINED DISPLAY "Versione attiva". >>END-IF >>IF MODULO-EXTRA IS NOT DEFINED DISPLAY "Modulo extra non disponibile". >>END-IF *> Definizione da riga di comando (GnuCOBOL) cobc -x -D DEBUG-MODE=1 -D PIATTAFORMA="LINUX" prog.cob *> Attivazione/disattivazione in cascata >>DEFINE LIVELLO AS 3 >>IF LIVELLO >= 2 PERFORM LogDettagliato. >>END-IF >>IF LIVELLO >= 3 PERFORM LogVerbose. >>END-IF
| Direttiva | Effetto |
|---|---|
>>DEFINE nome AS valore | Definisce una costante di compilazione |
>>IF condizione | Inizio blocco condizionale |
>>ELSE | Ramo alternativo |
>>END-IF | Fine blocco condizionale |
>>SET nome AS valore | Ridefinisce una costante (se già definita) |
>>TURN EC-BOUND CHECKING ON | Attiva/disattiva controlli runtime specifici |
>>SOURCE FORMAT FREE/FIXED | Cambia formato sorgente |
>>DEFINE possono anche essere passate da riga di comando con -D NOME=VALORE. Utile per build differenziati (debug/produzione, piattaforme diverse).La clausola COPY include testo da un copybook (.cpy) esterno. REPLACING permette sostituzioni testuali al momento dell'inclusione, fondamentale per il riuso delle strutture dati.
*> COPY base COPY nome-copybook. COPY "path/to/copybook.cpy". *> COPY con REPLACING (pseudo-text delimiters ==...==) COPY RECDEF REPLACING ==:PREFIX:== BY ==WS-CLI== ==:SIZE:== BY ==100==. *> REPLACING multipli sullo stesso COPY COPY SQLTAB REPLACING ==:TABLE:== BY ==CLIENTI== ==:KEY:== BY ==ID-CLIENTE== ==:REC:== BY ==REC-CLI==.
*> ─── File: RECDEF.cpy ─── 01 :PREFIX:-Record. 02 :PREFIX:-ID PIC 9(5). 02 :PREFIX:-Nome PIC X(30). 02 :PREFIX:-Stato PIC X. *> ─── Nel programma: istanzia due volte ─── COPY RECDEF REPLACING ==:PREFIX:== BY ==WS-CLI==. *> Genera: 01 WS-CLI-Record. 02 WS-CLI-ID PIC 9(5). ... COPY RECDEF REPLACING ==:PREFIX:== BY ==WS-FOR==. *> Genera: 01 WS-FOR-Record. 02 WS-FOR-ID PIC 9(5). ...
*> REPLACE opera su TUTTO il sorgente (non solo COPY) REPLACE ==VECCHIO-NOME== BY ==NUOVO-NOME==. *> Da qui in poi, ogni occorrenza viene sostituita *> Disattivare REPLACE REPLACE OFF.
| Clausola | Scope | Uso tipico |
|---|---|---|
COPY ... REPLACING | Solo il testo incluso dal COPY | Parametrizzare copybook (prefissi, nomi tabella) |
REPLACE | Tutto il sorgente fino a REPLACE OFF | Refactoring, rename globale temporaneo |
:PREFIX:) nei copybook per rendere chiaro dove avvengono le sostituzioni. I copybook sono cercati in: directory corrente, COB_COPY_DIR, directory specificate con -I in cobc.Il file locking controlla l'accesso concorrente quando più programmi o thread accedono allo stesso file. Definito nella clausola SELECT e nei verbi I/O.
SELECT ClienteFile ASSIGN TO "clienti.dat" ORGANIZATION IS INDEXED ACCESS MODE IS DYNAMIC LOCK MODE IS MANUAL *> lock esplicito per record WITH LOCK ON MULTIPLE RECORDS FILE STATUS IS WS-FS.
| LOCK MODE | Comportamento | Uso tipico |
|---|---|---|
AUTOMATIC | Lock acquisito automaticamente su READ, rilasciato su READ successiva o UNLOCK | Programmi semplici con accesso sequenziale |
MANUAL | Lock acquisito solo con READ WITH LOCK, rilasciato con UNLOCK o CLOSE | Transazioni che richiedono controllo preciso |
EXCLUSIVE | L'intero file è bloccato all'OPEN; nessun altro può accedervi | Batch esclusivi, riorganizzazione file |
*> READ con lock esplicito (LOCK MODE MANUAL) READ ClienteFile WITH LOCK *> blocca il record KEY IS IDCliente INVALID KEY DISPLAY "Non trovato" END-READ. *> READ senza lock (solo lettura) READ ClienteFile WITH NO LOCK *> non blocca KEY IS IDCliente END-READ. *> UNLOCK: rilascia i lock sul file UNLOCK ClienteFile RECORDS. *> rilascia tutti i record lockati UNLOCK ClienteFile RECORD. *> rilascia solo il record corrente *> OPEN con sharing (chi altro può aprire il file) OPEN I-O ClienteFile WITH LOCK. *> lock esclusivo OPEN INPUT ClienteFile SHARING WITH ALL OTHER. *> condiviso in lettura OPEN I-O ClienteFile SHARING WITH NO OTHER. *> esclusivo OPEN I-O ClienteFile SHARING WITH READ ONLY. *> altri possono solo leggere
"68" (record locked). Gestire sempre questo caso per evitare deadlock. In GnuCOBOL il locking è basato su fcntl() (POSIX).Da COBOL 2014, con supporto in GnuCOBOL 3.x+, IBM Enterprise COBOL V6.2+ e Micro Focus.
WORKING-STORAGE SECTION. 01 Prodotto. 02 ProdID PIC 9(5) VALUE 12345. 02 ProdNome PIC X(20) VALUE "Widget". 02 ProdPrezzo PIC 9(5)V99 VALUE 49.99. 02 ProdAttivo PIC 9 VALUE 1. 01 JsonOutput PIC X(500). 01 JsonLen PIC 9(5). *> Generazione base JSON GENERATE JsonOutput FROM Prodotto COUNT IN JsonLen ON EXCEPTION DISPLAY "Errore JSON GENERATE" NOT ON EXCEPTION DISPLAY JsonOutput(1 : JsonLen) END-JSON. *> Output: {"ProdID":12345,"ProdNome":"Widget","ProdPrezzo":49.99,"ProdAttivo":1} *> Con NAME (rinomina chiavi JSON) JSON GENERATE JsonOutput FROM Prodotto COUNT IN JsonLen NAME OF ProdID IS "id" ProdNome IS "name" ProdPrezzo IS "price" ProdAttivo IS "active" END-JSON. *> Output: {"id":12345,"name":"Widget","price":49.99,"active":1} *> Con SUPPRESS (escludi campi) JSON GENERATE JsonOutput FROM Prodotto COUNT IN JsonLen SUPPRESS ProdAttivo END-JSON.
01 JsonInput PIC X(500) VALUE '{"id":99,"name":"Gadget","price":19.99}'. 01 ParsedProd. 02 ProdID PIC 9(5). 02 ProdNome PIC X(20). 02 ProdPrezzo PIC 9(5)V99. JSON PARSE JsonInput INTO ParsedProd NAME OF ProdID IS "id" ProdNome IS "name" ProdPrezzo IS "price" ON EXCEPTION DISPLAY "Errore parsing JSON" NOT ON EXCEPTION DISPLAY "ID: " ProdID DISPLAY "Nome: " ProdNome DISPLAY "Prezzo: " ProdPrezzo END-JSON.
*> Sintassi analoga a JSON 01 XmlOutput PIC X(1000). 01 XmlLen PIC 9(5). XML GENERATE XmlOutput FROM Prodotto COUNT IN XmlLen WITH ATTRIBUTES *> oppure WITH ENCODING (UTF-8, ecc.) ON EXCEPTION DISPLAY "Errore XML" END-XML. XML PARSE XmlInput PROCESSING PROCEDURE IS HandleXml END-XML. *> HandleXml riceve eventi SAX: XML-EVENT, XML-TEXT, XML-NTEXT
COBOL su mainframe IBM usa Embedded SQL per interagire con DB2. Le istruzioni SQL sono racchiuse tra EXEC SQL e END-EXEC. Il precompilatore DB2 le converte in chiamate al database prima della compilazione COBOL.
WORKING-STORAGE SECTION. *> SQLCA: area di comunicazione SQL (obbligatoria) EXEC SQL INCLUDE SQLCA END-EXEC. *> Host variables: variabili COBOL usate nelle query 01 WS-ID PIC 9(5). 01 WS-Nome PIC X(30). 01 WS-Saldo PIC S9(9)V99 COMP-3. 01 WS-Ind PIC S9(4) COMP. *> indicator variable (null check)
*> SELECT singola riga (INTO host variables) EXEC SQL SELECT NOME, SALDO INTO :WS-Nome, :WS-Saldo:WS-Ind FROM CLIENTI WHERE ID = :WS-ID END-EXEC. *> :WS-Ind = -1 se SALDO è NULL *> INSERT EXEC SQL INSERT INTO CLIENTI (ID, NOME, SALDO) VALUES (:WS-ID, :WS-Nome, :WS-Saldo) END-EXEC. *> UPDATE EXEC SQL UPDATE CLIENTI SET SALDO = :WS-Saldo WHERE ID = :WS-ID END-EXEC. *> DELETE EXEC SQL DELETE FROM CLIENTI WHERE ID = :WS-ID END-EXEC.
*> Dichiarazione cursore EXEC SQL DECLARE CUR-CLIENTI CURSOR FOR SELECT ID, NOME, SALDO FROM CLIENTI WHERE SALDO > :WS-MinSaldo ORDER BY NOME END-EXEC. *> Apertura, lettura, chiusura EXEC SQL OPEN CUR-CLIENTI END-EXEC. PERFORM UNTIL SQLCODE NOT = 0 EXEC SQL FETCH CUR-CLIENTI INTO :WS-ID, :WS-Nome, :WS-Saldo END-EXEC IF SQLCODE = 0 DISPLAY WS-ID " " WS-Nome " " WS-Saldo END-IF END-PERFORM. EXEC SQL CLOSE CUR-CLIENTI END-EXEC.
| SQLCODE | Significato |
|---|---|
0 | Successo |
+100 | Nessuna riga trovata (SELECT) o fine cursore (FETCH) |
-803 | Violazione chiave duplicata (INSERT) |
-805 | Package/plan non trovato |
-811 | SELECT INTO restituisce più di una riga |
-911 | Deadlock o timeout |
-904 | Risorsa non disponibile |
< 0 | Errore generico (consultare SQLERRMC per dettagli) |
*> Gestione errori tipica EVALUATE SQLCODE WHEN 0 CONTINUE WHEN 100 DISPLAY "Nessun dato trovato" WHEN -803 DISPLAY "Chiave duplicata" WHEN OTHER DISPLAY "Errore SQL: " SQLCODE DISPLAY "Messaggio: " SQLERRMC END-EVALUATE.
DSNHPC su z/OS) che genera COBOL puro con CALL al runtime DB2. In ambiente GnuCOBOL si può usare ESQL/OC (Open COBOL ESQL) o OCESQL per interfacciarsi con PostgreSQL/MySQL.CICS (Customer Information Control System) è il transaction monitor IBM per applicazioni online su mainframe. I programmi COBOL/CICS gestiscono transazioni interattive (schermate 3270, servizi web) tramite comandi EXEC CICS.
*> Differenze rispetto a COBOL batch: *> - NON usare ACCEPT, DISPLAY, OPEN, READ, WRITE, CLOSE *> - NON usare STOP RUN (usare EXEC CICS RETURN) *> - I/O solo tramite EXEC CICS (SEND MAP, RECEIVE MAP, READ FILE, ecc.) IDENTIFICATION DIVISION. PROGRAM-ID. CICSPGM. DATA DIVISION. WORKING-STORAGE SECTION. 01 WS-Resp PIC S9(8) COMP. 01 WS-Resp2 PIC S9(8) COMP. 01 WS-Data PIC X(100). PROCEDURE DIVISION. EXEC CICS HANDLE CONDITION ERROR(Errore-Para) END-EXEC. PERFORM Logica-Main. EXEC CICS RETURN END-EXEC. Errore-Para. EXEC CICS SEND TEXT FROM("Errore!") LENGTH(7) ERASE END-EXEC. EXEC CICS RETURN END-EXEC.
| Categoria | Comando | Descrizione |
|---|---|---|
| Terminale | SEND MAP / RECEIVE MAP | Invia/ricevi schermata BMS (3270) |
| Terminale | SEND TEXT | Invia testo libero al terminale |
| File | READ FILE / WRITE FILE | Leggi/scrivi record VSAM |
| File | REWRITE FILE / DELETE FILE | Aggiorna/cancella record |
| File | STARTBR / READNEXT / ENDBR | Browse sequenziale su file VSAM |
| Queue | WRITEQ TS / READQ TS | Temporary Storage queue (dati di sessione) |
| Queue | WRITEQ TD / READQ TD | Transient Data queue (log, trigger) |
| Programma | LINK / XCTL | Chiama sottoprogramma / trasferimento controllo |
| Programma | RETURN | Ritorna al CICS o al chiamante |
| Sync | SYNCPOINT | Commit delle modifiche |
| Sync | SYNCPOINT ROLLBACK | Rollback delle modifiche |
EXEC CICS READ FILE('CUSTFILE') INTO(WS-Data) RIDFLD(WS-Key) LENGTH(WS-Len) RESP(WS-Resp) RESP2(WS-Resp2) END-EXEC. EVALUATE WS-Resp WHEN DFHRESP(NORMAL) PERFORM Processa WHEN DFHRESP(NOTFND) DISPLAY "Non trovato" WHEN DFHRESP(DISABLED) DISPLAY "File disabilitato" WHEN OTHER DISPLAY "Errore CICS RESP=" WS-Resp END-EVALUATE.
DFHECP1$) traduce i comandi EXEC CICS in CALL al runtime.Su mainframe IBM (z/OS), i programmi COBOL batch vengono eseguiti tramite JCL (Job Control Language). Il JCL definisce l'ambiente di esecuzione: file fisici, librerie, parametri e risorse.
//MYJOB JOB (ACCT),'NOME',CLASS=A,MSGCLASS=X //* //STEP1 EXEC PGM=MIOPROG //STEPLIB DD DSN=MY.LOAD.LIB,DISP=SHR //* // Associazione file logici COBOL → dataset fisici z/OS //CLIENTI DD DSN=PROD.CLIENTI.VSAM,DISP=SHR //REPORT DD DSN=PROD.REPORT.OUTPUT, // DISP=(NEW,CATLG,DELETE), // SPACE=(CYL,(5,2)), // DCB=(RECFM=FB,LRECL=80,BLKSIZE=0) //SYSOUT DD SYSOUT=* //SYSPRINT DD SYSOUT=*
| COBOL (SELECT) | JCL (DD) | Collegamento |
|---|---|---|
SELECT ClienteFile ASSIGN TO CLIENTI | //CLIENTI DD DSN=... | Il nome dopo ASSIGN TO corrisponde al DD name nel JCL |
SELECT ReportFile ASSIGN TO REPORT | //REPORT DD DSN=... | Idem |
DISPLAY ... UPON SYSOUT | //SYSOUT DD SYSOUT=* | Output standard (console/spool) |
//COMPILE EXEC PGM=IGYCRCTL,PARM='RENT,OPT(2)' //SYSIN DD DSN=MY.SOURCE.LIB(MIOPROG),DISP=SHR //SYSLIB DD DSN=MY.COPYBOOK.LIB,DISP=SHR //SYSLIN DD DSN=&&OBJ,DISP=(NEW,PASS),SPACE=(CYL,1) //SYSPRINT DD SYSOUT=* //* //LKED EXEC PGM=IEWL,PARM='RENT,LIST,MAP' //SYSLIN DD DSN=&&OBJ,DISP=(OLD,DELETE) //SYSLMOD DD DSN=MY.LOAD.LIB(MIOPROG),DISP=SHR //SYSPRINT DD SYSOUT=* //* //RUN EXEC PGM=MIOPROG //STEPLIB DD DSN=MY.LOAD.LIB,DISP=SHR
*> Nel programma COBOL: imposta il codice di ritorno MOVE 0 TO RETURN-CODE. *> successo MOVE 4 TO RETURN-CODE. *> warning MOVE 8 TO RETURN-CODE. *> errore MOVE 16 TO RETURN-CODE. *> errore grave
// Nel JCL: condiziona i passi successivi //STEP2 EXEC PGM=PROG2,COND=(4,LT,STEP1) //* Esegue STEP2 solo se RETURN-CODE di STEP1 >= 4 //* // Con IF/THEN/ELSE (JCL moderno): // IF (STEP1.RC = 0) THEN //STEP2 EXEC PGM=PROG2 // ELSE //STEPERR EXEC PGM=ERRPGM // ENDIF
*> 'D' in colonna 7 = riga di debug (compilata solo con -fdebugging-line) * Codice normale: MOVE 42 TO Valore. D DISPLAY "DEBUG: Valore = " Valore. *> Attivazione: cobc -x -fdebugging-line prog.cob *> Senza il flag, le righe D sono ignorate dal compilatore.
| Flag | Controllo |
|---|---|
-debug | Abilita tutti i controlli runtime (bounds, subscript, overflow) |
-g | Genera simboli di debug per gdb/lldb |
-ftrace | Traccia l'esecuzione di ogni statement (molto verboso) |
-ftraceall | Traccia tutto incluse le sezioni DECLARATIVES |
-fsource-location | Mostra file e riga nei messaggi di errore runtime |
-fstack-check | Controlla overflow dello stack |
# Compilazione per debugging completo cobc -x -debug -g -fsource-location -Wall prog.cob # Esecuzione con tracing a runtime export COB_SET_TRACE=Y ./prog # Stampa ogni statement eseguito: Source: 'prog.cob', Line: 42, ... # Redirect trace su file export COB_TRACE_FILE=debug.log ./prog # Debug con gdb cobc -x -g prog.cob gdb ./prog # In gdb: break cob_stop_run per fermarsi prima dell'uscita # In gdb: print b_42 per vedere variabile dichiarata alla riga 42
*> Richiede SOURCE-COMPUTER con WITH DEBUGGING MODE ENVIRONMENT DIVISION. CONFIGURATION SECTION. SOURCE-COMPUTER. X86 WITH DEBUGGING MODE. PROCEDURE DIVISION. DECLARATIVES. Debug-Handler SECTION. USE FOR DEBUGGING ON CalcolaIVA. Debug-Para. DISPLAY "Entrato in CalcolaIVA" DISPLAY "DEBUG-LINE: " DEBUG-LINE DISPLAY "DEBUG-NAME: " DEBUG-NAME. END DECLARATIVES. *> DEBUG-ITEM contiene: *> DEBUG-LINE - numero riga sorgente *> DEBUG-NAME - nome del paragrafo/variabile monitorata *> DEBUG-CONTENTS - contenuto (valore precedente, se variabile)
*> Pattern: trace manuale con timestamp 01 WS-Debug-Ts PIC X(21). MOVE FUNCTION CURRENT-DATE TO WS-Debug-Ts. DISPLAY "[" WS-Debug-Ts "] CalcolaIVA: Imp=" Imponibile " IVA=" TotaleIVA. *> Pattern: dump di un record DISPLAY "=== DUMP Cliente ===". DISPLAY " ID: [" IDCliente "]". DISPLAY " Nome: [" NomeCliente "]". DISPLAY " HEX: " FUNCTION ORD(IDCliente(1:1)). *> Pattern: validazione invarianti IF Totale < 0 DISPLAY "ASSERT FAIL: Totale negativo = " Totale UPON STDERR STOP RUN END-IF.
# 1. Compilare con simboli di debug cobc -x -g -debug -fsource-location prog.cob # 2. Lanciare gdb gdb ./prog # 3. Comandi gdb utili per COBOL
| Comando gdb | Effetto |
|---|---|
break cob_stop_run | Breakpoint prima dell'uscita dal programma |
break prog.c:42 | Breakpoint alla riga 42 del C generato (corrisponde a una riga COBOL) |
print b_WS_Conta | Stampa la variabile COBOL WS-Conta (prefisso b_, trattini → underscore) |
print b_1 | Stampa la variabile COBOL definita a livello 01 (se non ha nome: usa il numero di riga) |
display b_WS_FS | Mostra automaticamente WS-FS dopo ogni step |
info locals | Elenca tutte le variabili locali (include le variabili COBOL convertite) |
next | Esegue la prossima riga C (può corrispondere a più statement COBOL) |
step | Entra nelle funzioni chiamate (es. CALL) |
continue | Continua fino al prossimo breakpoint |
backtrace | Mostra lo stack di chiamate (utile dopo un crash) |
x/20cb b_RecordA | Dump esadecimale di 20 byte del record (utile per ispezionare campi packed) |
# Sessione di esempio $ gdb ./prog (gdb) break cob_stop_run (gdb) run (gdb) print b_WS_Totale $1 = "00012345" (gdb) print b_WS_FS $2 = "00" (gdb) x/10cb b_WS_Record 0x...: 0x4d 0x61 0x72 0x69 0x6f 0x20 0x20 0x20 ... (gdb) backtrace #0 cob_stop_run (status=0) at libcob/common.c:... #1 prog_ () at prog.c:142
b_ e trattini sostituiti da underscore. Es: WS-Conta → b_WS_Conta, IDCliente → b_IDCliente. Per trovare il nome esatto: cobc -x -g prog.cob poi grep "WS.Conta" prog.c.