đŠ PL/I (IBM) â Guide complet (AnnĂ©es 70/80 â toujours vivant)
Syntaxe, types, structures, exceptions (ON), fichiers, perf, mainframe, interop COBOL/ASM/C, modernisation.
Pourquoi PL/I ?
Langage âgeneral purposeâ IBM : science + business, riche, et trĂšs productif sur donnĂ©es.
HistoryIBMEnterpriseStructure dâun programme
PROC, DCL, BEGIN/END, statements, options compiler, style modulaire.
PROCDCLBEGIN/ENDTypes & déclarations
FIXED/BIN/DEC, FLOAT, CHAR/VARYING, BIT, structure, arrays, pointers.
FIXEDVARYINGSTRUCTContrĂŽle & boucles
IF/THEN/ELSE, SELECT, DO loops, iteration, LEAVE/ITERATE, GOTO (rare).
DOSELECTLEAVEStrings & manipulation
CHAR/VARYING, substr, index, translate, concat, formatting, parsing.
CHARSUBSTRINDEXI/O fichiers
OPEN/CLOSE/READ/WRITE, GET/PUT, record vs stream, formats, erreurs.
I/OGET/PUTFilesGestion dâerreurs (ON)
ON condition, SIGNAL, RESIGNAL, built-in conditions, âfail fastâ contrĂŽlĂ©.
ONSIGNALDiagnosticsModularité & appels
PROC options, paramĂštres, ENTRY, external, interop (COBOL/C/ASM).
ENTRYExternalInteropMémoire, pointeurs, ALLOCATE
BASED, POINTER, ALLOCATE/FREE, lifetimes, structures dynamiques.
POINTERBASEDALLOCATEPerformance & tuning
Design des données, conversions, I/O, options compiler, hot loops.
TuningCompilerI/OMainframe: batch & ops
Retour codes, logs, rerun safe, JCL integration, datasets, production.
z/OSBatchJCL0.x Carte mentale PL/I
Architecture : PROC, data model, I/O, exceptions ON, interop, migration.
MapBig PictureCheat-sheet
Rappels : DCL, PROC, DO, SELECT, ON, GET/PUT, VARYING, ALLOCATE.
Quick RefSnippetsPL/I en une phrase
PL/I (IBM) vise Ă ĂȘtre un langage âgĂ©nĂ©ralisteâ pour les environnements enterprise : fort sur la manipulation de donnĂ©es, I/O, gestion dâerreurs (ON), structures, et intĂ©gration mainframe.
Carte mentale
Program (PL/I)
ââ PROC (entry point)
ââ Declarations (DCL)
â ââ numeric: FIXED BIN / FIXED DEC / FLOAT
â ââ strings: CHAR / VARYING / BIT
â ââ struct: 1/2/3 levels (LIKE, BASED)
â ââ arrays
ââ Control
â ââ IF/THEN/ELSE
â ââ SELECT
â ââ DO loops (LEAVE/ITERATE)
ââ I/O
â ââ OPEN/CLOSE
â ââ GET/PUT (record/stream)
â ââ formats, errors
ââ Errors
â ââ ON conditions
â ââ SIGNAL/RESIGNAL
ââ Ops
ââ return codes, logs
ââ batch rerun safe
Forces PL/I (pratiques)
| Zone | Pourquoi câest fort | Usage |
|---|---|---|
| Strings | Opérations riches + VARYING | Parsing, formats, protocoles legacy |
| Data structs | Structures proches ârecordsâ | Interfaces, layouts fichiers |
| Exceptions | ON conditions | Erreurs contrÎlées, robustesse |
| I/O | GET/PUT + formats | Batch, reports, fichiers |
Runtime & Ops (batch)
- Le pilotage prod se fait souvent via RC, logs, et datasets.
- Rerun safe : outputs temporaires, checkpoints, invariants de totals.
- Perf : I/O patterns + conversions (DEC/BIN/CHAR), compiler options.
Batch flow:
extract â transform â report/load
Ops:
RC + totals + diagnostics
Ce quâil faut retenir
- PL/I a été conçu pour couvrir des besoins variés (scientifique + business).
- TrĂšs orientĂ© âmanipulation de donnĂ©esâ : strings, formats, structures.
- Riche en contrĂŽle dâerreurs via ON conditions.
- Fortement intégré aux environnements IBM (notamment z/OS).
Quand on le rencontre encore
| Contexte | Exemples |
|---|---|
| Batch âcoreâ | Compta, reporting, consolidation, transformations |
| Tools internes | Utilitaires, parsing, contrÎles de qualité data |
| Interop | Modules appelés depuis COBOL/ASM/C |
Programme minimal
HELLO: PROC OPTIONS(MAIN);
DCL msg CHAR(26) VARYING;
msg = 'HELLO FROM PL/I';
PUT SKIP LIST(msg);
END HELLO;
Lecture
- PROC : point dâentrĂ©e (ou routine).
- DCL : déclarations (types, structures, fichiers).
- BEGIN/END : bloc ; style structuré.
- PUT : sortie (ici console/stream).
DCL : déclarer clairement
DCL i FIXED BIN(31);
DCL amount FIXED DEC(15,2);
DCL code CHAR(3);
DCL name CHAR(30) VARYING;
DCL flags BIT(8);
Les conversions implicites existent, mais en production, il vaut mieux les contrĂŽler.
Style modulaire âbatchâ
MAIN: PROC OPTIONS(MAIN);
CALL init();
DO WHILE( more_input() );
CALL process_one();
END;
CALL finalize();
END MAIN;
Objectif : lisibilité + testabilité + rerun safe.
Compile/build (concepts)
- Options compiler influencent perf, diagnostics, runtime checks.
- En legacy, conventions site : naming, link-edit, load libs.
- RĂšgle : activer les diagnostics en dev/QA, puis durcir en prod.
Think in environments:
DEV: max diagnostics
QA: strict + test harness
PROD: stable options + monitoring
Fixed binary / fixed decimal
DCL cnt FIXED BIN(31);
DCL id FIXED BIN(31) INIT(0);
DCL price FIXED DEC(15,2);
DCL tax FIXED DEC(7,2);
price = 12345.67;
tax = price * 0.20;
Float (scientifique)
DCL x FLOAT(53);
x = 3.1415926535;
CHAR vs VARYING
DCL a CHAR(10);
DCL b CHAR(30) VARYING;
a = 'ABC';
b = 'HELLO';
b = b || ' WORLD';
BIT strings
DCL mask BIT(8);
mask = '10101010'B;
Les strings sont une force de PL/I : parsing, formats, manipulation.
Structures (records)
DCL 1 customer,
2 cust_id FIXED BIN(31),
2 cust_name CHAR(30) VARYING,
2 address,
3 street CHAR(40) VARYING,
3 city CHAR(20) VARYING,
3 zip CHAR(10);
customer.cust_id = 42;
customer.address.city = 'LYON';
Arrays
DCL i FIXED BIN(31);
DCL items(10) FIXED DEC(9,2);
DO i = 1 TO 10;
items(i) = i * 10.00;
END;
Les arrays + DO loops donnent un style âstructurĂ©â et lisible.
IF / THEN / ELSE
IF price > 0 THEN
total = total + price;
ELSE
rc = 12;
SELECT (case)
SELECT(action);
WHEN('C') CALL create();
WHEN('U') CALL update();
WHEN('D') CALL delete();
OTHERWISE rc = 16;
END;
DO loops
DO i = 1 TO 10;
sum = sum + items(i);
END;
DO WHILE(has_more());
CALL process_one();
END;
LEAVE / ITERATE
DO i = 1 TO 100;
IF i = 10 THEN LEAVE;
IF MOD(i,2)=0 THEN ITERATE;
CALL work(i);
END;
Anti-patterns
| Anti-pattern | Pourquoi | Alternative |
|---|---|---|
| Conversions implicites non maßtrisées | Bugs data silencieux | Cast/format explicite |
| Un seul gros bloc | Debug difficile | PROC modulaires |
| GOTO partout | Flow opaque | DO/SELECT + helpers |
Concatenation & VARYING
DCL s CHAR(80) VARYING;
s = 'A';
s = s || '-' || 'B';
PUT SKIP LIST(s);
SUBSTR / INDEX
DCL line CHAR(200) VARYING;
DCL pos FIXED BIN(31);
pos = INDEX(line, ':');
IF pos > 0 THEN DO;
key = SUBSTR(line, 1, pos-1);
val = SUBSTR(line, pos+1);
END;
Parsing robuste : checklist
- Valider la présence des séparateurs (INDEX).
- Trimmer / normaliser.
- Limiter les longueurs (avoid overflow).
- Tracer les lignes invalides dans un fichier ârejectâ.
IF pos = 0 THEN DO;
reject_count = reject_count + 1;
CALL write_reject(line);
ITERATE;
END;
Formatting (idée)
DCL amount FIXED DEC(15,2);
DCL out CHAR(40) VARYING;
out = 'AMOUNT=' || amount;
PUT SKIP LIST(out);
En production, standardiser les formats (longueur, séparateurs, encodage).
Déclarer un fichier
DCL in FILE;
DCL out FILE;
Les détails exacts (DD names, attributes) dépendent des conventions runtime/site.
Open / get / put
OPEN FILE(in) INPUT;
OPEN FILE(out) OUTPUT;
GET FILE(in) EDIT(line) (A);
PUT FILE(out) LIST(line);
CLOSE FILE(in);
CLOSE FILE(out);
Pattern batch : loop + counters
DCL cnt FIXED BIN(31) INIT(0);
DO WHILE( has_more_input() );
CALL read_one(line);
cnt = cnt + 1;
CALL process_one(line);
CALL write_one(line);
END;
PUT SKIP LIST('COUNT=', cnt);
Gestion erreurs I/O
- Capturer exceptions via ON (condition) autour des GET/PUT.
- Tracer le record en erreur + position + totals.
- Ăcrire un âreject fileâ plutĂŽt que crasher sans preuve.
ON ENDFILE(in) eof = 1;
ON ERROR CALL handle_io_error();
Contracts fichiers : le vrai sujet
| Contrat | Pourquoi | Action |
|---|---|---|
| Record layout | Ăvite corruption silencieuse | Doc + tests |
| Encoding | Charset issues | Standardize |
| Control totals | Detect regressions | Count/sum checks |
ON condition (concept)
ON ERROR DO;
rc = 12;
PUT SKIP LIST('ERROR DETECTED');
END;
ON ENDFILE (EOF)
ON ENDFILE(in) eof = 1;
DO WHILE(eof = 0);
GET FILE(in) LIST(line);
CALL process_one(line);
END;
SIGNAL / RESIGNAL (concept)
SIGNAL déclenche une condition ; RESIGNAL propage aprÚs traitement local.
ON ERROR DO;
CALL log_context();
RESIGNAL;
END;
Patterns de robustesse
| Pattern | But | Action |
|---|---|---|
| Fail fast contrÎlé | Stop avec preuve | Log + totals + RC |
| Reject file | Continuer malgré records bad | Write bad lines |
| Retry IO/locks | Résilience | Backoff + limit |
Procédure avec paramÚtres
calc_tax: PROC(amount, rate) RETURNS(FIXED DEC(15,2));
DCL amount FIXED DEC(15,2);
DCL rate FIXED DEC(7,4);
RETURN amount * rate;
END;
Interop (concept)
- PL/I peut cohabiter avec COBOL/C/ASM dans des load libs.
- Le vrai sujet : calling convention + layout structures + encoding.
- Standardiser les âinterface copybooks/struct defsâ.
Interop checklist:
params order/types
alignment/packing
strings encoding
error codes
ALLOCATE / FREE (concept)
DCL p POINTER;
DCL 1 node BASED(p),
2 key FIXED BIN(31),
2 next POINTER;
ALLOCATE node;
node.key = 123;
node.next = NULL();
FREE node;
Based structures : puissant, mais exige discipline (lifetime, free).
RÚgles de sécurité mémoire
| Risque | Cause | Prévention |
|---|---|---|
| Leak | FREE oublié | Ownership clair |
| Use-after-free | Pointeur gardé | Nullify pointers |
| Corruption | Layout mismatch | Struct contracts |
Leviers principaux
- Constructions data : éviter casts en boucle.
- I/O : réduire le nombre de passes fichiers, bufferiser.
- Strings : attention aux concat répétées sur gros volumes.
- Compiler : options de debug vs perf (selon environnements).
Rule of thumb:
avoid heavy conversions inside hot loops
move formatting to the edges (I/O)
SymptĂŽme â action
| SymptĂŽme | Cause probable | Action |
|---|---|---|
| Batch plus lent | I/O excessif | Single pass, fewer writes |
| CPU high | Conversions + strings | Precompute, reduce concat |
| Errors sporadiques | ON/conditions mal cadrées | Centralize handlers |
Checklist prod
- RC cohérents (0/4/8/12/16 selon conventions).
- Logs utiles : count, totals, time markers.
- Outputs temporaires + switch final pour rerun safe.
- Tests NRT sur jeux représentatifs.
Audit items:
job/step
input/output datasets
record counts
totals
return code
Batch pattern (concept)
extract â validate â transform â output
+ totals
+ rejects
+ RC
Approches
| Approche | Avantage | Risque |
|---|---|---|
| Encapsulate | Low risk, quick wins | Legacy stays |
| Strangler | Remplacement progressif | Complex routing |
| Refactor inside | Qualité/maint | Needs strong tests |
| Big bang | Clean slate | High failure rate |
Wrapper (concept)
API/service
â adapt request
â call PL/I module
â adapt response
Contract-first
Define:
schema fields/types
error codes
idempotency
versioning
Safe refactor
- Golden outputs + totals
- Isoler I/O et formats
- Modulariser PROC
- Centraliser ON handlers
- Shadow runs + compare
Shadow run:
legacy output A
new output B
compare A vs B
switch only when identical
Migration data : piĂšges
- Conversions DEC/BIN/CHAR (rounding, formats).
- Encodage (EBCDIC/ASCII selon environnements).
- Contrats fichiers : longueur fixe, records, separators.
- Anomalies historiques : valeurs âimpossiblesâ mais prĂ©sentes en prod.
PL/I Big Picture
1) PROC + DCL (types/structs)
2) Control (IF/SELECT/DO)
3) Data work (strings, arrays, records)
4) I/O (GET/PUT + formats)
5) Errors (ON + SIGNAL/RESIGNAL)
6) Ops (RC, totals, rerun)
7) Modernization (wrappers, strangler, safe refactor)
Core syntax
PROC OPTIONS(MAIN);
DCL x FIXED BIN(31);
DCL y FIXED DEC(15,2);
DCL s CHAR(80) VARYING;
IF cond THEN ... ELSE ...
SELECT(expr); WHEN(... ) ... OTHERWISE ... END;
DO i = 1 TO n; ... END;
DO WHILE(cond); ... END;
ON ERROR DO; ... END;
ON ENDFILE(file) eof = 1;
OPEN FILE(f) INPUT/OUTPUT;
GET FILE(f) LIST(x);
PUT FILE(f) LIST(x);
CLOSE FILE(f);
Template program
MAIN: PROC OPTIONS(MAIN);
DCL rc FIXED BIN(31) INIT(0);
DCL eof FIXED BIN(31) INIT(0);
DCL line CHAR(200) VARYING;
ON ERROR DO;
rc = 12;
PUT SKIP LIST('ERROR');
END;
CALL init();
DO WHILE(eof = 0);
/* read_one should set eof=1 at end */
CALL read_one(line, eof);
IF eof = 0 THEN DO;
CALL process_one(line, rc);
IF rc ^= 0 THEN LEAVE;
END;
END;
CALL finalize(rc);
END MAIN;
