# Programmeren in REXX/Bevelen, deel 1

Dit hoofdstuk geeft meer uitleg bij een eerste reeks veel gebruikte REXX bevelen.

# SAY

We beginnen met het eenvoudigste bevel, namelijk say. De instructie zal alles wat als parameter is meegegeven, na interpretatie, op het scherm afdrukken. De parameter kan zijn opgebouwd uit constanten, variabelen of een combinatie ervan.
In dit voorbeeld hebben we zelfs een Carriage Return en Line Feed (kortweg CrLf) toegevoegd om het afdrukken op 2 regels te laten geschieden:
De zinnen «Hallo !» en «Tot ziens !» komen onder elkaar op het scherm te staan.

# EXIT

Het exit bevel beëindigd het programma. Er kan desgevallend een geheel getal als parameter worden meegegeven. Dit getal stelt dan de returncode van het programma voor. Zonder parameter is de returncode steeds nul (0). Deze returncode kan opgepikt worden door de oproeper. Windows maakt er spijtig genoeg geen gebruik van en toont de returncode niet.

# DO

Een DO bevel duidt het begin aan van een reeks samenhorende statements. De reeks moet worden afgesloten door een END bevel. Men noemt dit een DO-blok.
DO-blokken kunnen andere DO-blokken bevatten (genest zijn). Het is een goede gewoonte om de statements binnen het blok te laten inspringen om de leesbaarheid te vergroten.

## Fundamentele vorm

De meest fundamentele vorm dient uitsluitend om statements logisch bij elkaar te houden:
Deze constructie komt men veel tegen in combinatie met bv. het if bevel dat we wat verder zullen leren gebruiken.
Merk ook op dat het aligneren van "do" en "end" de leesbaarheid bevorderen. We zijn soms ook voorstander van volgende schrijfwijze:
Ze heeft het voordeel compacter te zijn (smallere marges), en wij beschouwen het als zijnde een IF-blok.

## Itereren

Een DO-blok kan ook dienen om de reeks statements een aantal maal te laten uitvoeren. In zijn meest eenvoudige vorm bepaalt een parameter het aantal iteraties dat moet worden uitgevoerd:
Het aantal iteraties kan ook aangegeven worden via een variabele. Het moge duidelijk zijn dat de waarde van de variabele een geheel getal moet zijn, anders zal men een REXX fout krijgen (Code 26: Invalid whole number).
We kunnen ook een variabele opgeven die dan de teller van de lus wordt. Deze teller kan desgevallend binnen de lus gebruikt worden. We bepalen daarbij ook een begin- en eindwaarde.
Deze lus zal 10 maal doorlopen worden, waarbij de variabele i respectievelijk de waarde 1, 2, 3, ... 10 zal bevatten. Het resultaat van deze lus is dat we 10! (faculteit) hebben berekend.
Een alternatieve schrijfwijze bekomt men met het for sleutelwoord. Dit is dan ook gelijkwaardig aan vorige voorbeeld:
Bijkomend kunnen we een stapwaarde opgeven waarmee de teller bij elke iteratie moet worden verhoogd. Zonder dat is de stap natuurlijk altijd 1.
Deze stapwaarde kan ook negatief zijn, maar dan moet men van een groot getal naar een klein getal itereren, anders zal men de lus nooit meer verlaten.

## Eindeloze lussen

Met do forever geven we aan dat er oneindig lang geïtereerd moet worden. Uiteraard kan dat nooit de bedoeling zijn. We zullen dus op een bepaald ogenblik uit de lus moeten springen. Dit kan bereikt worden door het bevel leave te gebruiken. Meestal zal dit gebeuren na het testen van een voorwaarde, zoals in dit voorbeeld:

## Iteratiestappen overslaan

We kunnen naar een volgende iteratie gaan (en dus een gedeelte van de lus niet behandelen) mits gebruik van het iterate bevel. In het volgende voorbeeld lijsten we alle machten van 2 tussen 1 en 10, maar niet de 5-de macht.
Iets gelijkaardigs zou kunnen bekomen worden door de lus-variabele i te manipuleren, doch dit houdt gevaren in en maakt het programma minder leesbaar.

## Geneste lussen

Merk op dat we de lusvariabele kunnen opgeven bij het end bevel. Dit verhoogt zeker de leesbaarheid indien er veel programmalijnen in de lus zitten. De laatst begonnen lus moet natuurlijk eerst sluiten. We kunnen de lussen niet "kruisen".

## Conditionele lussen

We kunnen ook blijven itereren tot aan een bepaalde voorwaarde is voldaan. Dit doen we met een do until bevel.
Wanneer a een waarde groter dan 5 behaalt verlaten we de lus. Deze voorwaarde wordt telkens aan het einde van de lus getest, en de lus wordt dus minstens éénmaal uitgevoerd. Willen we echter de test uitvoeren aan het begin van de lus, dan gebruiken we het bevel do while.
Deze lus geeft hetzelfde resultaat als die met "do until".
* De lusvariabele wordt telkens aan het einde van de lus (of bij een iterate bevel) verhoogd met de stap. Bij het terugkeren naar het do bevel is de waarde dus op een bepaald moment groter geworden dan de eindwaarde en stopt de iteratie. Willen we m.a.w. na de lus vertellen hoeveel maal de lus doorlopen werd, dan moeten we terug een stap aftrekken.

# IF

De IF constructie wordt gebruikt om voorwaardelijk te programmeren:
Ditzelfde kunnen we op een meer compacte manier schrijven, waardoor het geheel van de constructie gemakkelijker te overzien is op eenzelfde schermhoogte, zeker als er veel statements in de blokken zitten:
We hebben dit al een IF-blok genoemd, naar analogie met het DO-blok.
Het gedeelte else is niet verplicht als het niet nodig is.
Indien slechts één statement moet worden uitgevoerd is een DO-blok ook niet nodig:
Of, met compacte schrijfwijze
Condities kunnen complexe vormen aannemen door gebruik van & (en) en | (of). Dit is een voorbeeld:
De voorwaarde die in het if bevel wordt getest moet resulteren in «1» als het resultaat waar is, en «0» als het onwaar is. Gelet daarop kunnen we ook iets schrijven in de aard van:
Merk tenslotte op dat else een aparte instructie moet zijn, reden waarom hier het scheidingsteken ; is gebruikt.
Ook if-blokken kunnen genest zijn. Daarbij moet men opletten dat de logica gerespecteerd wordt:
Stel dat voor het binnenste IF-blok geen else nodig is, dan moeten we er toch één schrijven omdat anders de andere else zou worden gebruikt. Als statement gebruikt men dan het bevel NOP wat een afkorting is voor No OPeration, "niets doen".

# SELECT

Met een IF kunnen we slechts twee gevallen (waar/onwaar) testen. Indien we meer dan 2 mogelijke uitkomsten kan verwachten gebruiken we liever een SELECT-blok dan een reeks geneste IF bevelen.
Otherwise is niet strikt nodig, maar men moet natuurlijk opletten dat alle mogelijkheden behandeld worden. Otherwise vangt de onverwachte gevallen mooi op.
Indien een when meerdere instructies nodig heeft moet men natuurlijk een DO-blok gebruiken. Otherwise bevat een impliciet DO-blok, dus alle instructies tussen otherwise en end horen automatisch logisch samen.

# PARSE

Het PARSE bevel is uitermate krachtig. Het combineert een aantal nuttige bewerkingen om strings op te splitsen. De algemene syntaxis is:
Hierbij wordt de bron opengebroken volgens wat is opgegeven in het sjabloon (template in het Engels). Het Engels werkwoord to parse betekent ontleden, analyseren. Het Van Dale woordenboek vermeldt zelfs parseren als een bestaand Nederlands woord. Maar het is misschien gemakkelijker te onthouden dat parse iets zal "opsplitsen in partjes". De bron wordt opgegeven als een combinatie van een codewoord en parameters. Het sjabloon is in zijn eenvoudigste vorm een reeks namen van variabelen.
In zijn eenvoudigste vorm behelst het opsplitsen dus een bewerking waarbij woorden uit de bron aan de respectievelijke variabelen van het sjabloon worden geässigneerd. Indien het optioneel codewoord upper is toegevoegd zal de bron tevens naar hoofdletters worden vertaald alvorens in de variabelen terecht te komen. Maar door meer complexe sjablonen te gebruiken kan men het opsplitsen intelligenter maken. We leren daar later meer over in het hoofdstuk Parse in Detail.
Laten we nu bekijken welke soorten bronnen mogelijk zijn.

## Parse bronnen
### ARG : argumenten ophalen

De bron verwijst hier naar de parameters (ofte argumenten) die men bij het oproepen van het programma of subroutine heeft meegegeven. Stel dat we volgend programma oproepen met de argumenten Jan Klaas,
dan mogen we terecht verwachten de zin «De voornaam van Klaas is Jan» op het scherm te zien verschijnen. Indien ook nog het codewoord upper zou zijn toegevoegd, dan bekwamen we «De voornaam van KLAAS is JAN».

### LINEIN : lezen van toetsenbord

Met linein wordt het toetsenbord de bron. Het programma zal daarbij wachten tot de gebruiker de enter-toets heeft gebruikt, al dan niet na intikken van data. De ingevoerde data worden dan door het sjabloon opgesplitst.
Bijvoorbeeld:

### PULL : lezen van de programmabuffer

In de programmabuffer ofte stack kunnen tekstregels aanwezig zijn. Deze werden er bijvoorbeeld worden aan toegevoegd met de bevelen PUSH of QUEUE (meer details hierover in het hoofdstuk Werken met de programmabuffer). Indien de stack leeg is gaat het programma wachten op gegevens ingebracht op het klavier (en is het dus equivalent aan het gebruik van linein als bron).

### VALUE : opsplitsen van een uitdrukking

Een uitdrukking bestaan uit constanten, variabelen en/of functies. Daar de uitdrukking kan resulteren in een zin bestaande uit verschillende woorden, is in deze vorm het sleutelwoord with verplicht om de bron van het sjabloon te scheiden. Als we dit uitvoeren,
dan krijgen we «De kaart met nummer 4567890 werd uitgegeven bij bank 123.». Hier hebben we de bron niet gesplitst waar er spaties voorkomen, maar wel waar er streepjes zijn.
Nu zal de variabele rest de woorden «een lange zin» bevatten, want er zijn niet genoeg variabelen in het sjabloon om alle woorden van de bron op te nemen. De laatste variabele krijgt dus hetgeen overblijft in de bron. Hoe we dat eventueel anders kunnen oplossen leren we straks bij de bespreking van de verschillende soorten sjablonen.

### VAR : de waarde van een variabele opsplitsen

Als bron geven we nu de naam van een variabele op.
Dit zal het volgende op het scherm afdrukken
Nu nog een paar speciale bronnen voor het parse bevel:

### SOURCE : programma karakteristieken ophalen

Door source als bron op te geven, vragen we meer informatie op over het programma zelf.
Al naargelang het besturingssysteem kan men andere antwoorden krijgen. Doch normaal mogen we als eerste drie woorden de volgende verwachten:
* de naam van het besturingssysteem;
* een aanduiding van hoe ons programma werd opgeroepen (COMMAND, SUBROUTINE of FUNCTION, later meer hierover);
* de naam en het volledige pad van ons programma.
Op een Windows systeem zou dit het volgende kunnen geven:

### VERSION : versienummer van REXX

assigneert de versie van REXX (bv. «REXX-ooRexx_3.1(MT) 6.01 20 Apr 2007») aan de variabele versie. Nuttig om bijvoorbeeld na te gaan of een bepaalde functie in deze versie van REXX kan gebruikt worden.

## Sjabloonvormen

Tot nu toe hebben we meestal aangenomen dat het sjabloon uit een rij tokens (variabelen) bestaat. De woorden uit de bron worden daarbij één voor één aan de variabelen toegekend. Hierbij speelt het aantal spaties tussen de woorden van de bron geen belang.
Een sjabloon kan echter complexere vormen aannemen en begrenzers bevatten. Deze begrenzers kunnen constanten, kolomnummers of indirecte kolomnummers zijn. Hier een voorbeeld met een constante begrenzer:
Hierbij duidt de constante "," aan waar er moet worden gesplitst. De begrenzer zelf verdwijnt daarbij. Dit levert dus:
Merk op dat de spatie die in de bron net voor "John" staat ook blijft bestaan in de variabele firstname ! Als we constante begrenzers gebruiken worden extra spaties niet langer gereduceerd tot één enkele ! We kunnen zeggen dat we zijn overgestapt van "zoeken naar één of meer spaties" op "zoeken naar de expliciet opgegeven constante".
In het laatste statement hebben we een dubbele spatie vóór de variabele lastname geplaatst, omdat het mooi aligneert met het statement erboven. Doch hier blijft uiteindelijk slechts één spatie over, want het aantal spaties tussen de woorden van een statement heeft geen belang, dat leerden we vroeger al.
En nu een eenvoudig voorbeeld waarin we kolombegrenzers gebruiken:
met als resultaat:
Het parse bevel zal eerst de karakters vanaf positie 6 tot en met 7 in variabele Taal plaatsen. Het karakter op positie 8 wordt verwaarloosd. Positie 9 gaat naar HoofdRubriek, posities 10 t.e.m. 17 vallen weg en tenslotte gaat alles vanaf positie 18 naar variabele VolgNumber.
* Naamgeving van variabelen Iedereen begrijpt wel dat cryptische namen voor variabelen (xyz17) de leesbaarheid niet bevorderen. Beter is het een naam te kiezen die de verwachte inhoud ervan beschrijft, zoals ons VolgNummer.
* Voor REXX worden alle karakters hoofdletters, maar wij hebben de mogelijkheid onze namen meer leesbaarheid te geven door met combinaties van hoofd- en kleine letters te werken. Een alternatieve schrijfwijze die men ook dikwijls gebruikt is volg_nummer.
In het hoofdstuk Parse in meer detail zullen we dus nog uitgebreid terugkomen op dit belangrijk en krachtig bevel.