 

Power Basic versus Quick Basic
Deel 3

Van Hans Lunsing kreeg ik een e-mail met enkele aanvullingen op het vorige deel. Ik wil dit de leden niet onthouden en druk hierbij zijn brief af.

Beste Sjef,

Hierbij nog wat opmerkingen n.a.v. de laatste Nieuwsbrief:

1. De programmeertip van "Hub Sakee" :) op blz. 12.

Parameters van subroutines en functies (kortweg procedures) kunnen op verschillende manieren worden doorgegeven. De twee belangrijkste zijn:
* by reference. Dit is de default. Het adres van de parameter wordt doorgegeven. Dat houdt in dat een verandering van de parameter in de procedure doorwerkt in de "caller", dat is het hoofdprogramma of de procedure van waaruit de procedure in kwestie werd aangeroepen.
* by value. In dit geval moet het sleutelwoord BYVAL worden gebruikt. Niet het adres maar de waarde van de parameter wordt doorgegeven. Omdat het adres in de procedure niet bekend is werken in de procedure aangebrachte veranderingen niet door in de caller. De waarde mag dus wel worden veranderd, maar dit heeft buiten de procedure geen effect. 

                                  In QuickBasic 4.5 is BYVAL alleen mogelijk met assembler routines, in PowerBasic en QuickBasic PDS 7.1 werkt het ook met Basic                      
                                  procedures. In geval van een "variable length" string wordt in PowerBasic de string handle als waarde doorgegeven, niet de string zelf. In QB 
                                 7.1 kan een "variable length" string niet by value worden doorgegeven.

                                 Vooral in het geval van integers is het doorgeven by value voordelig. In QB gaan weliswaar zowel by reference als by value 2 bytes op de stack,                                   
                                 maar in PB telt een adres 4 bytes en een integer maar 2 bytes. Bovendien is in de procedure zowel in QB als in PB meteen de waarde  
                                 beschikbaar. Hij hoeft niet eerst van het gegeven adres te worden opgehaald. Dat leidt inderdaad tot snellere en kortere code.

2. Verschillen tussen PB en QB, $DIM

Je noemt daar dat er aan $DIM ALL een nadeel kleeft: ook de meest eenvoudige variabelen moeten worden gedeclareerd. Ik zou er dan wel bij vertellen dat dat ook een groot voordeel kan zijn: het voorkomt namelijk fouten. Stel je gebruikt geen DEFINT A-Z, je hebt een variabele MyInt%, en per ongeluk schrijf je ergens MyInt. MyInt zonder % is een andere variabele dan MyInt%, en wel van het type single precision. Hij zal bij eerste gebruik de waarde 0 hebben en niet de aan MyInt% toegekende waarde. Zonder $DIM ALL spoor je zo'n fout niet gemakkelijk op, met $DIM ALL doet de compiler het voor je.

3. Verschillen tussen PB en QB, $SEGMENT

$SEGMENT wordt gebruikt om programma's die na compilatie niet meer in 1 codesegment (64Kb) passen in meerdere codesegmenten te splitsen.

4. Verschillen tussen PB en QB, $STACK

                                  In QB kan de stack grootte in het programma worden aangepast met de tweede parameter van het CLEAR statement, b.v.:

CLEAR,,4096
maakt een stack van 4Kb aan. 

Met hartelijke groet, 
Hans Lunsing
-----------------------------------------------------------------------------
In deze aflevering wordt begonnen met het vergelijken van diverse commando's. Als aandachtig lezer heeft u al kunnen merken dat ik alle vergelijkingen maak vanuit Power Basic, van nu af aan PB genoemd. Dat moet echter geen bezwaar zijn voor mensen die de voorkeur geven aan Quick Basic, van nu af aan QB genoemd, omdat ik, waar het mogelijk is, zal trachten het alternatief aan te geven, of de diverse oplossingen worden aan het eind van deze artikelenreeks gegeven.
* * * * *
ARRAY. Het ARRAY statement is niet opzichzelf staand. Door toevoeging van SORT, SCAN, INSERT of DELETE, heeft u de beschikking over een krachtige collectie van mogelijkheden. Als extra toevoeging van ASCENT of DESCENT (bij SORT) kan in oplopende of afgaande volgorde gesorteerd worden. Ook gedeeltes van een array kunnen, los van de andere elementen, gesorteerd worden. Als extra kunnen TAGARRAY en/of COLLATE toegevoegd worden. Met TAGARRAY wordt een tweede array in gelijke volg-orde meegesorteerd, bijvoorbeeld een index-array. Dat is zeer handig, met gebruikmaking van een binaire zoekroutine,  voor het het snel ophalen van een bepaald element. COLLATE wordt toegepast als u woorden met een andere ascii-waarde wilt meesorteren. Bij- voorbeeld woorden die beginnen met onze normale ' n ' gevolgd woorden die beginnen met de spaanse '  ' of '  '. Zonder de toevoeging COLLATE zullen na woorden beginnend met ' n ' (CHR$(110)) woorden beginnend met ' o ' (CHR$(111)) volgen en geen woorden beginnend met '  ' (CHR$(164)) of '  ' (CHR$(165)). Achter COLLATE moet uiteraard een toevoeging staan die aangeeft wat de volgende sorteerkeuze is. Dat kan een string zijn of een stringvariabele Ditzelfde is uiteraard van toepassing op grote en kleine letters. Door COLLATE UCASE toe te voegen, zullen hoofdletters als kleine letters gezien worden. De toevoegingen SCAN, INSERT en DELETE spreken voor zichzelf. Hier ga ik dan ook niet verder op in. Het geheel geldt voor nummerieke-, string- en multi-dimensionale array's Het alternatief voor QB is QSORT.BAS, dat standaard meegeleverd wordt. Hierin zijn bovenomschreven toepassingen niet mogelijk.
* * * * *
ASM. In PB is het mogelijk om een assemblerprogramma midden in uw broncode te plaatsen. Het maakt niet uit waar. Het is toe te passen op routines die in basic te traag zijn. De progammering is eenvoudig. Achter het woord ASM wordt de opcode geplaatst. Twee maal ASM plus opcode, of een ander statement, op een regel is niet toegestaan. Wel mag op dezelfde regel commentaar staan. Die moet dan voorafgegaan worden door een remarkteken. Dat is niet het woord REM en ook niet de hoge komma ( ' ), zoals we die in basic kennen, maar de semicolon ( ; ), beter bekend als punt-komma. Inplaats van ASM mag ook het uitroepteken ( ! ) gebruikt worden, dat maakt het intikken eenvoudiger en de code korter. Voor de rest wordt de PB-structuur gebruikt, inclusief labels, variabelen en eventueel procedures en functies. Bij PB wordt standaard een utility meegeleverd met de naam INLN2ASM.EXE. Daarmee kunnen $INLINE-codes naar assemblercodes geconverteerd worden.
* * * * *
BIT. Met het BIT statement kan elk individueel bit van gemarkeerde (signed) of ongemarkeerde (unsigned) integer variabele veranderd worden. Met de BIT functie is het mogelijk om elk individueel bit van een signed of unsigned integer variabele te lezen. Het BIT statement of de functie komt in QB niet voor.
* * * * *
CALL. Het gebruik van het CALL statement zal dusdanig bekend zijn, dat ik daar geen uitleg over hoef te geven. In PB heeft echter 'n tweede mogelijkheden om een procedure of functie te activeren. De eerste is het meest toegepaste en voor beide dialecten gelijk. Bij-voorbeeld; CALL Proc (a%, b%, c!), of CALL Display( ). Hierbij wordt, zoals gebruikelijk, het CALL statement gebruikt met begin- en eindhaakjes. De tweede mogelijkheid in PB is zonder gebruikmaking van CALL en haakjes. Hetzelfde voorbeeld; Proc a%, b%, c! of Display. Bij Display of iets gelijkends lijkt het net een normaal gereserveerd woord. U zult het echter niet vinden in een lijst met gereserveerde woorden.
* * * * *
CHDRIVE. Met het CHDRIVE statement kunt u in uw programma een ander diskette-station aanwijzen. Voorbeeld:

	CHDRIVE "B"
of
	INPUT "Nieuw diskettestation ", NieuwDrive$ 
	CHDRIVE NieuwDrive$

Opvallend in het eerst voorbeeld is dat de door DOS gebruikte dubbele punt niet aanwezig is. Deze hoeft niet, mag echter wel. QB kent dit statement niet.
* * * * *
CLEAR. Het CLEAR statement reset alle nummerieke variabelen tot 0 en alle string-variabelen tot nul-strings en schakelt event trapping uit. Het heeft geen effect op de stack-grootte en sluit geen open files af. Let hier op! Voor meer details in QB; zie de brief van Hans Lunsing, die bovenaan dit artikel is afgedrukt.
* * * * *
CLS. Het CLS statement in QB verschilt op diverse punten van dat van PB. In gebruik zonder toevoeging is de werking in beide dialecten gelijk. Het maakt het scherm schoon en zet de cursor in de linker bovenhoek. En nu de verschillen. Eerst het gebruik in QB, dan die in PB. De verschillen ziet u dan zelf. QB kent drie mogelijke toevoegingen.

CLS 0:		Maakt het scherm schoon, als boven omschreven.
CLS 1:		Maakt alleen de graphics viewport schoon (als die actief is).
CLS 2:		Maakt alleen de text viewport schoon en laat daarbij de 		onderste regel onveranderd.
CLS 0, 1, 2	Als alle drie argumenten gebruikt worden, zal alleen het 		graphics- of het text viewport schoon gemaakt worden, 		afhankelijk van het laatste gebruik van het VIEW statement.

In PB wordt het iets anders gedaan. Daar worden geen nummers achter het CLS statement gezet, maar leesbare woorden. Ook is het effect afhankelijk van de mode vanwaaruit ge-werkt wordt. Text mode of Graphics mode. De Text mode heeft voorrang. De ingestelde kleuren blijven behouden.

CLS		Zonder toevoeging. Is al beschreven.
CLS SCREEN	Werkt hetzelfde als CLS zonder toevoeging.
CLS GRAPHICS	Geen effect.
CLS TEXT	Maakt de text viewport schoon en plaatst de cursor in de 		linker 	bovenhoek.
CLS KEY		Maakt de function key viewport schoon.

En nu de Graphics mode.
CLS		Zonder toevoeging. Is al beschreven.
CLS SCREEN  	Werkt hetzelfde als CLS zonder toevoeging.
CLS GRAPHICS	Maakt de Graphics viewport schoon en zet de cursor in de 		linker bovenhoek.
CLS TEXT	Maakt de text viewport schoon en plaatst de cursor in de 		linker bovenhoek.
CLS KEY	      	Maakt de function key viewport schoon.

Zo te zien zijn de verschillen minimaal.
* * * * *
DECLARE. Zodra in QB een procedure of functie wordt geprogrammeerd wordt deze automatisch gedeclareerd. De declaratie komt dan aan het begin van het programma te staan. De procedure is daarna niet meer in het programma te zien, maar kan wel voor verdere bewerking weer ge-edit worden. Dat is een verhaal apart dat geen uitleg behoeft. In PB blijven procedures altijd beschikbaar in het programma en kunnen zowel voor als achterin geplaatst worden. Declaraties zijn echter onder bepaalde voorwaarden toch wel noodzakelijk. Declaraties moeten met naam en parameters gedefinieerd worden indien ze in een als assembly in een externe object (.OBJ) file geplaatst zijn. Zo ook in een UNIT file. De declaraties hoeven per definitie niet in het hoofdprogramma te staan. Ze kunnen als een lijst in een subprogramma staan, die dan doormiddel van $LINK aan het programma toegevoegd worden. Als echter een geassembleerde procedure of een prcedure in een UNIT niet gedeclareerd wordt kan deze niet opgeroepen worden en dus ook niet functioneren. Het programma zal, al bij het compileren, stoppen met een ERROR 519, Missing declaration.
* * * * *
DECR en INCR. Hiermee kan de waarde van een integer variabele verlaagd of verhoogd worden met een of met een waarde naar keuze. Enkele voorbeelden:
INCR a%		' Verhoog a% met 1 (a% = a% + 1)
DECR b%		' Verlaag b% met 1 (b% = b% -1)
INCR c%, 5	' Verhoog c% met 5 (c% = c% + 5)
DECR d%, 7	' Verlaag d% met 7 (d% = d% - 7)
De functies INCR en DECR komen in QB niet voor. De alternatieve oplossingen staan tussen haakjes.
* * * * *
DEFBCD, DEFBYT, DEFDWD, DEFEXT, DEFFIX, DEFFLX, DEFQUD, DEFWRD. Dit zijn functies die alleen in PB voorkomen.

DEFDBL, DEFINT, DEFLNG, DEFSNG, DEFSTR. Dit zijn functies die zowel in QB als in PB voorkomen. Iedereen herkent in een programma wel de functie DEFINT   a-z. Dat wil dan zeggen dat alle nummerieke variabelen die beginnen met een letter van ons alphabet integer variabelen zijn. Het is dan niet meer nodig om achter elke gebruikte variabele het procentteken te zetten. Als aan het begin van uw programma bijvoorbeeld DEFINT a-d staat, dan zijn alle variabelen beginnend met a, b, c of d van het type integer. Ze worden dan in het hele programma herkend als integer variabelen. 'aardig, begin, can, dat' zijn alle vier integer variabelen, alsof er het procentteken (%) achter staat. Dus niet de variabelen die beginnen met een letter van e t/m z. Overigens is dit het meest gebruikte variabele type. Deze regel geldt voor alle bovenstaande functies. U kunt dat naar believe veranderen gedurende in uw programma. Wanneer ook nog aan het begin van uw programma DEFDBL e-h staat dan zijn alle nummerieke variabelen beginnent met e, f, g of h van het type double-precision, dat wil dus zeggen dat u achter even, flink, gaan, hollen, geen dubbel kruis (#) hoeft te zetten. Die beginnen alle vier met een van laatst genoemde letters. Zo kan ik doorgaan met voorbeelden, maar het moet nu wel duidelijk zijn. Overigens kunt u in uw programma,naar believen de typeaanduiding wijzigen. Alle types (voor beide dialecten) op een rijtje;

Varabele type	Indicator DEF type Keyword type
Integer		   %	   DEFINT    INTEGER
Long integer	   &	   DEFLNG    LONG
Double precision   #	   DEFDBL    DOUBLE
Single precision   !	   DEFSNG    SINGLE
String		   $	   DEFSTR    STRING

De indicators zijn overgenomen uit de "Users Guide" van Power Basic. Die zijn voor Quick Basic waarschijnlijk gelijk.

De types uitsluitend voor PB zijn;

Varabele type	  Indicator   DEF type Keyword type
BCD fixed point		@      DEFFIX	  FIX
BCD floating point 	@@     DEFBCD     BCD 
Byte		     	?      DEFBYT	  BYTE 
Word		     	??     DEFDWD	  WORD
Double word	   	???    DEFWRD	  DWORD
Extended precision 	##     DEFEXT	  EXT
Quad integer	     	&&     DEFQUD	  QUAD
Flex string	     	$$     DEFFLX	  FLEX
* * * * *
DELAY. QB kent het DELAY statement niet. In PB wordt het gebruikt voor het pauzeren voor een bepaald aantal secondes of een fractie daarvan. Dit getal wordt aan het statement toegevoegd. Bijvoorbeeld;  DELAY 2.5.
* * * * *
ELSE. In het IF-blok mag in PB achter ELSE geen code staan. Dit in tegenstelling tot QB waar dat wel is toegestaan. Voorbeeld:

PB code	IF x% = 1 THEN
		    PRINT "Iets"
		  ELSE
		    PRINT "Niets"
		  END IF

QB code	IF x% = 1 THEN
		    PRINT "Iets"
		ELSE PRINT "Niets"
		END IF

Het is geen groot verschil, maar toch een waar rekening mee gehouden moet worden.
* * * * *
EXIT. Dit statement kan in PB, zonder toevoeging,  gebruikt worden om een functie of procedure direct te verlaten. In QB zowel als in PB wordt EXIT in diverse structuren op gelijke wijze gebruikt. EXIT DEF, EXIT DO, EXIT FOR, EXIT FUNCTION en EXIT SUB werken in beide dialecten gelijk. EXIT IF en EXIT SELECT kan echter niet in QB, maar wel in PB. Een belangrijk verschil.
* * * * *
EXIT FAR en EXIT FAR AT. Deze statements komen in QB niet voor. EXIT FAR is een manier om snel een stuk code in een lopende procedure te bereiken waar een bepaalde gebeurtenis, bij voorbeeld een fout, wordt afgehandeld, die in een onder de lopende procedure hangende procedure is opgetreden. De lopende procedure kan ook het hoofdprogramma zijn.
Stel in procedure MainProc wordt aan de gebruiker een sleutel gevraagd met behulp waarvan hij een bepaalde toegangscode kan verkrijgen. De bepaling van de toegangscode is heel ingewikkeld en op voorhand kan niet worden bepaald of een bepaalde sleutel geldig is. MainProc roept een procedure aan om vast te stellen of de sleutel geldig is en zo ja, wat de bijbehorende toegangscode is. Die procedure roept weer een andere procedure aan, en die op zijn beurt roept weer andere procedures aan, enzovoort. Er hangt dus een heel wortelstelsel van procedures aan. Stel nu dat in een van die procedures, heel diep onderin het stelsel wordt vastgesteld dat de sleutel niet geldig is. Zonder EXIT FAR zou je nu een foutcode moeten genereren en dan via het hele wortelstelsel van procedures naar boven moeten klimmen om uiteindelijk weer in MainProc aan te komen waar iets met die foutcode gedaan kan worden, bij voorbeeld de gebruiker het nog eens laten proberen. Met EXIT FAR is het veel gemakkelijker. 

(Deze tekst is van Hans Lunsing. Ik ben hem zeer erkentelijk, voor de geboden hulp. Het mailtje dat hij me over dit onderdeel stuurde was bijna twee pagina's groot en daarom te groot voor volledig plaatsing. Het wordt u echter niet onthouden. In de volgende Nieuwsbrief wordt het in zijn geheel afgedrukt).
* * * * *
EXECUTE. Het EXECUTE statement beindigt in PB het lopend programma en start een .EXE, .COM of een .BAT file op. Er blijven geen restanten achter, het nieuw opgestartte programma heeft de beschikking over het totale conventionele geheugen. 
* * * * *
EXTERNAL. EXTERNAL is in een UNIT het equavilent voor PUBLIC. Het laat de compiler weten dat de variabelen buiten de UNIT file, in bijvoorbeeld het hoofdprogramma, zijn gedefinieerd. Het mag duidelijk zijn dat de variabelenlijst achter EXTERNAL de zelfde namen moeten hebben als die in het hoofdprogramma. Het is een goede programmeermethode om, in een aparte file, een lijst te maken van alle variabelen en deze dan doormiddel van $INCLUDE, zowel aan het hoofdprogramma als aan de UNIT file toe te voegen. Dan hoeft u, indien nodig, alleen maar in deze $INCLUDE file iets te veranderen, herbenoemen of te verwijderen. Deze $INCLUDE file hoeft niet de extensie .BAS te hebben. Het mag ook een andere zijn, bijvoorbeeld .INC.
* * * * *
FLUSH. Met FLUSH worden alle data, die in de file-buffer zijn opgeslagen, direct naar disk geschreven. Dit statement sluit niet de file(s) waarin het opereerd. Het kan ook gebruikt worden om de data van alle geopende files meteen naar harde schijf of diskette te schrijven.
* * * * *
Dat is het voor deze keer. Volgend kwartaal komen de resterende statements aan de beurt en de eventuele conversievoorstellen.                                                                                                           J.M.

