# Programmeren in REXX/Parse in detail

In dit hoofdstuk gaan we dieper in op de mogelijkheden van het PARSE bevel.

# Waarvoor dient PARSE ?

Parse laat toe een bron op te splitsen volgens een sjabloon (Engels: template) waarbij de verschillende delen aan variabelen worden toegekend.
Bijvoorbeeld:
Hierbij is de bron de inhoud van de variabele zin en bestaat het sjabloon uit «woord1 woord2 woord3 woord4».
Na uitvoering zal «Dit» in variabele woord1 komen, «is» in variabele woord2, enzovoort.

# Korte herhaling van de verschillende bronnen

De bronnen kunnen zijn:
* ARG - de argumenten ofte parameters die aan het programma, een subroutine of functie worden meegegeven.
* PULL - de eerste zin die in de stack te vinden is. Bij ontstentenis hiervan, de gegevens die aan het klavier zullen worden ingevoerd.
* LINEIN - vergelijkbaar met pull, maar er wordt niet naar de stack gekeken, enkel naar input aan het klavier.
* VAR variable - de inhoud van de opgegeven variabele.
* VALUE uitdrukking WITH - het resultaat van de interpretatie van de uitdrukking.
en een paar buitenbeentjes:
* SOURCE - de karakteristieken van het uitvoerend programma (minstens: besturingssysteem, oproeptype en naam en plaats van de broncode)
* VERSION - de geïnstalleerde versie en release van REXX.
* Het sleutelwoord with is bij parse value écht nodig. De bron is een uitdrukking die complexe vormen kan aannemen, en het sleutelwoord dient als scheiding met het sjabloon.
* Een veel voorkomende fout is een with te gebruiken bij een parse var:
* parse var zin with woord1 woord2
* Dit resulteert niet in een syntax-fout, doch het eerste woord van zin zal terechtkomen in variabele with.

# Bespreking van de sjabloonvormen

Sjablonen kunnen bestaan uit:
* een eenvoudige opsomming van tokens (namen van variabelen);
* variabelen samen met constante zoek-strings;
* variabelen samen met relatieve of absolute positie-aanduidingen.
Ook combinaties van deze vormen zijn mogelijk.
Het voorbeeld waarmee we dit hoofdstuk zijn begonnen is van de eerste soort.
* Indien de bron meer woorden bevat dan er variabelen zijn opgegeven in het sjabloon, dan krijgt de laatste variabele van het sjabloon de rest uit de bron. Dus bij:
* parse value "Dit is een zin." with w1 w2 w3
* zal variabele w3 de waarde «een zin.» ontvangen.

## Plaatshouder

Willen we vermijden dat de laatste variabele het overtollige deel van de bron bevat, dan lijkt het toevoegen van een extra "wegwerp"-variabele in het sjabloon een eenvoudige oplossing. Dit zal wel werken, maar we verbruiken nodeloos geheugen indien de wegwerpvariabele nooit meer gebruikt zal worden.
Een meer elegante oplossing bestaat erin een plaatshouder te voorzien. Op elke plaats in het sjabloon waar we een woord uit de bron niet nodig zullen hebben schrijven we dan een punt om de plaats te reserveren, zonder dat de inhoud zal worden opgeslagen in geheugen.
Dit is een voorbeeld:
Nu bevat w1 de waarde «Dit», en w3 de waarde «een».
Meer nog, vermits de laatste variabele van een sjabloon de rest van de bronstring zal bevatten, inclusief de spaties, zal een plaatshouder ons in het volgend voorbeeld ook uit de nood kunnen helpen. Schrijven we:
dan zal naam de waarde « Klaas » bevatten, inclusief de 5 spaties aan het eind, én een spatie vooraan. Er wordt inderdaad slechts één spatie weggenomen tussen de woorden van de bron.
Gebruiken we echter een plaatshouder zoals hier:
dan zal variabele naam slechts de waarde «Klaas» bevatten en neemt de plaatshouder de spaties voor zijn rekening.
Een plaatshouder kan ook nuttig zijn in alle meer complexe sjablonen die we verder behandelen.

## Sjablonen met constante zoekterm

Een constante zoekterm in een sjabloon geeft aan dat de bron moet opgesplitst worden in 2 delen waar de constante (de eerste maal) voorkomt. Elk van de delen kan dan verder nog worden opgesplitst via andere sjabloonvormen. De zoekterm zelf maakt geen deel meer uit van het resultaat. Indien de zoekterm niet voorkomt in de bron, dan zal het eerste deel de volledige bron bevatten, en het tweede deel leeg blijven (een nullstring zijn).
Voorbeeld:
splitst het bankkaartnummer in 3 afzonderlijke delen op de plaatsen waar de zoekterm "-" voorkomt.
is een voorbeeld van opsplitsing van velden uit een CSV-bestand (zie hier voor meer uitleg over een CSV-bestand). Bij elke komma wordt een deel van de bron afgesplitst en verder ontleedt. Hier wordt het eerste deel nog verder opgesplitst in 2 variabelen (voornaam en naam) en wordt de eventuele rest in dit veld door de plaatshouder opgevangen. Een aandachtig lezer zal opmerken dat het misloopt als het eerste veld "Jan van Gent" zou bevatten. Dit is duidelijk geen al te goede programmatie.
Alles wat na de derde komma komt wordt ook door een plaatshouder opgevangen. Die plaatshouder hoeft strikt gezien zelfs niet meer te worden geschreven.
Laten we echter volgend voorbeeld even bestuderen:
Onze zoekterm bevat 2 spaties na de komma. Onder deze vorm komt de zoekterm niet voor in de bron, met als gevolg dat naam de volledige bron zal bevatten en dat voornaam een nullstring wordt.

## Sjablonen met variabele zoekterm

Zoektermen kunnen ook via een variabele worden opgegeven. In dat geval wordt de variabele tussen haakjes gezet om ze te onderscheiden van de rest in het sjabloon.
In volgend voorbeeld maken we het karakter dat de velden in een CSV bestand van elkaar scheidt variabel.

## Sjablonen met posities

Er zullen gevallen zijn waar we de opbouw van onze bron tot op de kolom kennen en waar we dan willen splitsen op bepaalde absolute of relatieve posities.

### Sjablonen met absolute posities

Een absolute positie wordt aangegeven door een getal, zonder plus- of minteken.
Voorbeeld:
Hier zullen de karakters op posities 1 t.e.m. 3 in variabele banknummer komen. Met het karakter op positie 4 gebeurt niets. Posities 5 tot 11 gaan naar kaartnummer, positie 12 gaat verloren en de posities 13 tot aan de eerste spatie of het eind van de bron gaan in controlenummer. Kortom, we hebben dezelfde uitslag als in bij het eerste voorbeeld met constante zoekterm, maar omdat we het formaat van een (Belgisch) bankkaart nummer kennen is het mogelijk op deze manier te parsen.
Gebruik van absolute posities is typisch voor het behandelen van gegevens met vaste kolombreedtes. Bekijk dit voorbeeld:
We splitsen dus op posities 1, 10 en 30. De opgave van positie 1 is niet nodig, maar verhoogt wel de leesbaarheid.
Bij meer uitgebreide records schrijft men het soms als volgt:
waarbij de commentaren best wat zinvoller kunnen gemaakt worden. Vergeet hierbij ook de vervolg-komma's niet !

### Sjablonen met relatieve posities

Als we weten hoe breed elke kolom is, dan kunnen we werken met relatieve posities. Die stellen we voor als positieve of negatieve getallen. Met negatieve getallen verplaatsen we ons terug in de bron !
Indien de eerste kolom 10 karakters breed is, en de tweede 20, dan kunnen we ons vorig voorbeeld omvormen tot:
Ook absolute of relatieve posities kunnen variabel worden gemaakt, zoals in dit aangepast voorbeeld:
Indien we absolute posities willen gebruiken, dan moeten we ze als volgt schrijven:
Voor absolute posities gebruiken we dus een gelijkheidsteken, en geen + of -.
Laten we tot slot nog even naar volgend voorbeeld kijken:
We splitsen waar een \-teken voorkomt, maar door relatief +0 te gebruiken trappelen we als het ware ter plaatse en zal het \-teken ook deel gaan uitmaken van de variabele die erna komt. Dus subdir1 zal «\Program Files» bevatten.

# Nog meer mogelijkheden
## De bron meermaals parsen

Bij de opmerkingen aan het eind van de bespreking van ons eerste REXX programma hebben we vermeld dat we:
konden herleiden tot:
Wat zal er nu gebeuren ? REXX interpreteert van links naar rechts. Als we veronderstellen dat i op een bepaald moment gelijk is aan «23», namelijk ons 9de priemgetal, en ook dat z nog steeds «8» bevat, dan zal
* de interpretatie van de bron leiden tot «9 23»;
* het parsen beginnen door het eerste woord van de bron, «9» in variabele z te zetten en door de rest te elimineren middels de plaatshouder;
* teruggesprongen worden naar absolute positie 1 van de bron;
* het parsen daar hernemen en de waarde «9» aan variabele priem.0 toegekend worden;
* en tenslotte wordt «23» gestockeerd in variabele priem.9, want z heeft ondertussen reeds de waarde «9» !

## Verschillende bronnen tegelijk parsen

Enkel de bevelen ARG en PARSE ARG kunnen meer dan één bron hebben. Zij behandelen namelijk de parameters die aan een subroutine of interne functie zijn meegegeven. Deze worden van elkaar gescheiden door komma's. Dan moet voor elke parameter een apart sjabloon gemaakt worden en moeten de sjablonen ook van elkaar worden gescheiden door een komma. We komen dus tot dit veralgemeend formaat:
Elk sjabloon kan daarbij zijn opgebouwd zoals we al hebben geleerd.
Laten we dit voorbeeld bestuderen:
Wat moeten we hiervan leren ?
* de functie krijgt 2 parameters binnen. Ze zijn gescheiden door een komma;
* de komma in het parse bevel, net na het woord subtotaal, scheidt deze parameters van elkaar;
* de eerste parameter gaat dus in variabele subtotaal;
* de tweede parameter - die in dit geval zelf ook komma's bevat - wordt door het tweede sjabloon (m1 ',' m2 ',' m3 ',' vierde) opgesplitst. Hier zijn de komma's constante zoektermen !
We mogen dus terecht volgend resultaat op het scherm zien verschijnen:
* Als een REXX programma vanuit het besturingssysteem (bv. op de opdrachtprompt van Windows) wordt opgeroepen kan men slechts één enkele parameter meegeven. Een eventuele komma in de parameter behoort dan in dat geval tot de bron zelf, en moet eventueel met een constante zoekterm worden gevonden.
* Aan een interne subroutine of functie kan men wél meer parameters meegeven zoals we hier hebben geleerd. Ook wanneer een ander REXX programma of een host-commando ons oproept, kunnen zij meer dan één parameter doorgeven.

## Een lijst "opeten"

Het kan gebeuren dat we een lange lijst data te verwerken krijgen. Indien deze lijst in één lange zin is vervat, dan bestaat een typische manier om de elementen van de lijst te behandelen er als volgt uit:
* indien de lijst later nog nodig is, maak dan een duplicaat in een hulpvariabele;
* start een lus die zal lopen tot de hulpvariabele leeg is;
* eet de hulpvariabele op door woord voor woord weg te parsen.
Het volgende voorbeeld zal dit duidelijk maken:
Ons parse bevel zal er bij de eerste iteratie voor zorgen dat:
* de variabele element de waarde «Jan» krijgt
* de variabele werk gereduceerd wordt tot «Piet Paul Simon Matthias»
Bij elke volgende iteratie gaat er zo een woord van werk naar de variabele element. Na 5 iteraties zal werk "leeg" zijn en zal de lus dus stoppen.

## Een laatste uitgewerkt voorbeeld

In dit programma verwachten we de naam van een map. Doch, optioneel kunnen ook andere parameters worden opgegeven die "/Vanaf startnummer" en "/Tot eindnummer" kunnen zijn.
Het gaat hier namelijk om het begin van een programma dat digitale foto's zal verwerken. Deze hebben typisch de vorm "IMG_nnnn.jpg", waarbij nnnn een volgnummer voorstelt. De verwerking kan beperkt worden tot de foto's met nummers gelegen tussen het opgegeven start- en eindnummer, anders worden alle foto's uit de map verwerkt.
Dit is ons programma:
Laten we veronderstellen dat we het programma oproepen als volgt:
We willen dus foto's die in map d:\MijnFotos\Reis2011\ zitten verwerken. Maar we willen de verwerking ook beperken tot de foto's met nummers tussen 1212 en 1233.
Het eerste statement in ons programma zal de argumenten parsen. Daarbij maken we echter gebruik van nog een nieuwe techniek.
Door een nullstring in het sjabloon te steken gaan we op zoek naar de eerstvolgende "leegte". Die komen we uiteraard pas tegen op het einde van bron ! Dus, alles wat we als parameters hebben meegegeven gaat in de variabele dir. Dan pas komen we de nullstring tegen, zodat de variabelen beginNr en eindNr geïnitialiseerd worden als een nullstring. Dit zal ons later toelaten met een "if BeginNr<>‘‘ then ..." na te gaan of we al dan niet een beginnummer tussen de parameters hebben gevonden.
Vervolgens gaan we alle parameters die in dir zitten opeten zoals we boven hebben geleerd. Komen we daarbij een woord tegen dat met een '/' begint, dan vermoeden we een optie te hebben gevonden. Met het select-blok gaan we vervolgens na of het een geldige optie is. De eerste letter is daarbij voldoende. Het moet gaan om /V of /T, anders geven we een foutbericht.
Bij een geldige optie hoort een getal. Dit halen we op door de variabele dir nog een woord verder op te eten.
Na het select-blok houden we dus nog enkel de echte mapnaam over in variabele dir.
Bemerk ook de elegante exit subroutine. Ze behandelt de eventuele foutcodes en -berichten. We komen hier nog op terug in een volgende hoofdstuk.
Hiermee hebben we hopelijk voldoende aangetoond welke de uitgebreide mogelijkheden van het parse bevel zijn.