Visita il nuovo sito https://www.markonetools.it/liberiamo-lrpg/
Dalla release IBM i 5.1 è disponibile il formato libero per scrivere programmi RPG IV.
Ad ogni release il formato libero è sempre stato arricchito fino a giungere nella versione IBM i 7.2 TR3 e 7.1 TR11 (nov-2015) a coprire tutti i tipi di specifiche e consentire l'uso del formato "totalmente libero".
Nella versione 7.1 TR7 (nov-2013) era stato introdotto il formato libero per le specifiche di controllo e definizione.
Il formato libero è il FUTURO dell'RPG.
Scrivere codice in formato libero - dopo qualche tempo di pratica - è sicuramente più veloce, più chiaro, più moderno!
/free
[...codice...]
/end-free
op-code(ext) factor1 factor2 result;
;
(punto e virgola). Si può scrivere un'istruzione su più righe senza nessun carattere di continuazione, perché la fine dell'istruzione è determinato dalla presenza del ;exec sql
e terminare anch'esse sempre con un ;
ctl-opt
dcl-f
dcl-pi, dcl-pr ... end-pr
dcl-parm
(opzionale; serve solo se il nome campo coincide con il nome di un codice operativo)dcl-c
dcl-s
dcl-ds ... end-ds
dcl-subf
(opzionale; serve solo se il nome campo coincide con il nome di un codice operativo)dcl-proc ... end-proc
ctl-opt;
ext
deve precedere la keyword inz
.disk usage(*input)
.*input:*output
: lettura e scrittura ma non aggiornamento *delete
: lettura e cancellazione*n
dove invece nel formato fisso si poteva semplicemente lasciare vuotodcl-c LenQta 13;
dcl-c DecQta 3;
dcl-s QtaOrdine packed(LenQta:DecQta);
dcl-ds MiaStruttura extname('NOMEDS') end-ds;
dcl-s TotQta like(QtaOrdine:+2);
dcl-pr qcmdexc extpgm;
d qcmdexc pr extpgm('QCMDEXC')
dcl-s TotImporto
/IF DEFINED(bignumber)
packed(17:2)
/ELSE
packed(13:2)
/ENDIF;
char
, varchar
ucs2
, varucs2
graph
, vargraph
ind
packed
zoned
bindec
int
uns
float
date
time
timestamp
pointer
pointer(*proc)
object
Con i tipi dati date o time è possibile specificare tra parentesi il formato che nel formato fisso viene specificato tramite le keyword datfmt/timfmt. P.es. date(*MDY-)
.
Nelle specifiche a formato fisso si definiva una variabile di tipo oggetto con la keyword CLASS, invece nel formato libero si usa direttamente il tipo dati OBJECT. P.es.
D obj S O CLASS(*JAVA:'MyClass')
equivale a
DCL-S obj OBJECT(*JAVA:'MyClass');
**FREE
oppure **free
a partire dalla prima colonnaAlcuni esempi di espressioni comparate con i codici operativi a formato fisso:
FIELD1 ADD FIELD2 FIELDR --> FIELDR = FIELD1 + FIELD2;
FIELD1 MULT FIELD2 FIELDR --> FIELDR = FIELD1 * FIELD2;
FIELD1 SUB FIELD2 FIELDR --> FIELDR = FIELD1 - FIELD2;
Z-ADD FIELD2 FIELDR --> FIELDR = FIELD2;
Z-SUB FIELD2 FIELDR --> FIELDR = -(FIELD2);
FIELD1 DIV FIELD2 FIELDR --> FIELDR = FIELD1/FIELD2
(or bif %div
)MVR FIELD3 --> %rem(FIELD1:FIELD2);
IMPORTANTE: le espressioni non troncano il risultato se il campo non è sufficientemente grande per contenerlo; bensì si riceve l'errore RNQ0103.
Nelle specifiche di definizione dei file (dcl-f) alcune keyword vengono assunte di default anche in relazione al tipo di file.
DISK
*INPUT
, per i tipi file PRINTER è *OUTPUT
In free non esiste il codice operativo MOVE. Si può usare EVALR. Però bisogna porre attenzione che sovrascrive sempre il contenuto della variabile di destinazione.
From5 = 'ABCDE';
To10 = 'XXXXXXXXXX';
Evalr
To10 = From5; //To10 will contain ' ABCDE’
To10 = From5; // To10 contains 'ABCDE '
To10 = *all'X';
From5 = *all'A';
Evalr %subst(TO10:6) = From5; //’XXXXXAAAAA’
%subst(To10:1:5) = From5; //’AAAAAXXXXX’
To5 = *all'X';
From10 = 'ABCDEFGHIJ';
To5 = From10; // to5 will be ‘ABCDE’
Evalr To5 = From10; // to5 will be ‘FGHIJ’
MyNbr = 12345.67;
To10 = *all'x';
//to10 contains ' 1234567‘
Evalr to10 = %editc(mynbr:'X');
//to10 contains ‘0001234567‘
Evalr to10 = '0000000000' + %trim(%editc(myNbr:'X'));
//to10 contains ‘0012345,67‘
Evalr to10 = '0000000000' + %trim(%editc(myNbr:‘3'));
con aggiunta di carattere di riempimento:
MyNbr1 = 1234567.89;
// ‘$1234567,8’
to10 = %editc(myNbr1:'3':'$');
// ‘01234567,8’
to10 = %editc(myNbr1:'3':'0');
MyNbr= 123.89;
// ‘**123,89’
to10 = %editc(myNbr:'3':*astfill);
MyNbr = 12345.67;
// a destra: MyNbr2V0 = 67. !!! Non funziona con i negativi
MyNbr2V0 = %int(%subst(%editc(MyNbr:'X'):6:2));
MyNbr = -12345.67;
// a destra:MyNbr2V0 = -67
MyNbr2v0 = %rem(%int(MyNbr*%int(10**%decPos(MyNbr))):100);
// a sinistra: MyNbr2V0 = -12
MyNbr2V0 = %int(%subst(%editc(MyNbr:'L'):1:2));//12
EvalR Sign1 = %editc(MyNbr:'L'); // ‘-’
If Sign1='-';
MyNbr2V0 *= -1;
Endif;
Non esiste l'equivalente in formato libero del codice operativo MOVEA; è necessario modificare la definizione dell'array affinché esista una DS che abbia come sottocampo l'array. A questo punto dove nel formato fisso si usa la variabile Array con il codice operativo MOVEA, invece nel formato libero si usa la DS con il codice operativo EVAL.
Per es.
dcl-ds dsArray;
Array char(2) dim(10);
end-ds;
dcl-s tmp char(20);
dcl-s i uns(3);
// versione in formato fisso
c 1 do 10 i
c eval Array(i) = %char(i)
c enddo
c movea Array tmp
c movea(p) 'AaBbCcDdEeFf'Array
// versione in formato libero
for i = 1 to %elem(Array);
Array(i) = %char(i);
endfor;
tmp = dsArray;
dsArray = 'AaBbCcDdEeFf';
*inlr = *on;
Un'altra alternativa è l'utilizzo della BIF %subarr
(disponibile da V5R3). P.es.
%Subarr(Array:3:2) = 'AaBb';
L'istruzione DO *HIVAL non ha una corrispondenza esatta nel formato libero.
Si può scrivere un costrutto do while con un condizione sempre vera.
dcl-s ForEverTrue inz('1') ind;
setll ...;
dow ForEverTrue;
read/reade...;
if %eof;
leave;
endif;
enddo;
Invece di definire le chiavi composte usando il codice operativo KLIST si può definire una ds qualificata con i campi chiave e poi usarla con la funzione %kds.
Ipotizzando che il file XPROJAC1 abbia i campi chiave PROJNO, ACTNO, ACSTDATE.
Definisco la ds
dcl-ds KeyTest likerec(PROJACT:*key);
Valorizzo i campi chiave
KeyTest.PROJNO = 'AD3110';
KeyTest.ACTNO = 10;
KeyTest.ACSTDATE = '1982-01-01';
Leggo il file
chain %kds(KeyTest) XPROJAC1;
Tra l'altro la funzione %kds ha un parametro opzionale che consente di definire quanti campi chiave si desidera utilizzare con un notevole risparmio di definizioni di KLIST. P.es.
setll %kds(KeyTest) XPROJAC1;
do....;
reade %kds(KeyTest:1) XPROJAC1;
...
enddo;
Si può usare anche un elenco di campi (o costanti) singoli come chiave, evitando quindi sia di definire una KLIST sia una ds per la funzione %kds, p.es.
chain (wProjNo:10:wAcstDate) XPROJAC1;
Di solito le schiere a tempo di compilazione vengono usate per scrivere le costanti di messaggi diagnostici da esporre all'utente. La relativa scomodità delle schiere a tempo di compilazione è che la definizione della schiera deve essere scritta nelle specifiche D (quindi all'inizio del sorgente) invece i valori vanno scritti in coda al sorgente. Se si definiscono più schiere a tempo di compilazione il risultato può essere confusionario o per le meno scomodo.
Un buon metodo alternativo per scrivere tutto nelle specifiche D è definire una DS con un array che si sovrappone.
Il numero di elementi dell'array deve corrispondere al numero di messaggi
P.es.
d Messaggi ds
d 70a inz('Messaggio numero 1')
d 70a inz('Messaggio numero 2 molto lungo +
d anzi lunghissimo')
d Msg 70a overlay(Messaggi) dim(2)
dcl-ds Messaggi;
*n char(70) inz('Messaggio numero 1');
*n char(70) inz('Messaggio numero 2 molto lungo anzi lunghissimo');
Msg char(70) pos(1) dim(2);
end-ds;
Nel formato libero si può ottenere lo stesso risultato di un codice operaitvo CALL scritto in formato fisso definendo una procedura con la keyword extpgm
.
P.es.:
dcl-pr MioPgm extpgm;
parm1 char(10);
parm2 char(2);
end-pr;
dcl-s campo1 char(10);
dcl-s campo2 char(2);
campo1 = 'valore_1';
clear campo2;
MioPgm(campo1:campo2);
...
Aree dati
Dichiarazione della DS Area1 per mappare il contentuto dell'area dati MIAAREA nella libreria QGPL.
dcl-ds Area1 dtaara('QGPL/MIAAREA');
campo1 char(100);
campo2 char(1) overlay(campo1:30);
end-ds;
...
in Area1;
Dichiarazione LDA:
dcl-ds *n dtaara(*auto);
SubField1 char(10) pos(50);
end-ds
Nel caso si utilizzi il tool per la modernizzazione delle proprie applicazioni "WebGate400" si applicano le seguenti limitazioni:
/free.../end-free
.