Programmeren in REXX/Bevelen, deel 1

Uit Wikibooks
Naar navigatie springen Naar zoeken springen

   Programmeren    in REXX


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


SAY[bewerken]

say parameter

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:

/* Voorbeeld voor SAY */
crlf='0D0A'x    
say 'Hallo !'crlf'Tot ziens !'

De zinnen «Hallo !» en «Tot ziens !» komen onder elkaar op het scherm te staan.


EXIT[bewerken]

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[bewerken]

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[bewerken]

De meest fundamentele vorm dient uitsluitend om statements logisch bij elkaar te houden:

do
   say 'Hello'
   say 'Goodbye'
end

Deze constructie komt men veel tegen in combinatie met bv. het if bevel dat we wat verder zullen leren gebruiken.

if 7>5 then do
               say 'Hello' ; say 'Goodbye'
            end

Merk ook op dat het aligneren van "do" en "end" de leesbaarheid bevorderen. We zijn soms ook voorstander van volgende schrijfwijze:

if 7>5 then do
   say 'Hello' ; say 'Goodbye'
end

Ze heeft het voordeel compacter te zijn (smallere marges), en wij beschouwen het als zijnde een IF-blok.

Itereren[bewerken]

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:

do 7 ; say 'Hello' ; end

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).

a=7
do a ; say 'Hello' ; end

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.

a=1
do i = 1 to 10  /* bereken 10 faculteit */
   a = a * i
end

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:

a=1
do i = 1 for 10  /* bereken 10 faculteit */
   a = a * i
end

Bijkomend kunnen we een stapwaarde opgeven waarmee de teller bij elke iteratie moet worden verhoogd. Zonder dat is de stap natuurlijk altijd 1.

a=1
do i=2 to 10 by 2
   a=a*i  /* we berekenen 2 * 4 * 6 * 8 * 10 */
end

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.

a=1
do i=10 to 2 by -2
   a=a*i  /* we berekenen 10 * 8 * 6 * 4 * 2 */
end

Eindeloze lussen[bewerken]

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:

a=2
do forever
   a=a*a                /* berekenen van de machten van 2 */
   if a>256 then leave  /* maar stoppen als we voorbij 256 komen */
end

Iteratiestappen overslaan[bewerken]

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.

do i = 1 to 10
   say i
   if i=5 then iterate 
   say 2**i
end

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[bewerken]

do i = 1 to 10
   do j = 1 to 2
      say i*j
   end j
end i

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[bewerken]

We kunnen ook blijven itereren tot aan een bepaalde voorwaarde is voldaan. Dit doen we met een do until bevel.

a=1
do until a>5
   say a ; a=a+1
end

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.

do while a<6
   say a ; a=a+1
end

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[bewerken]

De IF constructie wordt gebruikt om voorwaardelijk te programmeren:

if test then
   do
      statements indien test waar
   end
else
   do
      statements indien test onwaar
   end

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:

if test then do
   statements indien test waar
end
else do
   statements indien test onwaar
end

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:

if a//7=0 then
   say a 'is deelbaar door 7'
else
   say a 'is niet deelbaar door 7'

Of, met compacte schrijfwijze

if a//7=0 then say a 'is deelbaar door 7'
          else say a 'is niet deelbaar door 7'

Condities kunnen complexe vormen aannemen door gebruik van & (en) en | (of). Dit is een voorbeeld:

vandaag=date('Weekday')
if vandaag='Sunday' | vandaag='Saturday' then say 'Het is weekend !!!'

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:

if 1 then say 'Het is waar!' ; else say 'Het is niet waar!'

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:

if voorwaarde1 then
   if voorwaarde2 then statement
                  else statement
               else statement

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[bewerken]

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.

select
   when voorwaarde_1 then statement
   when voorwaarde_2 then do
      statements
   end
   otherwise  /* voor alle andere gevallen */
      statements of NOP
end


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[bewerken]

Het PARSE bevel is uitermate krachtig. Het combineert een aantal nuttige bewerkingen om strings op te splitsen.
De algemene syntaxis is:

parse [upper] bron sjabloon

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[bewerken]

ARG : argumenten ophalen[bewerken]

parse arg sjabloon

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,

/* Programma behandelt parameters */
parse arg voornaam familienaam
say "De voornaam van" familienaam "is" voornaam
exit

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».

Het bevel ARG is een verkorte vorm voor parse upper arg. We verkiezen dit niet te gebruiken omdat het niet duidelijk de aandacht trekt op het feit dat alles naar hoofdletters zal worden vertaald.

LINEIN : lezen van toetsenbord[bewerken]

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.

parse linein sjabloon

Bijvoorbeeld:

parse linein gegevens
say 'Je hebt "'gegevens'" ingetikt.'

PULL : lezen van de programmabuffer[bewerken]

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).

parse pull input
say 'De eerste lijn van de programmabuffer bevatte "'input'"'
Het bevel PULL is een verkorte vorm voor parse upper pull.

VALUE : opsplitsen van een uitdrukking[bewerken]

parse value een_uitdrukking with sjabloon

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,

parse value "123-4567890-22" with bank '-' kaartnummer '-' controle
say "De kaart met nummer" kaartnummer "werd uitgegeven bij bank" bank"."

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.

parse value "Dit is een lange zin" with woord1 woord2 rest

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[bewerken]

parse var variabele sjabloon

Als bron geven we nu de naam van een variabele op.

a="Dit is een tekst."
parse var a woord1 woord2 woord3
say 'Het tweede woord van "'a'" is "'woord2'"'
say 'Het derde woord is echter "'woord3'"'

Dit zal het volgende op het scherm afdrukken

Het tweede woord van "Dit is een tekst." is "is"
Het derde woord is echter "een tekst."

Nu nog een paar speciale bronnen voor het parse bevel:

SOURCE : programma karakteristieken ophalen[bewerken]

Door source als bron op te geven, vragen we meer informatie op over het programma zelf.

parse source sjabloon

Al naargelang het besturingssysteem kan men andere antwoorden krijgen. Doch normaal mogen we als eerste drie woorden de volgende verwachten:

  1. de naam van het besturingssysteem;
  2. een aanduiding van hoe ons programma werd opgeroepen (COMMAND, SUBROUTINE of FUNCTION, later meer hierover);
  3. de naam en het volledige pad van ons programma.
parse source systeem oproeping programma
say 'Het programma in uitvoering is:' programma
say 'Het werd opgeroepen als:' oproeping
say 'Het draait onder controle van:' systeem

Op een Windows systeem zou dit het volgende kunnen geven:

Het programma in uitvoering is: C:\Program Files\mijnrexxprogramma.rex
Het werd opgeroepen als: COMMAND
Het draait onder controle van: WindowsNT

VERSION : versienummer van REXX[bewerken]

parse version versie

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[bewerken]

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:

myVar = "Smith, John"
parse var MyVar LastName "," FirstName
say "First name is:" firstName
say "Last name is:"  lastName

Hierbij duidt de constante "," aan waar er moet worden gesplitst. De begrenzer zelf verdwijnt daarbij. Dit levert dus:

First name is:  John
Last name is: Smith

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:

myVar = "WSBN nl-3-34-343-00010"
parse var MyVar 6 Taal 8 9 HoofdRubriek 10 18 VolgNummer
say "De taal van het Wikibook is:" Taal
say "De hoofdrubriek is         :" HoofdRubriek
say "en het volgnummer is       :" VolgNummer

met als resultaat:

De taal van het Wikibook is: nl
De hoofdrubriek is         : 3
en het volgnummer is       : 00010

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.

Informatie afkomstig van http://nl.wikibooks.org Wikibooks NL.
Wikibooks NL is onderdeel van de wikimediafoundation.