Det er lang tid siden, jeg har skrevet et programmeringstip. Jeg koder mest REXX, og REXX har en fantastisk opfindelse kaldet stems. Ideen i stems har vundet indpas i mange moderne programmeringssprog, hvor konceptet er kendt som "associative arrays". Rent praktisk betyder det "bare", at i stedet for at anvende et tal til at indeksere en tabel med, så kan man anvende et navn eller ord. Dette koncept har endnu ikke "ramt" PL/I (eller COBOL), men det kommer nok.
Jeg har fået en ide, der ligner lidt. I første omgang benytter jeg den til at løse opgaver, hvor jeg har brug for at finde ud af, om et givet navn eller ord er et, jeg har stødt på tidligere. Man kan kalde det tjek af duplikater. Det fantastiske ved stems i REXX er, at de er nemme at bruge og kræver meget lidt kode for at fungere. Det har jeg så prøvet at opnå i følgende eksempel:
plipgm: PROC(parm) OPTIONS(MAIN) ORDER; DCL parm CHAR(100) VAR; DCL dataCache CHAR(32767) VAR; DCL dataSize FIXED BIN(31); DCL sysprint FILE PRINT; DCL sysin FILE RECORD SEQUENTIAL; DCL sysin_data CHAR(80) VAR; DCL sysin_eof CHAR(1); DCL startPos FIXED BIN(31); DCL wordPos FIXED BIN(31); sysin_eof = 'N'; ON ENDFILE(sysin) sysin_eof = 'Y'; dataSize = stg(dataCache) - 2; dataCache = 'FF'X; OPEN FILE(sysin); READ FILE(sysin) INTO(sysin_data); DO WHILE(sysin_eof = 'N'); sysin_data = trim(sysin_data); IF index(dataCache, 'FF'X !! sysin_data !! 'FF'X) = 0 THEN IF length(dataCache) + length(sysin_data) < dataSize THEN dataCache = dataCache !! sysin_data !! 'FF'X; READ FILE(sysin) INTO(sysin_data); END; CLOSE FILE(sysin); startPos = 2; wordPos = index(dataCache, 'FF'X, startPos); DO WHILE(wordPos > 0); PUT SKIP LIST(substr(dataCache, StartPos, wordPos - startPos)); startPos = wordPos + 1; wordPos = index(dataCache, 'FF'X, startPos); END; END plipgm;
Programmet læser alle records i SYSIN, og udskriver alle de unikke records fundet på SYSIN strippet for foranstillede og efterstillede blanke. Duplikater er dermed blevet fjernet. De unikke records gemmes i en variabel tegnstreng med plads til maksimalt 32767 tegn. De enkelte unikke records adskilles af den hexadecimale værdi FF, som helst ikke skal findes i SYSIN, for så går det galt.
I stedet for en traditionel løsning med et array benytter jeg som sagt en tegnstreng. For at finde elementer i tegnstrengen benytter jeg INDEX funktionen. Denne løsning er langt mere fleksibel end et array, hvor jeg vil være nødt til både at begrænse på antallet af elementer, men også på længden af de enkelte elementer.
Eneste ulempe er den interne begrænsning i PL/I på 32767 tegn for en tegnstreng. Når længden af samtlige unikke records i SYSIN passerer 32767, så vil disse ekstra unikke records simpelthen blive ignoreret. Det er derfor vigtigt at vurdere, om de data, du vil behandle med denne løsning, kan holdes inden for 32767 bytes. Og hvis grænsen alligevel overskrides, hvad skal der så ske. Og så må skilletegnet (i mit eksempel hex FF) selvfølgelig ikke indgå i data.
Jeg synes, det er en supernem løsning at programmere, da INDEX funktionen laver alt det hårde arbejde. Og det smarte ved INDEX på mainframen er, at der er en instruktion i maskinsproget, der matcher, så derfor går det også rasende stærkt (hvis altså PL/I compileren laver en optimal oversættelse).