Instruction RPG full free · IBM i (AS/400) · Procédures, sous-programmes et erreurs
BEGSR
Sous-programme interne
Délimite un sous-programme interne, un bloc de code appelé par EXSR depuis le même programme ou la même procédure et qui peut se quitter par LEAVESR.
Syntaxe
BEGSR nom-sous-programme;
...
LEAVESR;
ENDSR;
EXSR nom-sous-programme;
nom-sous-programme- Le nom du sous-programme.
BEGSRle définit,EXSRl'appelle. LEAVESR- Quitte le sous-programme tout de suite et reprend après le
EXSRqui l'a appelé. ENDSR- Termine le sous-programme. L'exécution reprend après le
EXSR. - Effet
- Aucun indicateur ni fonction d'état n'est positionné. Après
ENDSRouLEAVESR, l'exécution reprend à l'instruction qui suitEXSR. Toutes les zones modifiées dans le sous-programme restent modifiées.
À quoi ça sert
Un sous-programme regroupe un traitement répété ou une étape qu'on veut nommer : la boucle de lecture reste lisible et le détail est ailleurs. C'est l'outil historique du RPG (BEGSR et ENDSR existent aussi en colonnes). Dans l'exemple, traiter est appelé pour chaque client, et leavesr évite d'imbriquer le reste du traitement dans un else quand le solde n'est pas positif.
Pour du code neuf, une procédure est souvent préférable : elle a des paramètres et ses propres variables. Un sous-programme n'a ni l'un ni l'autre : il travaille directement sur les zones du programme ou de la procédure qui le contient. Déclarer une variable à l'intérieur (dcl-s après begsr) est refusé à la compilation (RNF0724).
Exemple 1 : Traiter les clients avec EXSR et LEAVESR
**free
// BEGSR : un sous-programme interne, appele par EXSR, avec sortie anticipee LEAVESR.
ctl-opt dftactgrp(*no) actgrp(*new) alwnull(*usrctl);
dcl-f client keyed extdesc('JOBIRPG/CLIENT') extfile(*extdesc);
dcl-s nbvilles int(10);
dcl-s total packed(11:2);
dcl-s libelle varchar(40);
setll *loval client;
read client;
dow not %eof(client);
exsr traiter;
read client;
enddo;
snd-msg 'Clients Montpellier : ' + %char(nbvilles);
snd-msg 'Solde cumule : ' + %char(total);
*inlr = *on;
begsr traiter;
libelle = %trim(nom) + ' (' + %trim(ville) + ')';
if solde <= 0;
snd-msg 'Ignore : ' + libelle;
leavesr;
endif;
total += solde;
if %trim(ville) = 'Montpellier';
nbvilles += 1;
endif;
snd-msg 'Retenu : ' + libelle + ' ' + %char(solde);
endsr;
Résultat réel, compilé et exécuté sur IBM i 7.5 :
Retenu : Dupont SA (Montpellier) 1250.50
Ignore : Martin et fils (Lyon)
Ignore : Leroy SARL (Montpellier)
Retenu : Bernard Transports (Brest) 98000.00
Retenu : Petit Atelier (Lyon) 45.10
Clients Montpellier : 1
Solde cumule : 99295.60
Chaque client lu appelle traiter. Les soldes négatifs ou nuls (Martin et fils, Leroy SARL) quittent le sous-programme par leavesr et ne sont pas cumulés. Le sous-programme modifie directement total et nbvilles, déclarées dans le programme.
Exemple 2 : Un sous-programme qui écrase l'indice de l'appelant
**free
// BEGSR : un sous-programme partage les variables du programme appelant.
ctl-opt dftactgrp(*no) actgrp(*new);
dcl-s i int(10);
dcl-s j int(10);
dcl-s n int(10);
dcl-s clients char(10) dim(3);
clients(1) = 'Dupont';
clients(2) = 'Martin';
clients(3) = 'Leroy';
// Boucle externe sur 3 clients : le sous-programme reutilise la meme variable I.
for i = 1 to 3;
snd-msg 'Client ' + %char(i) + ' : ' + %trim(clients(i));
exsr compter_lettres;
endfor;
snd-msg 'I vaut maintenant ' + %char(i);
// Correction : un indice different dans le sous-programme.
for i = 1 to 3;
snd-msg 'Client ' + %char(i) + ' : ' + %trim(clients(i));
exsr compter_lettres_j;
endfor;
*inlr = *on;
begsr compter_lettres;
n = 0;
for i = 1 to 2;
n += 1;
endfor;
endsr;
begsr compter_lettres_j;
n = 0;
for j = 1 to 2;
n += 1;
endfor;
endsr;
Résultat réel, compilé et exécuté sur IBM i 7.5 :
Client 1 : Dupont
I vaut maintenant 4
Client 1 : Dupont
Client 2 : Martin
Client 3 : Leroy
La première boucle devrait afficher trois clients. Le sous-programme compter_lettres réutilise la variable I du programme : en sortant de sa propre boucle, I vaut 3, la boucle externe l'incrémente à 4 et s'arrête après un seul client. Avec un indice différent (J), les trois clients sont affichés.
Le piège
Un sous-programme partage toutes les variables de son appelant. Il n'y a pas de variable locale : si le sous-programme et la boucle qui l'appelle utilisent le même indice, le résultat est faux sans aucune erreur. Dans le deuxième exemple, une boucle de trois tours s'arrête au premier et I vaut 4 à la sortie. Réservez des noms propres aux sous-programmes (j, idxsr…), ou utilisez une procédure, dont les variables sont vraiment locales.