HANDLEIDING BIJ SPECTRUM FORTH83 1. ALGEMEEN 1.1 VERANTWOORDING Dit FORTH systeem is geschreven door L.C. Benschop te Eindhoven. Hierbij werd gebruik gemaakt van een assembler en een aantal codedefinities die ontworpen zijn door Coos Haak te Utrecht. Verscheidene high-level definities zijn ontleend aan de FIG-FORTH standaard, het overige is eigen werk, in het bijzonder de screen-editor en alle Spectrum specifieke woorden. Voor een exacte definitie van de FORTH 83 standaard is deze handleiding niet bedoeld. Hiertoe raadplege men: FORTH-83 STANDARD FORTH STANDARDS TEAM P.O. BOX 4545 MOUNTAIN VIEW CA94040 USA waarvan een exemplaar te verkrijgen is bij de FORTH interes- se groep van de H.C.C. 1.2 INLEIDING Deze Forth compiler is geschikt voor ZX-Spectrum 48 en 128, al dan niet voorzien van Microdrive of diskdrive. De volledige FORTH-83 Required Word Set en System Extension Word Set zijn in het programma opgenomen, terwijl de Double Number Extension Word Set en Assembler Word Set zijn bij te laden. Verder zijn er nog uitbreidingen op het gebied van Floating Point Berekening, strings en graphics. Het volledige systeem, al dan niet uitgebreid met een of meer van de genoemde word sets is op tape, disk of Microdrive te bewaren. Het systeem is blokken-geori‰nteerd. Deze blokken of screens worden in een RAM-disk bewaard en kunnen apart of samen van tape, Microdrive of disk worden geladen en daarop worden bewaard. Deze RAM-disk bevindt zich bij de Spectrum 48 in het hoge geheugen en kan in grootte gevarieerd worden. Bij de Spectrum 128 bevindt hij zich in het extra geheugen en is 80K groot. Het systeem is standaard voorzien van een screen-editor, waarmee ook aaneengesloten teksten over meer blokken kunnen worden verwerkt. Er is voorzien in een BREAK toets die FORTH en machinetaal programma's kan afbreken. 1.3 HET LADEN EN BEWAREN VAN FORTH. Op de Spectrum 128 moet FORTH vanuit 128K Basic of Tape Loader van cassette geladen worden. Op de Spectrum 48 gaat het met LOAD "" . Forth start dan vanzelf. Mocht u met een 48K Spectrum werken met een of andere interface of geheugenuitbreiding die op adres 7FFDH werkt en mocht FORTH niet werken, dan moet u het eerste deel van tape laden, op BREAK drukken, de rest inladen met LOAD "" CODE 27028 en dan een wijziging aanbrengen: POKE 30388,250 POKE 30389,111 Daarna starten met RUN 20 Bewaren op tape gaat met 0 DRIVE 60 BCAL Bewaren op disk of Microdrive met: 1 DRIVE 60 BCAL Mocht het al op de disk staan, dan moet men eerst de oude files verwijderen met 1 DRIVE DELETE run DELETE FORT83.BIN Het komt dan op drive nr.1. Van de drive kan het dan weer geladen worden door na het aanzetten van de Spectrum RUN in te typen, op de Spectrum 128 moet dit in 128K Basic. Het kan noodzakelijk zijn dat de load en save commando's in het Basic deel worden aangepast aan het eigen drive systeem. In Basic komt men met de toets SYMBOL SHIFT W en terug in FORTH met RUN. Heeft men uitbreidingen geladen en wil men het systeem bewaren, dan typt men voor het bewaren eerst: HERE FENCE ! Op de 48K Spectrum kan het aantal screens veranderd orden door: N ' #B >BODY ! COLD in te typen, waarbij in plaats van N het aantal gewenste screens wordt getypt. 1.4 SCHERM,TOETSEN EN PRINTER. In FORTH heeft het scherm 24 regels van 32 tekens. Het zal niet na verloop van tijd 'Scroll?' vragen. De Extended Mode van het toetsenbord komt niet voor. De tekens die anders met Extended Mode moesten worden ingetypt, zoals \, { en [ worden met SYMBOL SHIFT getypt. Basic woorden kunnen niet worden ingetypt. DELETE wist het laatst getypte teken. ENTER geeft aan dat de getypte regel klaar is en de commando's moeten worden uitgevoerd. CAPSLOCK werkt normaal en SYMBOl SHIFT W keert terug naar Basic, evenals het commando BYE. Vanuit Basic kan Forth weer gestart worden met RUN. BREAK breekt FORTH programma's af en EDIT wordt gebruikt om DUMP,VLIST en LIST netjes af te breken. Het woord >P stuurt alle uitvoer naar de printer tot dat de volgende regel met commando's moet worden ingetypt. >S stuurt de uitvoer naar het scherm. Heeft men een Spectrum 128 en wil men de ZX-Printer gebruiken, dan typt men eerst ZX-PRINT Wil men de RS232 op Interface-1 gebruiken, dan moet men FORTH verlaten met SYMBOL SHIFT W, aan regel 20 de statements FORMAT "t";9600:OPEN #3,"t" toe voegen voor de RANDOMIZE en RUN 20 typen. Daarna kan het systeem als in 1.3 is beschreven worden bewaard. 1.5 FOUTCONDITIES EN HUN EFFECT. Overal waar in hoofdstuk 3 sprake is van een fout of foutmelding, wordt een foutmelding afgedrukt, darna de naam van het woord in de woordbuffer en daarna wordt ABORT uitgevoerd. Trad de fout op tijdens laden van een screen, dan wordt tevens informatie op de stack achtergelaten, waar in de tekst de fout optrad. Geen foutmelding treedt op bij: -te groot resultaat bij deling of delen door 0. In dit geval is het resultaat -1 -negatief getal indien de standaard positief getal voorschrijft. In dit geval wordt het als een unsigned getal beschouwd. -het manipuleren van de returnstack op een verkeerde manier. Er wordt bij EXIT niet gecontroleerd of het returnadres klopt. Een system-crash ligt in de lijn der verwachting. -Ook EXECUTE controleert niet het adres. -Als WORD geen eind-delimiter vindt. 2. SCREENS EN FILES 2.1 DE RAM-DISK Daar de Spectrum met trage cassettes of de niet erg snelle Microdrive moet kunnen werken, bevinden de FORTH screens zich tijdens het programmeren in een RAM-disk. Op de Spectrum 48 bevindt hij zich in het geheu- gen vanaf het adres in de variabele LO tot adres 65535. Op de Spectrum 128 bevindt hij zich in het extra geheugen en bestaat uit 5 groepen van 16 screens, te weten 1-16,17-32, 33-48,49-64 en 65-80. Het totale aantal screens wordt gegeven door #SCR Na het inladen van FORTH kan de RAM-disk worden geledigd met het commando FORMAT, wat zeker aan te raden is. Met het commando N1 N2 INDEX krijgt men de eerste regel te zien van alle screens van N1 tot en met N2. In verband hiermee is het FORTH programmeurs zeer aan te raden de bovenste regel van ieder screen voor commentaar te gebruiken. 2.2 LADEN EN BEWAREN VAN SCREENS Met het commando N DRIVE kan men de drive selecteren waarvan men screens wil laden e.d. N=0 betekent tape,N=1-8 betekent Microdrive of disk nr. N. Het commando CAT toont de namen van de files die er zijn. Bij tape dient men dit met de spatiebalk af te breken. Met N GET filenaam wordt de gekozen file geladen vanaf screen N. Met N1 N2 PUT filenaam worden de screens N1 tot en met N2 bewaard onder de gekozen filenaam. met behulp van SAVE..CODE. Met DELETE filenaam kan men een file wissen, wat bij Microdrive noodzakelijk is indien men een file wil bewaren met dezelfde naam als een bestaande file die men kwijt wil. BELANGRIJK: Op de Spectrum 128 moeten alle screens die men als een enkele file wil laden of bewaren in dezelfde groep zitten bijv. 15 17 PUT JANTJE mag niet. Wat wel mag is 15 16 PUT JANTJE1 17 17 PUT JANTJE2 Het copi‰ren van files gaat als volgt: 1 Type eerst FORMAT 2 Daarna 1 GET filenaam 3 Dan 1 N INDEX waarbij N het hoogste screen nummer is of 16 bij de Spectrum 128. 4 Kijk wat het hoogste screen nummer is waar nog wat achter staat. 5 Selecteer eventueel een andere drive en plaats de juiste cassette of disk. Eventueel wordt een andere file met dezelfde naam gewist met DELETE filenaam 6 Type 1 M PUT filenaam met M het bij stap 4 gevonden nummer. 2.3 DE EDITOR Met N EDIT wordt de screen editor gestart. Men ziet dan de helft van screen N met een knipperende cursor. Onderaan ziet men het screen nummer en de letter A als de bovenste helft in beeld is en de letter B als de onderste helft in beeld is. De cusor kan verplaatst worden met de cursortoetsen, zijnde CAPS SHIFT 5 t/m CAPS SHIFT 8 op het oude toetsenbord. Altijd is de helft van het screen in beeld waar de cursor staat. In tegenstelling tot veel standaard systemen heeft elk screen 32 regels met 32 tekens. De volgende toetsen hebben binnen de editor een speciale betekenis: EDIT=CAPS 1 verlaat de editor. CAPS LOCk=CAPS 2 als in BASIC. TRUE VIDEO=CAPS 3 Voegt een nieuwe regel in op de plaats van de cursor. De regels daaronder schuiven een plaats naar beneden. De laatste regel verdwijnt. INV VIDEO=CAPS 4 wist de regel waar de cursor op staat. De regels daaronder schuiven een plaats nar boven. De laatste regel wordt leeg. GRAPHICS=CAPS 9 Voegt een spatie in op de plaats van de cursor. De rest van de regel schuift naar rechts. Dreigt er iets van de regel weg te vallen, dan schuift dat door naar volgende regels. DELETE=CAPS 0 Wist het teken ter plaatse van de cursor. De rest van de regel schuift naar links. Dreigt een woord dat over twee regels verdeeld is hierdoor gesplitst te wor- den, dan worden volgende regels meegeschoven. SYMBOL SHIFT Q gaat naar het vorige screen of de vorige helft van het screen. SYMBOL SHIFT E gaat naar het volgende screen of de volgende helft van het screen. Deze beide toetsen geven de mogelijkheid om door de RAM-disk te 'bladeren'. SYMBOL SHIFT W gaat naar de eerste plaats op de eerste regel van het screen. ENTER gaat naar de eerste plaats van de volgende regel. Het woord FILE brengt de editor in een toestand waarin de hele RAM-disk of bij de Spectrum 128 de hele groep screens, als ‚‚n geheel wwordt gezien met betrekking tot invoegen en wissen. Ook de cursortoetsen gaan over de grenzen van het screen. Met BLOCKS worden alle screens als apart beschouwd. 2.4 LADEN VAN PROGRAMMA'S Een programma wordt van een screen geladen met N LOAD Staat op een screen een \ gevolgd door een spatie, dan wordt de rest van de regel als commentaar beschouwd. Een --> laat het laden verder gaan op het volgende screen. Met RUN filenaam kan een file in de RAM-disk geladen worden en meteen als programma worden geladen. Het laden van programma's heeft tot gevolg dat alle tekst op een screen wordt ge‹nterpreteerd alsof hij via het toetsenbord was ingetypt. Vanuit een screen kunnen ook andere screens worden geladen. 3 AANWEZIGE WOORDEN 3.1 STACKNOTATIE De woorden in de lijst staan op ASCII volgorde. Na de naam van het woord komen de eventuele waarden die het woord op de stack verwacht, dan drie mintekens en dan de eventuele waarden die het woord op de stack achterlaat. Een eventuele I geeft aan, dat het woord immediate is, 83 geeft aan dat het woord tot de FORTH83 Required Word Set behoort, S geeft aan, dat het tot de System Extension Word Set behoort, C geeft aan, dat het woord alleen tijdens cmpileren gebruikt mag worden en en D geeft aan, dat het tot de Double Number Extension Word Set behoort, welke niet volledig is geimplementeerd in het kale systeem. De volgende notatie wordt gebruikt voor waarden op de stack: f : 0=onwaar,anders waar true : -1,duidt waar aan false : 0,duidt onwaar aan c : ASCII teken 8b : byte 16b : 16 bits woord. n : getal tussen -32768 en +32767 u : getal tussen 0 en 65535 w : getal tussen -32768 en 65535, betekenis hangt af van interpretatie. addr : geheugen adres Al de voorafgaande stackwaarden nemen ‚‚n plaats op de stack in. 32b : 32 bit woord d : getal tussen -2147483648 en +2147483647 ud : getal tussen 0 en 4294967295 wd : getal tussen -2147483648 en +4294967295, betekenis afhankelijk van interpretatie. Al deze vier waarden nemen twee plaatsen op de stack in beslag. 3.2 DEFINITIES blokbuffer: buffer van 1024 bytes waarin de inhoud van het in gebruik zijnde screen wordt bewaard. colon-definitie: FORTH woord dat gedefinieerd is dmv : De uitvoering van dat woord heeft tot gevolg dat de woorden waaruit de definitie is opgebouwd achtereenvolgens worden uitgevoerd door de inner interpreter. Het adres van waaruit de colon-definitie werd aangeroepen wordt op de return stack bewaard. compilatie adres: het adres, behorende bij een woord, dat tijdens het compileren aan het woordenboek wordt toegevoegd. compileren: het opbouwen van een colon-definitie door het toevoegen van compilatie-adressen en literals aan het woordenboek en het uitvoeren van immediate woorden. counted string: rij ASCII tekens als bytes in het geheugen voorafgegaan door de lengte van die rij. immediate woord: FORTH woord, dat wordt uitgevoerd, ook als de tekstinterpreter bezig is met compileren. inner interpreter: stukje machinecode, dat de afzonderlijke woorden waaruit colon-definities zijn opgebouwd uitvoert. interpreteren: het uitvoeren van de woorden in de invoertekst en het op de stack zetten van getallen indien een woord niet in het woordenboek voorkomt, maar wel een getal voorstelt. invoerbuffer: buffer waar de van het toetsenbord ingetypte regel wordt opgeslagen. invoertekst: tekst die door de tekstinterpreter wordt gelezen, hetzij uit de invoerbuffer, hetzij uit een blokbuffer. literal: speciaal woord in een colon-definitie met een getal erachter, dat, indien uitgevoerd, het getal op de stack zet. loop: een herhalingsstructuur die gebruikt kan worden binnen een colon-definitie, waarbij de eindwaarde (limiet) en een teller (index) op de return stack bewaard worden. numerieke conversie: het omzetten van een getal in een rij ASCII tekens, die dat getal in leesbare vorm voorstelt. return stack: stapel waarop de terugkeeradressen van colon definities, index, limiet en start van een loop en andere waarden op worden bewaard. runtime deel: woord dat door een immediate woord tijdens compileren aan het woordenboek wordt toegevoegd en dat tijdens het uitvoeren van de colon-definitie wordt uitgevoerd. screen blok van 1024 bytes dat meestal FORTH programmatekst bevat. De screens bevinden zich in een RAM-disk. stack: stapel waarop alle berekeningen van FORTH worden uitgevoerd. tekstinterpreter: FORTH woord dat woorden uit de invoertekst leest en afhankelijk van de toestand interpreteert of compileert. user variabele: variabele waarvan het adres zich in een geheugengebied bevindt, waarvan het beginadres veranderd kan worden. Bij multitasking heeft iedere taak zijn eigen uservariabelen. vocabulary: lijst met FORTH woorden, woordenboek: verzameling vocabulary's. Hierin bevinden zich alle FORTH woorden. Beslaat aaneengesloten geheugengebied en wordt aan de bovenkant uitgebreid of ingekrompen. 3.3 WOORDEN IN FORTH VOCABULARY ! 16b addr --- 83 Schrijft 16b in geheugen op adres addr. !CSP --- bewaart de stackpointer in de variabele CSP # ud1 --- ud2 83 gebruikt tussen <# en #> deelt meest rechtse cijfer uit ud1, neemt de ASCII code op in de string dmv HOLD en geeft als resultaat het getal ud1 waar het meest rechtse cijfer af is. #> ud --- addr n 83 beeindigt numerieke conversie, geeft adres en lengte van de string. #B --- n constante, geeft aantal screens op Spectrum 48. #S ud1 --- ud2 83 converteert alle cijfers naar ASCII string dmv # , ud2 is 0. #SCR --- n geeft aantal screens. #TIB --- addr 83 user-variabele die het aantal tekens in de invoerbuffer bevat. ' --- addr 83 leest woord uit de invoertekst, zoekt dit woord in het woordenboek, en geeft het compilatieadres. foutmelding als woord onvindbaar is. 'ERRNUM --- addr user variabele die het adres bevat van het woord dat moet worden uitgevoerd als binnen NUMBER een fout optreedt. ( --- I83 slaat de invoertekst over tot aan ) ,dient als commentaar. (+LOOP) --- w runtime deel van +LOOP. (.") --- runtime deel van ." (;CODE) --- Mag alleen in een colon-definitie voorkomen. Verlaat de colon-definitie en zet het adres achter dit woord in het codeveld van het laatst aangemaakte woord (?DO) w1 w2 --- runtime deel van ?DO (ABORT") f --- runtime deel van ABORT" (DO) w1 w2 --- runtime deel van DO (EMIT) --- addr user-variabele die het adres bevat van het woord, dat EMIT moet uitvoeren. (ERRNUM) f --- Geeft fout als f waar is. 'ERRNUM verwijst hier meestal naar. (FIND) addr1 addr2 --- addr3 n addr2 is naamveld adres van laatste woord in vocabulary. gedraagt zich verder als FIND (FORGET) addr --- addr is het linkveld adres van woord dat vergeten moet worden. Verwijdert dit woord en alle later gedefinieerde woorden uit woordenboek. (KEY) --- addr user-variabele die het adres bevat van het woord, dat KEY uitvoert. (LOOP) --- runtime deel van LOOP (WAIT) --- addr variabele die het adres bevat van het woord dat moet worden uitgevoerd tijdens het wachten in KEY of PAUSE. (WORD) c addr1 --- addr2 addr1 is het adres in de invoertekst, waar wordt begonnen met zoeken naar een woord. Het eerste teken dat ongelijk is aan c is het eerste teken van het woord; de tekens tot aan c behoren tot het woord. addr2 geeft het adres in de invoertekst na het afsluitende teken c. Een byte 0 markeert het einde van de invoertekst. addr2 zal niet hoger worden dan het eindadres van de invoertekst. Het woord komt in de vorm van een counted string op het adres in DP Indien geen woord in de invoertekst werd gevonden, is de lengte 0. Achter de string komt een ASCII spatie. * w1 w2 --- w3 83 vermenigvuldigt w1 met w2. */ n1 n2 n3 --- n4 83 vermenigvuldigt n1 met n2 en deelt door n3. Tussenresultaat heeft dubbele precisie. */MOD n1 n2 n3 --- n4 n5 83 als */ maar geeft n4 als rest van de deling en n5 als quotient + w1 w2 --- w3 83 telt w1 en w2 op +! w addr --- 83 telt w op bij de inhoud van geheugenplaats addr en zet het resultaat daar weer weg. +- n1 n2 --- n3 geeft het tegengestelde van n1 als n2 negatief is, anders n1 +LOOP addr 3 --- IC83 (runtime) w --- sluit een DO LOOP af. telt w op bij de index en eindigt de loop indien daarbij de grens tussen limiet-1 en limiet wodt over- schreden., keert anders terug naar begin van de loop. , 16b --- 83 vergroot het woordenboek met 2 bytes en zet 16b aan het einde. - w1 w2 --- w3 83 trekt w2 af van w1 --> --- I mag alleen in een screen voorkomen. zorgt dat de tekst interpreter verder gaat op volgende screen -1 --- -1 constante -1 -ROT 16b1 16b2 16b3 --- 16b3 16b1 16b2 verplaatst de top van de stapel naar de derde plaats. -TRAILING addr n1 --- addr n2 83 indien de string met adres addr en lengte c1 aan het einde spaties bevat, wordt c1 zo verlaagd, dat de spaties aan het einde wegvallen. . n1 --- 83 drukt het getal n1 af. ." --- IC83 (runtime) --- leest de tekens uit de invoertekst tot aan " en zorgt er voor dat die tekst tijdens runtime wordt afgedrukt. .( --- I83 leest de invoertekst tot aan ) en drukt die meteen af. .R n1 n2 --- drukt n1 af zo dat de totale lengte minstens n2 is. Indien nodig woden links spaties toegevoegd. .S --- drukt de inhoud van de stack af zonder de stack te veranderen. / n1 n2 --- n3 83 deelt n1 door n2. n3 wordt altijd nar beneden afgerond. /MOD n1 n2 --- n3 n4 83 deelt n1 door n2. n3 is de rest en heeft hetzelfde teken als n2, n4 is het quotient en wordt naar beneden afgerond ( niet naar de 0 toe). 0 --- 0 constante 0 0< n1 --- f 83 f=true als n1 negatief is, anders false 0= n1 --- f 83 f=true als n1 0 is, anders false 0> n1 --- f 83 f=true als n1 positief is, anders false 1 --- 1 constante 1 1+ w1 --- w2 83 telt 1 bij w1 op 1- w1 --- w2 83 trekt 1 van w1 af 2 --- 2 constante 2 2! 32b addr --- 83 schrijft 32b op adres addr 2* w1 --- w2 vermenigvuldigt w1 met 2 2+ w1 --- w2 83 telt 2 bij w1 op 2- w1 --- w2 83 trekt 2 van w1 af 2/ n1 --- n2 83 deelt n1 door 2 2@ adr --- 32b 83 leest 32b uit geheugen van adres addr 2DROP 32b --- D verwijdert 32b van stack 2DUP 32b --- 32b 32n D dupliceert 32b op stack 2OVER 32b1 32b2 --- 32b1 32b2 32b1 D dupliceert tweede element op stack. 2SWAP 32b1 38b --- 32b2 32b1 D verwisselt de bovenste twee elementen. 2ROT 32b1 32b2 32b3 --- 32b2 32b3 32b1 D verplaatst derde element naar top van stack. 3 --- 3 constante 3 : --- I83 mag niet tijdens compileren gebruikt worden. leest een woord uit de invoertekst, maakt in het woordenboek een nieuwe colon-definitie aan met die naam, die nog niet af is en nog niet gevonden kan worden. schakelt interpreter over naar compilatietoestand. De CONTEXT vocabulary wordt de CURRENT. ; --- I83 mag alleen tijdens compileren gebruikt worden. Besluit colon-definitie door het woord EXIT in het woordenboek te zet- ten, het laatst gedefinieerde woord vindbaar te maken en door de interpreter in de interpretatietoestand te brengen. < n1 n2 --- f 83 f=true als n1 kleiner is dan n2, anders false n1 n2 --- f 83 f=true als n1 groter is dan n2, anders false. >< 16b1 --- 16b2 verwisselt de bytes van 16b1 >BODY addr1 --- addr2 83 zet compilatie-adres om in parameterveld-adres. >IN --- addr 83 user-variabele die de positie gerekend vanaf het begin van de invoerbuffer of blokbuffer bevat, waar de tekstinterpreter het volgende woord zal lezen. >MARK --- addr S wordt uitgevoerd tijdens compileren door woorden ald IF. maakt ruimte voor een sprong adres en markeert de plaats waar dit adres later moet worden ingevuld. >NAME addr1 --- addr2 zet compilatie-adres om in naamveld-adres. >P --- zorgt ervoor dat alle uitvoer naar de printer gaat, totdat >S wordt uitgevoerd of een noeuwe regel moet worden ingetypt. >R 16b --- 83 bewaart 16b op returnstack. >S --- zorgt ervoor at alle uitvoer naar het scherm gaat. >RESOLVE addr --- S wordt uitgevoerd tijdens compileren door woorden als THEN. vult het adres HERE in op de plaats waar >MARK een sprongadres gemarkeerd had. ? addr --- drukt het 16 bits getal op adres addr af. ?BRANCH f --- S kan alleen in colon-definitie voorkomen. Er achter staat een adres. Springt als f=false ?COMP --- geeft foutmelding indien niet in compileer-toestand. ?CSP --- geeft foutmelding indien de inhoud van de variabele CSP ongelijk is aan de stackpointer. wordt gebruikt om bij ; te controleren of alle structuren compleet zijn. ?DO --- addr 3 (runtime) w1 w2 --- geeft de start van een loop aan. De index wordt w2,de limiet w1 De loop wordt in zijn geheel overgeslagen als w1=w2. ?DUP 16b --- 16b 16b of 16b 83 dupliceert 16b op de stack als 16b geen 0 is. ?EXEC --- geeft een foutmelding indien niet in interpretatietoestand. ?LOADING --- geeft een foutmelding indien de invoertekst in de invoerbuffer zit. ?PAIRS 16b1 16b2 --- geeft een foutmelding indien 16b1 ongelijk aan 16b2. wordt gebruikt omte controleren of IF .. THEN etc. constructies op de goede wijze worden gebruikt. ?STACK --- geeft een foutmelding indien de stack te vol is of van de stack meer is afgehaald dan er ooit is opgezet. ?TERMINAL --- f f=true als de EDIT toets is ingedrukt, anders false. @ addr --- 16b 83 leest 16b uit geheugen van adres addr. ABORT --- 83 ledigt alle stacks en start FORTH in een gedefinieerde toestand door WARM uit te voeren ABORT" --- IC83 (runtime) f --- leest de invoertekst tot aan " en geeft tijdens runtime die tekst als foutmelding indien f=true. ABS n --- u 83 geeft absolute waarde van n ADDR n1 --- addr geeft het adres van screen n1 en schakelt bij de Spectrum 128 de juiste geheugenbank in. ALLOT n --- 83 breidt het woordenboek met n bytes uit of krimpt het in als n negatief is. geeft foutmelding als er te weinig geheugen is of te veel van het woordenboek verloren dreigt te gaan. AND 16b1 16b2 --- 16b3 83 geeft de bitgewijze en-functie van 16b1 en 16b2. AT u1 u2 --- zet cursor op regel u1 en kolom u2. B/BUF --- 1024 constante geeft aantal bytes in blokbuffer. B/SCR --- 1 constante geeft het aantal blokbuffers per screen. BANK n --- schakelt geheugenbank n op het adresgebied C000H-0FFFFH. 0 BANK normaal geheugen, 1-5 extra gehegen Spectrum 128. BASE --- addr 83 user-variabele die het talstelsel bevat, dat gebruikt wordt bij numerieke conversie, het afdrukken van getallen of het inlezen van getallen uit de invoertekst. BCAL n --- springt naar regel n van BASIC programma. met BAsIC statement RANDOMIZE USR 27036 keert men terug naar zelfde plaats in FORTH. Indien BASIC de onderste schermregels gebruikt heeft, moet daarna het statement PRINT; gebruikt worden. BEGIN --- addr 1 IC83 geeft begin van BEGIN..UNTIL lus of BEGIN..WHILE..REPEAT aan. BL --- 32 constante ASCII code voor spatie BLK --- addr 83 user-variabele die aangeeft van welk screen de invoertekst komt. is 0 als invoertekst van invoerbuffer komt. BLANK addr u --- vult geheugengebied beginnend op adres addr ter lengte u met spaties. BLOCK n --- addr 83 zorgt dat screen n in de blokbuffer staat en geeft het adres van die buffer. een eventueel ander screen in de buffer wordt eerst op RAM-disk gezet. BLOCKS --- 83 brengt de editor in een toestand dat alle screens aparte stukken tekst bevatten. BRANCH --- S als ?BRANCH maar springt onvoorwaardelijk. wordt gecompileerd door ELSE en REPEAT. BS --- drukt een backspace af. BUFFER n --- addr 83 maakt een lege blokbuffer voor screen n en geeft het adres. BYE --- keert terug naar BASIC. dit is altijd 48K BASIC, maar de computer kan het extra geheugen op de Spectrum 128 nog adresseren. C! 8b addr --- 83 schrjft 8b in geheugen op adres addr. C, 8b --- breidt het woordenboek uit met 1 byte en zet 8b in op die extra plaats. C/L --- u geeft het aantal tekens per regel. C@ addr --- 8b 83 leest 8b uit geheugen van adres addr. CAP --- schakelt de CAPSLOCK aan of uit. CAT --- toont de namen van de files op de disk, cartridge of tape. in het laatste geval met BREAK-toets stoppen. CHAN n --- kiest een uitvoerkanaal, 2 is scherm, 3 is printer. CLEAR n --- vult screen n met spaties. CLS --- maakt scherm schoon. CMOVE addr1 addr2 u --- 83 verplaatst geheugengebied beginnend op adres addr1 ter lengte u naar addr2, waarbij de byte op adres addr1 als eerste verplaatst wordt. CMOVE> addr1 addr2 u --- 83 als CMOVE, maar nu wordt de byte op adres addr1 als laatste verplaatst. COLD --- koude start van FORTH. verwijdert alle woorden uit het woordenboek boven FENCE, controleert of het extra geheugen adresseerbaar is en stelt de variabele LO overeenkomstig in. initialiseert alle relevante user-variabelen. COMPILE --- 83 mag alleen in een colon-definitie voorkomen die immediate is. voegt het adres dat achter dit woord in het woordenboek staat aan het woordenboek toe. CONSTANT 16b --- 83 (runtime) --- 16b leest een woord uit de invoertekst en maakt een constante met die naam en de waarde 16b. CONTEXT --- addr S user-variabele die het adres van de vocabulary bevat, die als erste doorzocht wordt. CONVERT ud1 addr1 --- ud2 addr2 83 leest ASCII tekens vanaf adres addr1+1. indien dit teken een cijfer voorstelt, wordt ud1 met de inhoud van BASE vermenigvuldigd en wordt het cijfer erbij opgeteld. anders eindigt CONVERT. addr2 is het adres van het eerste teken dat geen cijfer is. zet ASCII string om in getal COPY n1 n2 --- kopieert screen n1 naar n2. COUNT addr1 --- addr2 n 83 n is de byte op adres addr1, addr2 is addr1+1 wordt gebruikt om adres en lengte van en counted string te bepalen. CR --- 83 drukt een return en newline af. CREATE --- 83 (runtime) --- addr leest een woord uit de invoertekst en makt een nieuw woord in het woordenboek zonder daar ruimte voor data bij te reserveren. Dit geschiedt met ALLOT. geeft tijdens runtime het adres van die eventuele ruimte. CSP --- addr uservariabele die de waarde van de stackpointer bevat bij de laatste : CURRENT --- addr S user-variabele die het adres bevat van de vocabulary waar nieuwe woorden an worden toegevoegd. D+ wd1 wd2 --- wd3 83 telt wd1 en wd2 bij elkaar op. D+- d1 n --- d2 d2 is het tegengestelde van d1 als n negatief is, anders d1. D- wd1 wd2 --- wd3 D trekt wd2 van wd1 af. D. d --- D drukt d af. D.R d u --- D als .R maar nu met dubbel precisie getal. D0< d --- f D f=true als d negatief is, anders false. D0= 32b -- f D f=true als 32b nul is, anders false. D< d1 d2 --- f 83 f=true als d1 kleiner dan d2, anders false. DABS d1 --- ud1 D geeft de absolute waarde van d. DECIMAL --- 83 maakt de variabele BASE gelijk aan 10. DEFINITIONS --- 83 maakt de CURRENT vocabulary gelijk aan de CONTEXT vocabulary DELETE --- leest woord uit invoertekst en verwijdert de file met die naam. DEPTH --- n 83 geeft aantal getallen op de stack. DIGIT c --- u true of false zet ASCII teken c om in cijfer u en geef een true vlag en geef alleen een false vlag als c geen cijfer is. DLITERAL 32b --- I als literal, maar dan met dubbel getal. Er wordt 2 maal LIT gevormd. DNEGATE d1 --- d2 83 berekent het tegengestelde van d DO --- addr 3 83 (runtme) w1 w2 --- geeft de start van een loop aan. w2 is de index, w1 is de limiet. als w1=w2, dan wordt de loop 65536 maal doorlopen. DOES> --- IC83 (runtime) --- (runtime van gecreeerde woord) --- addr komt voor in woord dat CREATE bevat. Tijdens compileren wordt (;CODE) en een machinecodeinstructie die een colon-definitie aanroept gecompileerd. Tijdens de uitvoering wordt het codeveld van het zojuist door CREATE aangemaakte woord aangepast en wordt de colon-definitie verlaten. Tijdens de runtime van het zojuist aangemakte woord wordt het parameterveld-adres op de stack gezet en wordt de colon-definitie voorbij DOES> aange- roepen. DP --- addr 83 variabele die 1 mer dan het hoogste adres van het woordenboek bevat. DPL --- addr user-variabele die de plaats van de punt in het laatste door NUMBER ingelezen getal beat, gerekend vanaf rechts. Bevat -1 indien er geen punt in het getal zat. DRIVE n --- slecteert het massa-opslagmedium. n=0 is tape, n=1-8 is drive nr. n DROP 16b --- 83 verwijdert 16b van de stack. DUMP addr u --- toont de inhoud van het geheugengebied vanf adres addr ter lengte u in hexadecimale en ASCII vorm. DUP 16b --- 16b 16b 83 dupliceert 16b op de stack. EDIT n --- start de editor op screen n. EDITOR --- vocabulary met woorden die specifiek zijn voor de editor. ELSE addr1 2 --- addr2 2 IC83 komt voor in IF..ELSE..THEN constructe. woorden tussen ELSE en THEN worden alleen uitgevoerd als de vlag bij IF false is. EMIT c --- 83 drukt teken met ASCII code c af, gebruikmakend van het woord gespecificeerd in (EMIT). EMPTY-BUFFERS geeft aan dat de blokbuffer geen relevante informatie meer bevat. ERASE addr u --- vult geheugengebied beginnend op adres addr ter lengte u met byte 0. EXECUTE addr --- 83 voert het woord met compilatieadres addr uit. EXIT --- 83 verlaat de colon-definitie waar het woord in voorkomt. indien het tijdens interpretatie voorkomt, wordt interpretatie van dat screen gestaakt. EXPECT addr u --- 83 leest u tekens van het toetsenbord, die getoond worden op het scherm, vanaf adres addr speciale toetsen zijn hetzelfde als bij intypen van commando's. FENCE --- addr variabele die het adres bevat waarbeneden niets meer uit het woordenboek wordt verwijderd en vanaf waar COLD het woordenboek afbreekt. moet een link-veld-adres bevatten. FILE --- brengt de editor in een toestand waarbij de hele RAM-disk, of groep van 16 screens daarvan, wordt opgevat als een en dezelfde tekst. FIND addr1 --- addr2 n 83 addr1 is het beginadres van een counted string, die het te zoeken woord bevat. zoekt woord eerst in CONTEXT vocabulary, daarna in CURRENT vocabulary. addr2 is het compilatie-adres van dat woord, indien het woord is gevonden, anders het adres van die string. n=0 als het woord niet is gevonden, n=1 als het woord immediate is en n=-1 anders. FIRST --- addr 83 geeft het eerste adres van de blokbuffer. FLUSH --- 83 brengt de inhoud van de blokbuffer over naar RAM-disk als hij een screen bevat en geeft daarna aan dat hij leeg is. FORGET --- 83 leest een woord uit de invoertekst en verwijdert het woord met die naam en alle later gedefinieerde woorden uit het woordenboek. Foutmelding indien woord niet is te vinden of indien een woord beneden FENCE dreigt te verdwijnen. FORMAT --- vult de gehele RAM-disk met spaties. FORTH --- I83 vocabulary die al deze woorden bevat. Alle andere vocabularies zijn uiteindelijk gekoppeld aan FORTH. FORTH-83 --- 83 laat zien dat dit systeem FORTH-83 is. GET n --- leest een woord uit de invoertekst en leest de file met die naam van het massaopslagmedum, op screen n en volgende. GETFN u1 u2 --- leest een woord uit de invoertekst en zet dat in de BASIC-variabele A$. n1 komt in de BASIC-variabele I en n2 in de BASIC-variabele J. H. u --- drukt u af in vier hexadecimale cijfers. HERE --- addr 83 geeft het eerste adres voorbij het woordenboek. HEX --- maakt BASE gelijk aan 16. HLD --- addr user-variabele die het adres bevat waarbeneden het eerstvolgende cijfer bij numerieke conversie terechtkomt. HOLD c --- 83 voegt teken c aan de string van numerieke conversie toe. I --- w 83 geeft de index van de binnenste loop. I' --- w geeft de limiet van de binnenste loop. ID. addr --- addr is een naamveld adres. drukt de bijbehorende naam af. IF --- addr 2 IC83 (runtime) f --- komt voor in IF..THEN of IF..ELSE..THEN. de woorden tussen IF en ELSE of IF en THEN worden alleen uitgevoerd als f=true. IMMEDIATE --- 83 maakt laatst gedefinieerde woord immediate. INDEX n1 n2 --- toont de eerste regels van de screens n1 t/m n2. INKEY --- c c=0 als geen toets is ingedrukt en de ASCII code van de toets als er wel een is ingedrukt. INTERPRET --- de tekstinterpreter. leest woorden uit de invoertekst tot het einde daarvan en interpreteert of compileert. Getallen met een . erin worden beschouwd als 32-bits getallen. J --- w geeft de index van de op een na binnenste loop. KEY --- c 83 leest een teken in van het toetsenbord en c is de ASCII code. Gebruikt (KEY). LATEST --- addr geeft het adres van het laatst gedefinieerde woord. LEAVE --- 83 verlaat de loop. de returnstack wordt schoongemaakt. LIMIT --- addr 83 het adres juist boven de blokbuffer. LIST n --- drukt de inhoud van screen n af. LIT --- 16b komt alleen in colon-definitie voor met daarachter een getal. zet dat getal op de stack. wordt gecompileerd door LITERAL. LITERAL 16b --- niets of 16b I83 indien de interpreter in compilatietoestand is, wordt 16b als literal gecompileerd. LLIST n1 n2 --- drukt de screens n1 t/m n2 op de printer af. LO --- addr variabele die het onderste adres van de RAM-disk bevat. LOAD n --- 83 geeft het screen n aan de tekstinterpreter als invoertekst en keert terug op het punt in de invoertekst na LOAD als het screen is geladen. LOOP addr 3 --- IC83 geeft het einde aan van een loop de index wordt met 1 verhoogd en indien hij gelijk wordt aan de limiet, dan wordt de loop beeindigd, anders wordt teruggesprongen naar net begin. MAX n1 n2 --- n3 83 n3 is de grootste van n1 en n2. M* n1 n2 --- d n1 wordt vermenigvuldigd met n2 met een 32-bits produkt. M/ d n1 --- n2 n3 deelt d door n1 met n2 als rest en n3 als quotient. dezelfde afrondingsregels als bij /MOD worden gehanteerd. M/MOD ud1 u1 --- u2 ud2 deelt ud1 door u1 met u2 als rest en ud2 als quotient. MIN n1 n2 --- n3 83 n3 is de kleinste van n1 en n2. MIR 16b1 16b2 16b3 --- 16b3 16b2 16b1 verwisselt top met derde op stack. MOD n1 n2 --- n3 83 berekent de rest als n1 door n2 wordt gedeeld. MTYPE addr u --- snelle versie van TYPE die niet gebruik maakt van (EMIT). NAME> addr1 --- addr2 zet naamveld-adres om in compilatie-adres. NEGATE n1 --- n2 83 berekent het tegengestelde van n1. NOOP --- doet niets. NOT 16b1 --- 16b2 83 berekent het 1-complement. NUMBER addr --- wd zet een string beginnende op adres addr+1 en eindigend met een spatie om in het bijbehorende getal. de variabele DPL bevat de plaats van een eventuele punt of -1. als de string met & begint, wordt de ASCII-code van het tweede teken genomen. indien de string geen getal voorstelt, wordt via de variabele 'ERRNUM een procedure uitgevoerd die een foutmelding geeft. OR 16b1 16b2 --- 16b3 83 berekent bitsgewijze of-functie van 16b1 en 16b2 OUT --- addr user-variabele die de positie op de regel van EMIT bevat. wordt op nul gezet door CR, wordt met 1 verhoogd door EMIT. OVER 16b1 16b2 --- 16b1 16b2 16b1 83 dupliceert tweede waarde op stack. P! 8b addr --- stuurt 8b naar outputpoort op adres addr. P@ addr --- 8b leest 8b van inputpoort op adres addr. PAD --- addr 83 geeft het adres van een 64 byte buffer waarin o.a. met strings kan worden gewerkt. PAUSE u --- wacht u vijftigsten van seconden. voer ondertussen het woord uit, waarvan het adres in de variabele (WAIT) zit. PICK u --- 16b 83 haalt de waarde op plaats u op de stack naar boven waarbij u=0 de top van de stack is u=1 het tweede getal etc. De waarde blijft ook op zijn oorspronkelijke plaats staan. PKEY --- c wacht tot een toets is ingedrukt en geeft ASCII code. PUT n1 n2 --- leest een woord uit de invoertekst en schrijft de screens n1 t/m n2 naar het massaopslagmedium onder die naam. QUERY --- leest tot 128 tekens van het toetsenbord dmv EXPECT in de invoerbuffer en zet BLK en >IN op nul. van tevoren wordt ervoor gezorgd dat scherm en toetsenbord gebruikt worden. QUIT --- 83 leegt de retrun stack, leest regels in va het toetsenbord en gaat die interpreteren. R> --- 16b 83 haalt 16b van return stack. R0 --- addr user-variabele die de het hoogste adres van de returnstack bevat. R@ --- 16b 83 leest 16b van de returnstack, zonder deze te verwijderen. REPEAT addr1 addr2 4 --- 83 geeft het einde van een BEGIN..WHILE..REPEAT constructie aan. keert terug naar de plaats van BEGIN. ROLL u --- 83 haalt de waarde op plaats u op de stack naar boven, zoals PICK, maar verwijdert die waarde van zijn oorspronkelijke plaats. ROT 16b1 16b2 16b3 --- 16b2 16b3 16b1 83 haalt de derde waarde op de stack naar boven. RP! --- initialiseert de returnstackpointer. RP@ --- addr geeft de waarde van de returnstackpointer. RUN --- leest een woord uit de invoertekst en laadt de file met die naam vanaf screen 1, waarna screen 1 wordt geladen. S->D n --- d zet enkele precisie getal om naar dubbele precisie. S0 --- addr user-variabele die de bodem van de stack bevat. SAVE-BUFFERS --- 83 bewaart de inhoud van de blokbuffer in de RAM-disk als die een screen bevat. SCR --- addr user-variabele die het nummer van het laatst geliste screen bevat. SIGN n --- 83 voegt een - aan de numerieke conversie string toe indien n negatief is. SMUDGE --- maakt het laatst gedefinieerde woord vindbaar danwel onvindbaar voor FIND. SP! --- initialiseert de stackpointer. SP@ --- addr geeft de stackpointer. SPACE --- 83 drukt een spatie af. SPACES u --- 83 drukt u spaties af. SPAN --- addr 83 user-variabele die het aantal tekens bevat, dat bij de laatste EXPECT is gelezen. STATE --- addr 83 user-variabele die de toestand van de tekstinterpreter bevat, 0 is interpreteren, anders compileren. STOPOFF --- schakelt de BREAK toets uit. STOPON --- schakelt de BREAK toets in. STYPE addr u --- drukt u tekens af te beginnen op adres addr, waarbij het hoogste bit genegeerd wordt en control characters als punt worden afgedrukt. SWAP 16b1 16b2 --- 16b2 16b1 83 verwisselt de bovenste twee elementen op de stack. TCH c --- drukt teken met ASCII code c op scherm of printer af. TERMINAL --- zorgt ervoor dat de invoer van het toetsenbord komt en de uitvoer naar het scherm gaat. THEN addr 2 --- IC83 geeft einde van IF..ELSE..THEN of IF..THEN constructie aan. TIB --- addr 83 constante het eerste adres van de invoerbuffer. TOGGLE addr 8b --- de bits op geheugenplaats addr die corresponderen met de 1-bits in 8b worden gecomplementeerd. TRAVERSE addr1 n --- addr2 telt net zo lang n bij addr op tot bit 7 van de byte op dat adres 1 is. TYPE addr u 83 drukt u tekens af, te beginnen op adres addr, waarbij (EMIT) wordt gebruikt. U. u --- 83 drukt u af. U< u1 u2 ---f 83 f=tru als u1 kleiner is dan u2, anders false. UM* u1 u2 --- ud 83 vermenigvuldigt u1 en u2, met een dubbel precisie resultaat. UM/MOD ud u1 --- u2 u3 83 deelt ud door u1 met u2 als rest en u3 als quotient. UNDER 16b1 16b2 --- 16b2 verwijdert het tweede element van de stack. UNTIL addr 1 --- IC83 (runtime) f --- geeft het einde van een BEGIN..UNTIL constructie aan. als f=false, dan wordt teruggesprongen naar het begin, anders wordt doorgegaan. UPDATE --- 83 geeft aan dat een blokbuffer gewijzigd is en dus teruggeschreven moet worden naar disk. Bij dit systeem wordt altijd teruggeschreven, daar het een snelle RAM-disk betreft. USER n --- (runtime) --- addr leest een woord uit de invoertekst en maakt een user-variabele met die naam, die op een adres n vanaf het begin van de user-area zit. Geeft tijdens runtime het adres. VARIABLE --- 83 (runtie) --- addr leest een woord uit de invoertekst en maakt een variabele met die naam. Geeft tijdens runtime het adres, waar een 16-bits waarde kan worden bewaard. VLIST --- toont alle woorden in de CONTEXT vocabulary voorafgegaan door hun naamveld adres. VOC-LINK --- addr user-variabele die een pointer naar een lijst bevat, die alle vocabulary's met elkaar verbindt VOCABULARY --- 83 leest een woord uit de invoertekst en maakt een vocabulary met die naam, die reeds de woorden uit de CONTEXT vocabulary bevat. Elke vocabulary bevat dus FORTH. Maakt tijdes runtime de CONTEXT vocabulary de opgegeven vocabulary. WHERE n1 n2 --- n1 is het screennummer, n2 de waarde van >IN toen een fout optrad tijdens laden van het screen. deze blijven na een fout achter op de stack. de editor wordt gestart met de cursor op de plaats van de fout. WHILE addr1 1 --- addr2 4 IC83 (runtime) f --- komt voor in een BEGIN..WHILE..REPEAT constructie. Als f=false, dan wordt gesprongen tot voorbij REPEAT, zodat de herhaling tussen BEGIN en REPEAT eindigt. WIDTH --- addr user-variabele die het maximale aantal tekens bevat, die van de naam van een nieuw woord worden onthouden. normaal 31 WORD c ---addr 83 leest een woord uit de invoertekst, te beginnen bij het eerste teken ongelijk aan c en eindigend bij c, gebruikmakend van (WORD). addr is het eerste adres van de counted string die het woord bevat, zijnde HERE. XOR 16b1 16b2 --- 16b3 83 bitsgewijze exclusieve of van 16b1 en 16b2. ZX-PRINT --- maakt de Spectrum 128 geschikt voor de ZX-Printer. [ --- I83 schakelt de tekst-interpreter in interpreteer-toestand. ['] --- IC83 leest een woord uit de invoertekst, zoekt dit op en compileert het compilatie-adres als een LITERAL. [COMPILE] --- IC83 leest een woord uit de invertekst, zoekt dit op en compileert het, ook als het IMMEDIATE is. ] --- 83 zet de tekstinterpreter in de compileer-toestand. \ --- mag alleen op een screen voor komen. slaat de rest van de regel over. 3.4 DE EDITOR VOCABULARY CUR --- zet de knipperende cursor aan of uit. DEL --- wist een teken. DN --- gaat een plaats naar beneden HO --- addr variabele horizontale cursorpositie. HOME --- zet cursor aan begin van screen. INS --- voegt een teken in. LDEL --- wist een regel. LE --- gaat een plaats naar links. LIM --- addr 1 meer dan laatste adres tekst. LINS --- voegt een regel in. LPOS --- addr adrs in tekst van begin regel. LREST --- u aantal tekens op scherm vanaf cursor regel. LST --- drukt scherm af. PD --- gaat half screen naar beneden. POS --- addr geeft adres in tekst. PU --- gaat half screen naar boven. REST --- u geeft aantal tekens op scherm vanaf cursor. RI --- gaat een plaats naar rechts. SADR --- addr geeft adres begin screen of blokbuffer. SET --- zet printpositie op plaats van cursor. TXT --- addr variabele die aangeeft of de RAM-disk aaneengesloten is. UP --- gaat regel naar boven. VE --- addr variabele verticale positie van cursor. 4 OPBOUW VAN DE COMPILER 4.1 DE INNER INTERPRETER. De inner interpreter werkt met direct threaded code, dat wil zeggen, dat de adressen waaruit een colon-definitie is opgebouwd directe sprongadressen zijn. Derhalve staat in het codeveld van ieder FORTH woord een stukje machinecode. Bij codedefinities is dit het begin van de codedefinitie zelf, bij constanten, variabelen, colon-definities en user-variabelen is dit een subroutine-call naar een bijbehorende runtime-routine. Bij DOES> definities is dit een subroutine call naar het adres achter (;CODE), waar een call-instructie naar de subroutine voor colon-definities staat. De eerste call zorgt voor het op de stack zetten van het parameterveld adres, terwijl de tweede voor interpretatie van de colon-definitie na DOES> zorgt. In alle gevallen zorgt de call-instructie ervoor, dat het parameterveld-adres op de stack eenvoudig bereikbaar is. Iedere codedefinitie zorgt door een JP (IX) instructie voor de interpretatie van het volgende adres. De instruction pointer is DE. De FORTH stackpointer is SP. Het adres van NEXT zit in IX. De returnstackpointer zit op adres 69A7H, de pointer naar de user-area op adres 6994H. Het W-register is niet nodig; dit komt door de call op de stack terecht. De BREAK-toets wordt bekeken door de interruptroutine in interruptmode 2. 4.2 DE HEADERSTRUCTUUR De woorden in dit Forth systeem bestaan uit 4 velden, dit zijn: -linkveld :hierin staat het naamveld adres van het vorige woord of 0. Altijd 2 bytes. -naamveld :de eerste byte bevat bit 7: altijd 1 bit 6: immediate bit 5: smudge 1 indien niet vindbaar bit 4-bit 0:lengte naam. De volgende bytes bevatten de tekens die van de naam zijn onthouden, de laatste heeft bit 7 =1. -codeveld :call instructie. altijd 3 bytes. -parameterveld: bevat alle informatie die dit woord verder nodig heeft. (bij codedefinities is geen apart codeveld of parameterveld te onderscheiden.) 4.3 DE GEHEUGENINDELING. Alle adressen zijn decimaal. 25580: bovenste adres van de datastack. Hierbeneden is ca. 1 kilobyte ruimte. 25600: invoerbuffer,128 bytes 26000: bovenste adres return stack. groeit naar invoerbuffer toe. 272 bytes ruimte. 26000-27027: blokbuffer met zijn markeringen. 27028: user-area pointer. 27030: koude start entry 27033: warme start entry 27036: BCAL return. 27039: begin user-area 60 bytes groot. De plaatsen 48 t/m 59 zijn nog vrij. 27047: returnstackpointer, bevindt zich in user-area. 27099: inner-interpreter. Vanaf hier het woordenboek. 33792: pagina gevuld met 85H, interruptvectortabel. 34136: start interruptroutine. vanaf hier gaat woordenboek verder. HERE=36989: start woordbuffer PAD=HERE+56: vlak boven numerieke conversiebuffer, start stringbuffer. Na PAD komt vrije ruimte. LO @ =55296 op 48K Spectrum. start RAM-disk. Op Spectrum 128 komt dit stuk niet voor. Adressen liggen daar tussen 49152 en 65535 in 5 extra banken. Alleen woorden beneden dit adres mogen rechtstreeks de RAM-disk adresseren. 4.4 BASIC PROGRAMMA Alle tape- en disk bewerkingen gaan via BASIC. Hierbij is de variabele I de start van het blok, J de lengte en D het drivenummer en 0 voor tape. A$ bevat de filenaam. Zie voor gegevens over wijze van aanroepen det woorden BCAL en GETFN in 3.3 regel 1: warme start regel 10: start na inladen. reserveert geheugen en laadt code in. regel 20: koude start. regel 40: DELETE routine. regel 45: CAT routine. regel 50: PUT routine. regel 55: GET routine. regel 60: bewaren van FORTH. 4.5 METACOMPILATIE. De files META1 t/m META4 bevatten de metacompiler waarmee FORTH gereproduceerd kan worden. De werkwijze is als volgt: eventueel DELETE FORT83.BIN RUN META1 RUN META2 RUN META3 RUN META4 Nu wordt FORT83.BIN bewaard. BYE Nu in BASIC GO TO 10 De nieuwe FORTH wordt ingeladen en gestart. RUN EDITOR eventueel DELETE run eventueel DELETE FORT83.BIN 60 BCAL De nieuwe FORTH compleet met BASIC deel en editor wordt bewaard. De file META1 bevat de eigenlijke metacompiler, bestaande uit: -woorden als !-T @-T ,-T die hetzelfde doen als ! @ en , maar hun adressen omrekenen naar het gebied waar het target systeem wordt opgebouwd. -De vocabulary META. De meeste woorden hierin hebben dezelfde nam als normale FORTH woorden en compileren in het target systeem. -de vocabulary TARGET. hierin zitten de IMMEDIATE woorden van het target systeem. -CREATE-T die headers in het target systeem aanmaakt. Verder creeert het definities in de vocabulary META. -de metaforth assembler, die codedefinities in het target systeem maakt. -woorden die de acties verrichten van de immediate woorden in FORTH, maar op het target systeem weken. Die zitten in de vocabulary META De files META2,META3 en META4 bouwen met die compiler een target systeem. De file EDITOR wordt door het nieuwe systteem gebruikt om de editor te maken. Met de metacompiler zijn op source-code niveau wij- zigingen in FORTH aan te brengen op vrijwel elk gebied of er kunnen speciale versies zonder headers en compileerwoorden, die een applicaie bevatten, worden aangemaak. Dergelijke projecten zijn alleen uit te voeren door ervaren FORTH programmeurs. 5 DE ASSEMBLER 5.1 INLEIDING Met de assembler kunnen woorden in machinecode worden gemaakt. Deze handleiding veronderstelt dat u bekend bent met de Z80 en zijn standaard mnemonics. De mnemonics wijken af van die van de standaard assembler om twee redenen: -De standaard assembler gebruikt een en hetzelfde woord als mnemonic voor instructies met een verschillende vertaling, bv LD wordt gebruikt voor LD A,B LD (IX+12),23 LD HL,(RPTR) LD A,I LD SP,HL -Forth is geschikt voor expressies in postfix-notatie. Derhalve is het schrijven van een assembler die de mnemonics na de argumenten verwacht eenvoudig en kunnen er ook expressies gebruikt worden. Labels ontbreken in een FORTH assembler vrijwel geheel en in plaats daarvan worden IF en BEGIN constructies gebruikt zoals ook in FORTH. Deze assembler was ontworpen door Coos Haak te Utrecht voor zijn eigen FORTH en door L.C. Benschop overgedragen naar FORTH83. 5.2 LADEN VAN DE ASSEMBLER De assembler bestaat uit twee files, TASM ter lngte van 1 screen en ASSEMBLER ter lengte van 8 screens Indien u de assembler permanent in FORTH aanwezig wilt hebben om FORTH in die toestand te bewaren, dan typt u: RUN ASSEMBLER Met HERE FENCE ! wordt hij permanent en dan kunt u hem bewaren als beschreven in 1.3 Indien u de assembler tijdelijk nodig heeft, bijv om de Double Number Extension Word Set in te laden, dan tijpt u: RUN TASM Hierdoor wordt de assembler boven in het geheugen geladen en kan hij na gebruik eenvoudig worden weggewerkt met het commando DISPOSE De met de assembler gedefinieerde woorden blijven dan bestaan. 5.3 HET MAKEN VAN CODEWOORDEN Voor het maken van machinecodedefinities staan de volgende woorden ter beschikking. Een A geeft aan, dat het woord tot de Assembler Extension Word Set behoort. Alle woorden zitten in de ASSEMBLER vocabulary, tenzij er F achter staat. Onder de assembleertoestand wordt verstaan: de interpretatietostand met daarbij de ASSEMBLER vocabulary als CONTEXT en BASE op 16. ;c --- F synoniem voor END-CODE ;CODE --- FICA komt in een colon-definitie voor die CREATE bevat. compileert (;CODE) en brengt FORTH in de assembleertoestand. De colon-definitie die dit woord bevat zal tijdens runtime het codeveld van het zojuist gecreeerde woord naar het stukje code achter ;CODE laten verwijzen. Op zijn beurt zal het gecreeerde woord het stukje code uitvoeren met het parameterveld adres op de stack, net als bij DOES> ASSEMBLER --- FA vocabulary waarin alle Assembler mnemonics en dergelijke zitten. CODE --- A leest woord uit invoertekst en maakt een codedefinitie met die naam. brengt FORTH in de assembleertoestand en maakt woord onvindbaar. END-CODE --- FA beeindigt codedefinitie, maakt laatst gedefinieerde woord vindbaar, maakt de CONTEXT gelijk aan de CURRENT vocabulary en maakt BASE gelijk aan 10. Dient als afsluiting voor CODE ;CODE en LABEL ENDM --- IC synoniem voor ; beeindigt macro. LABEL --- F leest woord uit invoertekst een creeert een woord met die naam, dat tijdens runtime zijn parameterveld-adres geeft. brengt FORTH in assembleertoestand. Het nieuwe woord kan dan tijdens assembleren van een ander woord als adres voor sprong of call gebruikt worden. MACRO --- F als : maar maakt ASSEMBLER de context vocabulary en BASE 16. een aantal assembler instructies kunnen zo in een macro worden samengebracht. XY --- addr F variabele die aangeeft welk indexregister gebruikt wordt. DDH voor IX,FDH voor IY 5.4 DE REGISTERS De assembler kent de namen A,B,C,D,E,H en L voor de enkelvoudige registers. De naam M wordt gebruikt in plaats van (HL) en geldt als register. De registerparen hebben de namen B,D en H voor resp. BC,DE en HL en SP en AF. AF mag alleen gebruikt worden bij PUSH en POP, in veel andere gevallen met een registerpaar alleen SP,B,D en H. Indien een indexregister voorkomt anders dan in bijv. (IX+12) dan kan men de instructie vooraf laten gaan door X Zo wordt LD SP,IX vervangen door X LDSP XH en XL kunnen het H of het L register vervangen door het indexregister. Voor instructies met (IX+N) bestan speciale mnemonics beginnende met een ) . Normaal is het indexregister IX. Men kan dit in IY veranderen door %Y en weer in IX door %X 5.5 DE INSTRUCTIESET Een zelfde stacknotatie wordt gebruikt als in hoofdtuk 3 met de volgende toevoegingen: b: bit 0-7 r: register A,B,C,D,E,H,L of M rp: registerpaar B,D of H rps: registerpaar of SP. rpa: registerpaar of AF. disp: displacement tussen -128 en 127 bij IX of IY. LD r1 r2 --- de inhoud van register r1 gaat naar r2. LD r2,r1 )LD r1 disp --- laadt r van adres IX+disp LD r1,(IX+disp) )ST r disp --- scrijft r op geheugenplaats IX+disp LD (IX+disp),r1 LD# 8b r --- laadt r met 8b LD r1,8b )LD# 8b disp --- laadt de geheugenplaats IX+disp met 8b LD (IX+disp),8b MOV rp1 rp2 --- de inhoud van registerpaar rp1 gaat naar rp2. D B MOV wordt LD B,D LD C,E LDP# 16b rps --- laadt registerpaar rps met 16b LD rps,16b LDP addr rps --- laadt registerpaar rps van adres addr. LD rps,(addr) )LDP rps disp --- laadt registerpaar van adres IX+disp. B 2 LDP wordt C 2 )LD B 3 )LD STP addr rps --- schrijft registerpaar rps op adres addr LD (addr),rps )STP rps disp --- schrijft registerpaar op adres IX+disp. B 2 )STP wordt C 2 )ST B 3 )ST LDHL addr --- als LDP maar voor HL register STHL addr --- als STP maar voor HL register. LDA addr --- laadt A van adres addr LD A,(addr) STA addr --- schrijft A op adres addr LD (addr),A LDAP rp --- rp=B of D laadt A vanaf adres in rp LD A,(BC) of LD A,(DE) LD A,(HL) wordt M A LD !!! STAP rp --- rp=B of D schrijft A op adres in rp LD (BC),A of LD (DE),A LD (HL),A wordt A M LD !!! LDSP --- laadt SP met HL. LD SP,HL LDAI --- laadt A met I. LD A,I LDIA --- laadt I met A. LD I,a EXAF --- verwisselt AF en AF'. EX AF,AF' EXDE --- verwisselt DE en HL. EX DE,HL EXSP --- verwisselt HL met element op stack. EX (SP),HL CLR rps --- laadt rps met 0. LD rps,0 ADD r --- telt r op bij accumulator ADD A,r analoog gaan ADC, SUB, SBC, AND, XOR, OR en CP. )ADD disp --- telt inhoud van adres IX+disp op bij accumulator. ADD A,(IX+disp) Analoog gaan )ADC, )SUB, )SBC, )AND, )XOR, )OR en )CP. ADD# 8b --- telt 8b op bij accumulator ADD A,8b Analoog gaan ADC#, SUB#, SBC#, AND#, XOR#, OR# en CP#. ADDP rps --- telt rps op bij HL. ADD HL,rps Analoog gaan ADCP, SUBP en SBCP. rps SUBP is A AND rps SBCP. INC rps --- hoogt registerpaar rps 1 op. INC rps. Analoog gaat DEC. INR r --- hoogt register r 1 op. INC r Analoog gaat DER (DEC r) )INR disp --- hoogt de inhoud van geheugenplaats IX+disp met 1 op. INC (IX+disp) Analoog )DER. RL r --- Roteert register r 1 plaats naar links RL r. Analoog gaan RR, RLC, RRC, SRL, SRA en SLA. )RL disp --- Roteert de inhoud van geheugenplaats IX+disp 1 plaats naar links. RL (IX+disp) Analoog gaan )RR, )RLC, )RRC, )SRL, )SRA en )SLA. BIT b r --- test bit b van register r. BIT b,r. Analoog gaan RES en SET )BIT b disp --- test bit op geheugenplaats IX+disp. BIT b,(IX+disp). Analoog gaan )RES en )SET. TST rp --- test of rp 0 is. B TST is hetzelfde als B A LD C OR JP addr --- springt naar adres addr. Analoog gaan JPNZ, JPZ, JPNC, JPC, JPPO, JPPE, JPP, JPM, CALL, JR, JRNZ, JRZ, JRNC, JRC, DJNZ en RST. addr JPNZ is JP NZ,addr. JPHL --- springt naar het adres in HL Analoog gaat JPIX. CALLC addr cc --- conditionele call naar adres addr cc is de in kleine letters geschreven conditiecode uit 5.6 RETC cc --- conditionele return.cc heeft zelfde betekenis als bij CALLC. PUSH rpa --- zet rpa op stack. PUSH rpa. Analoog gaat POP. PRT --- RST 16H om teken af te drukken. HOOK 8b --- RST 8 DEFB 8b om foutmelding te geven of Interface1 te sturen. IN 8b --- leest accumulator van poort 8b IN A,(8b) Analoog gaat OUT. De instructies NOP, RLCA, RRCA, RLA, RRA, HALT, DAA, CPL, SCF, CCF, DI, HALT, EXX, LDIR, LDDR, CPIR, IM1, EI, IM2 en NEG zijn hetzelfde als in de standaard assembler. Een aantal weinig voorkomende instructies is niet geimplemen- teerd. Zij zijn te maken met , en C, of alsnog te defini‰ren. RPTR, UPTR en NEXT zijn 3 constanten die het adres van de returnstackpointer, het adres van de pointer naar de user-area en het adres van de inner-interpreter voorstellen. 5.6 IF EN BEGIN STRUCTUREN. In de assembler komen de IF..THEN, IF..ELSE..THEN, BEGIN..UNTIL en BEGIN..WHILE..REPEAT constructies van FORTH voor, die met relatieve sprongen worden geimplementeerd. IF, WHILE en UNTIL worden voorafgegaan door een coditiecode, die Z, NZ, CS of NC kan zijn. BEGIN .. NC UNTIL betekent, dat een bepaald stuk herhaald moet worden totdat het carrybit 0 is. Er is dan een JRC instructie aanwezig. Verder zijn er nog BEGIN..AGAIN, dat een herhaling eeuwig laat duren, en BEGIN..DSZ, dat een DJNZ instructie aan het eind van de herhaling plaatst. Dezelfde constructies behalve BEGIN..DSZ kunnen ook met absolute sprongen worden gemaakt. De relevante woorden dienen dan in kleine letters te worden geschreven. De conditiecodes zijn dan z, cs, pe, p en v, waarbij v hetzelfde is als pe. Elk van deze codes kan worden gevolgd door NOT in hoofdletters, dat de tegenovergestelde code aanduidt. 6 DE DOUBLE NUMBER EXTENSION WORD SET 6.1 INLEIDING De file DOUBLE bestaat uit 3 screens en bevat alle woorden, die nodig zijn om de Double Number Extension Word Set volledig te implementeren en daarbij nog woorden die het mogelijk maken alle berekeningen met dubbele precisie te doen, inclusief vermenigvuldigen, delen en worteltrekken. Alvorens DOUBLE te laden moet eerst de assembler geladen worden met RUN TASM of RUN ASSEMBLER Daarna RUN DOUBLE en tenslotte eventueel DISPOSE 6.2 EXTRA WOORDEN 2CONSTANT 32b --- D (runtime) --- 32b als CONSTANT maar nu voor 32-bit waarde. 2UNDER 32b1 32b2 --- 32b2 verwijdert tweede waarde van stack. 2VARIABLE --- D (runtime) --- addr als VARIABLE maar nu met 4 bytes ruimte. D* wd1 wd2 ---wd3 vermenigvuldigt wd1 met wd2. D/ d1 d2 --- d3 deelt d1 door d2. Er wordt naar beneden afgerond. D/MOD d1 d2 --- d3 d4 deelt d1 door d2. d3 is de rest en d4 het quotient. D2* wd1 --- wd2 vermenigvuldigt wd1 met 2 D2/ wd1 --- wd2 D deelt wd1 door 2 D= 32b1 32b2 --- f D f=true als 32b1 en 32b2 gelijk zijn, anders false. D> d1 d2 --- f D f=true als d1 groter dan d2, anders false. DIVISOR --- addr dubbele variabele die de deler bevat bij D/ DMAX d1 d2 --- d3 D d3 is het maximum van d1 en d2. DMIN d1 d2 --- d3 D d3 is het minimum van d1 en d2. DMOD d1 d2 --- d3 d3 is de rest bij deling van d1 door d2. DU. ud --- als D. maar nu voor unsigned getal. DU.R ud u --- alse D.R maar nu voor unsigned getal. DU< ud1 ud2 --- f D f=true als ud1 kleiner is dan ud2, anders false. SQRT ud --- u u is de naar beneden afgeronde vierkantswortel van ud. U.R u1 u2 --- als .R maar nu met unsigned getal. UD/MOD ud1 ud2 --- ud3 ud4 deelt ud1 door ud2. ud3 is de rest en ud4 het quotient. 7 DE FLOATING POINT UITBREIDING 7.1 INLEIDING Met deze uitbreiding kunt u in Forth floating point getallen gebruiken. Deze getallen zijn 32 bits groot en dus kunnen 2@, 2! en de stack bewerkingen voor dubbele precisie getallen ook voor floating point getallen gebruikt worden. Het woord NUMBER is uitgebreid met een mogelijkheid om floating point getallen te verwerken. U kunt floating point getallen nu vanuit de tekstinterpreter invoeren door achter een getal, dat al dan niet een decimale punt bevat een & teken te typen. Achter het & teken kan dan + of - een getal komen, dat aangeeft met welke macht van BASE het getal vermenigvuldigd moet worden. Zo kunnen getallen in wetenschappelijke notatie worden ingevoerd in elk talstelsel. Voorbeelden zijn: 2& het getal 2 -2.718& het getal -2.718 12&+3 het getal 12000 -0.041& het getal -0.041 -4.1&-2 het getal -0.041 De floating point woorden zitten in twee files. De eerste file FLOATING bestaat uit 8 blokken en bevat de basisbewerkingen, woorden om floating point getallen af te drukken, de bovenbeschreven uitbreiding van NUMBER en een worteltrekking. Eerst moet de assembler aanwezig zijn. Deze kan worden geladen met RUN TASM of RUN ASSEMBLER. Daarna kan dde uitbreiding geladen worden met RUN FLOATING. Na afloop eventueel DISPOSE intypen. De twwede file TRANSCEN bevat de trigoniometrische en logaritmische functies. Deze heeft de assembler niet nodig, maar FLOATING moet geladen zijn. TRANSCEN bestaat uit 4 blokken. 7.2 FORMAAT EN NAUWKEURIGHEID. Een floating point getal bestaat uit twee delen. De drie minst significante bytes vormen de mantisse, een 24-bits binair getal tussen 1 en 2. Het eerste bit stelt 1 voor, het tweede 1/2 het derde 1/4 enz. Daar het eerste bit toch altijd 1 is, wordt dit weggelaten en in plaats daarvan komt het tekenbit 0=positief, 1 is negatief. Het meest significante byte is de exponent, de macht van 2, waarmee de mantisse vermenigvuldigd is plus 128. Het grootste negatieve getal en het kleinste positieve getal stellen per definitie nul voor. Dus het floating point getal nul wordt voorgesteld door alle bits 0. Het grootste positieve getal en het kleinste negatieve getal stellen + of - oneindig voor. Deze getallen komen uit berekeningen waar te grote getallen uitkomen of die onmogelijk zijn (delen door nul). De floating point getallen hebben een nauwkeurigheid van ongeveer 7 cijfers. De getallen 38 -39 -39 38 zijn tussen -3x10 en -3x10, tussen 3x10 en 3x10 en nul. 7.3 WOORDEN UIT FLOATING. De stack notatie is als in de voorgaande hoofdstukken met dit verschil dat fp een 32-bits floating point getal voorstelt. Woorden die alleen bij het assembleren gebruikt worden, zijn hier niet beschreven. 1& --- fp De constante 1. 10& --- fp De constante 10. 2CONSTANT 32b --- (runtime) --- 32b Zie hoofdstuk 6 D->F d --- fp zet het dubbele precisie gehele getal d om in het equivalente floating point getal. F* fp1 fp2 --- fp3 floating point vermenigvuldiging F+ fp1 fp2 --- fp3 floating point optelling. F- fp1 fp2 --- fp3 fp2 wordt afgetrokken van fp1 F->D fp --- d Het floating point getal f wordt omgezet in een dubbele precisie geheel getal, waarbij naar nul toe wordt afgerond. F. fp --- fp wordt afgedrukt in wetenschappelijke notatie met & als symbool voor maal tien tot de macht. F.R fp n1 n2 --- fp wordt afgedrukt zo dat de totale lengte minstens n1 is. Indien nodig worden links spaties toegevoegd. Er worden n2 cijfers achter de punt getoond. Er kan in elk talstelsel worden afgedrukt. F/ fp1 fp2 --- fp3 fp1 wordt door fp2 gedeeld. F0< fp --- f f is waar als fp kleiner is dan 0, anders onwaar. F0= fp --- f f is waar als fp gelijk is aan 0, anders onwaar. F2* fp1 --- fp2 vermenigvuldigt fp1 met 2. F2/ fp1 --- fp2 deelt fp1 door 2. F< fp1 fp2 --- f f is waar als fp1 kleiner is dan fp2, anders onwaar. F= fp1 fp2 --- f f is waar als fp1 gelijk is aan fp2, anders onwaar. F> fp1 fp2 --- f f is waar als fp1 groter is dan fp2, anders onwaar. FABS fp1 --- fp2 fp2 is de absolute waarde van fp1. FERRNUM f --- Bevat de uitbreiding van NUMBER. Het adres in 'ERRNUM verwijst daarnaar. Probeert floating point getal te maken als f waar is. Lukt dit niet, dan volgt een foutmelding. FI** fp1 n --- fp2 verheft fp1 tot de macht n. n is altijd geheel uiteraard. FLOAT --- Maakt de uitbreiding van NUMBER actief. Moet gegeven worden na koude start. FNEGATE fp1 --- fp2 trekt fp1 van 0 af. FSQRT fp1 --- fp2 Berekent vierkantswortel van fp1. NAN --- fp Constante, geeft ongeldig resultaat aan. X! fp1 8b --- fp2 Vervangt het exponent byte in fp1 door 8b. X@ fp --- fp 8b 8b is het exponent byte van fp. 7.4 WOORDEN UIT TRANSCEN. 180/PI --- fp Constante 180 gedeeld door pi 2, 32b --- breidt het woordenboek uit met 32b, net als , 2VARIABLE --- (runtime) --- addr Zie hoofdstuk 6. ATN2 --- fp fp is de hoek in radialen, die de vector in FX en FY maakt met de x-as. ATNTAB --- addr addr is het beginadres van een tabel met de arctangenten van negatieve machten van 2. Wordt gebruikt bij berekening trigoniometrische functies. ATNTAB@ u --- fp fp is de arctangens van 2 tot de macht -u. DEG fp1 --- fp2 Zet hoek fp1 in radialen om naar hoek fp2 in graden. F** fp1 fp2 --- fp3 verheft fp1 tot de macht fp2. fp1 mag niet negatief zijn. De verheffing tot een gehele macht, FI** heeft die beperking niet. F*2** fp1 n --- fp2 deelt fp1 door 2 tot de macht n. F10** fp1 --- fp2 berekent 10 tot de macht fp1. FARCCOS fp1 --- fp2 berekent de arccosinus van fp1 in radialen. FARCSIN fp1 --- fp2 berekent de arcsinus van fp1 in radialen. FARCTAN fp1 --- fp2 berekent de arctangens van fp1 in radialen. FCOS fp1 --- fp2 fp1 is in radialen. Berekent cosinus. FEXP fp1 --- fp2 berekent de e-macht van fp1. FLN fp1 --- fp2 berekent de natuurlijke logaritme van fp1. FLOG fp1 --- fp2 berekent de tientallige logaritme van fp1. FSIN fp1 --- fp2 fp1 in radialen. Berekent sinus. FTAN fp1 --- fp2 fp1 is in radialen. Berekent de tangens. FX --- addr FY --- addr Twee floating point variabelen die een vector bevatten voor de berekening van trigoniometrische functies. LN10 --- fp constante, de natuurlijke logaritme uit 10. LN2 --- fp constante, de natuurlijke logaritme uit 2. LNTAB --- addr addr is het beginadres van een tabel die de natuurlijke logaritmen bevat van 1 plus een negatieve macht van 2. Wordt gebruikt bij logaritmische berekeningen. LNTAB@ u --- fp fp is de natuurlijke logaritme van 1 plus twee tot de macht -u. PI --- fp constante, het getal pi. PI/180 --- fp constante, pi gedeeld door 180. RAD fp1 --- fp2 zet hoek fp1 in graden om in hoek fp2 in radialen. Om de sinus van 45 graden te berekenen typt men 45& RAD FSIN F. RAD zet 45 om naar radialen, daar FSIN radialen nodig heeft. TAN2 fp --- fp is positief. Maakt een vector in de variabe- len FX en FY onder een hoek van fp radialen met de x-as. 8 GRAFIEK EN GELUID. 8.1 GRAFISCHE ROUTINES. De file GRAPHIC bestaat uit 2 blokken en bevat routines om punten en lijnen te tekenen en verder commando's voor de kleuren. GRAPHIC gebruikt de assembler en daarom moet de assembler eerst geleaden worden. Het laden van GRAPHIC geschiedt op de zelfde wijze als beschre- ven voor DOUBLE in hoofstuk 6. PLOT n1 n2 --- Tekent een punt met x-coordinaat n1 en y-coordinaat n2. DRAW n1 n2 --- Tekent een lijn van de huidige plotpositie n1 punten naar links en n2 punten naar boven. Als n1 of n2 negatief zijn worden de richtingen resp. naar links en naar beneden. POINT n1 n2 --- f geft aan of het punt met x-coordinaat n1 en y-coordinaat n2 getekend is. ATTR n1 n2 --- c geeft de waarde van het attribute byte op regel n1 en kolom n2. HARDCOPY --- maakt een kopie van het scherm op een ZX-Printer. SCREENLOAD --- Leest de filenaam uit de invoertekst en leest de file met die naam in het schermgeheugen. SCREENSAVE --- Leest de filenaam uit de invoertekst en bewaart de inhoud van het scherm op band of schijf onder die naam. INK n --- PAPER n --- BORDER n --- BRIGHT n --- FLASH n --- werken het zelfde als de gelijknamige BASIC commando's. INV n --- Welkt als het BASIC commando INVERSE. GOVER n --- Werkt als het BASIC commando OVER. NORMAL --- Stelt de normale kleuren en dergelijke in. COLOR c --- (runtime) n --- Definierend woord dat gebruikt wordt om INK, PAPER etc te maken 8.2 USER DEFINED GRAPHICS. De file UED bestaat uit 4 blokken. Hij kan geladen worden met RUN UED indien GRAPHIC aanwezig is. De codes van de UDG's kunnen worden ingevoerd met ^ direct gevolgd door de letter. ^A stelt graphic A voor. CHADDR n --- addr geeft het adres van de grafische representatie van het teken met code n. UED --- start de UDG editor Binnen de UDG editor hebben de toetsen de volgende betekenis. Cursortoetsen en ENTER. Verplaatsen de grafische cursor in het 8x8 veld. @ Leest een teken in in het 8x8 veld. Typt men direct na @ een letter in, dan wordt de bijbehorende UDG gelezen. Typt men na @ een & in en dan een teken, dan wordt dit teken ingelezen. ! Schrijft het teken in het 8x8 veld in het geheugen op het adres waar de grafische representatie van een bepaald teken staat. De keuze van het teken geschiedt als bij @. Normaal kan men alleen UDG's wegschrijven, maar als de systeemvariabele CHARS op 23606 gewijzigd is, ook andere tekens. A O en E voeren resp. een AND, OR en EXOR bewerking uit met het teken in het 8x8 veld en een willekeurig te kiezen teken. X en Y spiegelen het teken in het 8x8 veld in resp. de X en de Y as. R roteert het teken in het 8x8 veld een kwartslag. I inverteert het teken in het 8x8 veld. SPATIE inverteert de pixel waar de grafische cursor staat. EDIT beeindigt de grafische editor. 8.3 GELUID. De file MUSIC bestaat uit twee blokken en bevat routines om uit de Spectrum 48k zowel als 128k geluid te krijgen. De ASSEMBLER is nodig. Zie voor het laden hoofdstuk 6, waar het laden van DOUBLE wordt beschreven. BEEPER u1 u2 --- produceert een toon bestaande uit u1 pulsen met een lengte van u2 machine tijdseenheden. TONE u1 u2 --- produceert een toon van u1 milliseconden en u2 Hz. MS n1 --- wacht n1 milliseconden. De volgende commando's werken alleen op een 128K Spectrum. SOUND 8b n --- schrijft 8b in register n van de geluidschip. FREQ u n --- Stelt kanaal n (n=0,1 of 2) in op frequentie u VOL u n --- Stelt kanaal n (n=0,1 of 2) in op volome u (u=0 t/m 15). TONES --- Schakelt de 3 toonkanalen in. NOISE --- Schakelt de 3 ruiskanalen in. Met n 6 SOUND kan de ruisfrequentie worden beinvloed. SHUTUP --- Schakelt het geluid uit. De volgende commando's werken afhankelijk van het type Spectrum op de BEEPER of op de geluidschip. NOOT u --- (runtime) --- definierend woord dat een noot met frequentie u definieert. A A# B C C# D D# E F F# G G# brengen de gewenste noot ten gehore. L u --- Stelt de lengte van de volgende noten op u tellen. O+ O- --- verhoogt, verlaagt het octaaf. >> << --- verhoogt of verlaagt het volume. R --- Geeft een rust. TEMP --- addr variabele die het tempo aangeeft in milliseconden per tel. OCT --- addr variabele die het octaaf aangeeft. (vermenigvuldigingsfactor van frequentie.) VOLUME --- addr Variablele die het volume aangeeft. LEN --- addr variabele die het aantal tellen per noot aangeeft. 9 DE DECOMPILER De file UTIL bestaat uit 2 blokken en bevat een utility om te bekijken hoe een bepaald FORTH woord is opgebouwd, te decompileren. Met SEE naam krijgt men een overzicht, dat de volgende informatie bevat: - het codeveld adres. - eventueel IMMEDIATE. - het soort woord, dit kan zijn CONSTANT voor constanten USER voor user variabelen. : voor colondefinities. CREATE voor variabelen of woorden die met CREATE zijn gemaakt. CODEWORD voor machinecodewoorden. De naam van het definierende woord voor woorden die met een ander definierend woord zijn gemaakt, zoals VOCABULARY - De inhoud van het woord d.i. Voor constanten en uservariabelen: de waarde. Voor colondefinities: een lijst van alle woorden waaruit de definitie is opgebouwd. Dit verschilt van de sourcecode doordat de runtime delen van immediate woorden worden getoond. Hierbij wordt rekening gehouden met eventuele operanden, zoals de waarde van een literal, de sprongafstand van BRANCH e.d. en de string achter (."). Voor alle ander woorden: een hex en ASCII dump. - Het aantal bytes in het parameterveld. Deze lengte klopt niet als het volgende woord in de CONTEXT vocabulary niet op het gedecompileerde woord volgt. Het decompileren van colondefinities stopt als EXIT wordt gevonden. Woorden die EXIT ergens middenin gebruiken worden niet compleet gedecompileerd. Wanneer nieuwe compilerende woorden worden gedefinieerd die operanden achter zich hebben, werkt de decompiler daarmee niet correct. De decompiler zal dan moeten worden aangepast. Behalve SEE zijn de volgende woorden nog van belang: (SEE) addr --- Verricht de actie van SEE op het woord met addr als codeveldadres HIGH-NFA addr1 --- addr2 addr2 is het naamveld adres in de de CONTEXT vocabulary dat het dichtst boven addr1 ligt. #WORDS --- u geeft het aantal woorden in de CONTEXT vocabulary inclusief wat eraan vast zit. DOCON --- addr DOCOL --- addr DOUSER --- addr constanten die de adresssen van de runtime routines van CONSTANT : en USER bevatten. NEXT --- addr adres van de inner interpreter. Komt voor in het codeveld van variabelen. 10 MULTITASKING. 10.1 INLEIDING. Multitasking is het uitvoeren van meer programma's schijnbaar tegelijkertijd. Hierbij heeft ieder programma zijn eigen stack en uservariabelen en wordt zeer snel tussen de programma's omgeschakeld. Voor de hand liggende toepassingen zijn: -besturing van apparaten zoals modeltreinen. -videogames. -meerstemmige muziek. (128k) -muziek op de achtergrond.(128k) -doorwerken met FORTH terwijl de computer bezig is met een langdurige berekening. De file TASKS bevat de basisroutines om multitasking mogelijk te maken en bestaat uit 3 screens. De assembler is nodig. Voor het laden volge men dezelfde procedure als voor DOUBLE in hoofdstuk 6. 10.2 HET MAKEN VAN EEN TAAK. Het maken van een taak wordt ge‹llustreerd aan de hand van een voorbeeld. We maken een taak die linksboven op het scherm een getal schrijt, dat steeds oploopt. Allereerst defini‰ren we een woord, dat de cursorpositie geeft, zodat die door AT weer hersteld kan worden. : UNAT 24 23689 C@ - 33 23688 C@ - DUP 32 = IF DROP 1+ 0 THEN ; Nu definieren we de taak, alsof het een colon definitie was maar dan met TASK: en ;TASK TASK: TAAK1 DECIMAL 0 BEGIN UNAT 0 0 AT 2 PICK 6 .R AT 1+ DUP 0= SWITCH UNTIL ;TASK Nu wordt het multitasking systeem opgestart met STARTUP Om de taak te starten typt men zijn naam, dus TAAK1 Nu moet men, terwijl men gewoon met FORTH werkt, linksboven een getal snel zien oplopen. Typt men ' TAAK1 STOP in, dan zal het getal niet meer oplopen. Typt men ' TAAK1 START in, dan gaat het tellen weer door. Typt men weer TAAK1, dan start de taak weer opnieuw vanf 0. Wacht men lang genoeg en heeft de taak behalve de positieve getallen ook de negatieve getallen geteld, dan zal de taak uit zichzelf ophouden. Krijgt men ergens een foutmelding, dan start men alle taken weer door STARTUP. De foutmelding moet dan wel in de normale FORTH taak ontstaan. 10.3 DE WERKING. Iedere keer dat men een nieuwe taak aanmaakt, wordt een nieuw taakgebied aangemaakt. Dit bestaat uit de volgende onderdelen - 2 bytes startadres van de FORTH code. - 2 bytes adres van de vorige gedefinieerde taak. Bij de eerste taak wijst dit naar de laatste, zodat alle taken circulair met elkaar zijn verbonden. - 1 byte statusbyte: 0=actief (uitvoerbaar) 1=nieuw. 2=be‰indigd. 3=slapend. 4=gestopt. Alleen met een statusbyte 0 mag de taak doorgaan. - 2 bytes adres van de taak zijn stackpointer. - 60 bytes user variabelen. - 256 bytes returnstack. - 256 bytes stack. Hierna begint de FORTH code. Op de Spectrum 128K moeten alle taakgebieden beneden adres 49152 liggen! Het omschakelen tussen taken geschiedt met het woord SWITCH Met dit woord worden de return-stackpointer en de instructiepointer van de huidige taak op de stack bewaard. Dan wordt de stackpointer op zijn plaats bewaard. Dan wordt via de linkadressen een taak opgezocht, die uitvoerbaar is. Dan worden de stackpointer, de instructiepointer en de returnstackpointer van de nieuwe taak geladen en wordt verdergegaan met de nieuwe taak. Alle taken komen zo cyclisch aan de beurt. De user area pointer wijst naar de user area in het taakgebied van de huidige taak. Om multitasking te verkrijgen moet men iedere taak voorzien van het woord SWITCH in de lusstructuren die vaak worden herhaald en een vrij korte tijd per herhalingsslag hebben. Anders duurt het te lang voordat andere taken een beurt krijgen. Indien een taak nooit een SWITCH uitvoert, blijft hij steeds aan de beurt. Ook de woorden KEY en PAUSE voeren tijdens het wachten SWITCH uit. Dit wordt bereikt via de variabele (WAIT). 10.4 DE WOORDEN. SWITCH --- Schakelt om naar de volgende uitvoerbare taak. UPTR --- addr constante, het adres van de user area pointer. TASK-LINK --- addr variabele die het adres van het laatst aangemaakte taakgebied bevat. FIRST-TASK --- addr Variabele die het adres van het eerst aangemaakte taakgebied bevat. TASK: --- Definierend woord, dat een taak aanmaakt. Brengt FORTH in de comileertoestand. Tijdens runtime wordt de taak vanaf het begin gestart. ;TASK --- sluit de definitie van een taak af. Brengt FORTH in de interpretatietoestand. TERMINATE --- Be‰indigt de huidige taak. Men moet de taak dan niet daarna met start weer door laten gaan. SLEEP --- Brengt de huidige taak in de slaaptoestand. Uit deze toestand kan een taak wel worden wakker geroepen door start. STOP addr --- addr is het codeveld adres van een taak. Stopt een andere taak. START addr --- addr is het codeveld adres van een taak. Herstart een gestopte taak vanaf het punt waar hij werd gestopt. MTSK --- De taak die de FORTH interpreter bevat. Dat MTSK actief is is te zien aan de prompt > . (START) --- codedeel van STARTUP STARTUP --- schakelt het multitasking systeem in. TLIST --- Geeft een lijst van alle taken met hun status. De status ACTIVE heeft de taak die TLIST aanriep. De status RUNNABLE hebben alle andere uitvoerbare taken. 11 STRINGS EN ANDERE DATATYPEN. 11.1 INLEIDING De file OBJECT bestaat uit 6 screens en bevat al het nodige om met strings te werken en een aantal woorden om gestructureerde datatypen zoals arrays te bouwen. Veel van de bewerkingen die in dit hoofdstuk zijn beschreveen zijn ook op een lager niveau mogelijk en daarbij sneller. Deze routines zijn niet ontworpen voor snelheid maar voor gebruikersvriendelijkheid. 11.2 DE STRINGSTACK Strings zijn rijen ASCII tekens met een bepaalde lengte. Zij worden bewaard op een aparte stack. Iedere string bestaat uit een lengtebyte, van 0 tot en met 255 en daarachter de tekens. De string aan de top van de stack zit het laagst in het geheugen, de string die daaronder zit komt er direct achteraan. De stringstackpointer wijst naar het lengtebyte van de string aan de top van de stack. Het adres van de tweede string kan worden gevonden door het lengtebyte plus 1 bij de stackpointer op te tellen. De string stack bevindt zich bovenin het vrije geheugen, direct onder het adres in de variable LO. De strinstackpointer bevindt zich in de variable $SP Met de stringstack zijn de bewerkingen $DUP, $SWAP, $OVER en $DROP mogelijk. Verder kunnen strings van de stack naar het geheugen verplaatst worden met $! en $!LIM en van het geheugen naar de stack met $@. Met de strings op de stack kunnen de zelfde bewerkingen worden uitgevoerd als in de meeste BASIC dialecten, zoals MID$, STR$ VAL, ASC, CHR$, LEFT$ en RIGHT$. Verder kunnen strings vergeleken worden met $=,$< en $> en samengevoegd met $+ en afgedrukt met $. Stringconstanten kunnen zowel vanuit de interpreter als in de compiler worden ingevoerd met " waaracher een spatie en dan de string afgesloten door " Zo betekent " Dit is een tekst." $. hetzelfde als ." Dit is een tekst." in de compiler of .( Dit is een tekst.) in de interpreter. Alleen gebruiken de laatste twee niet de stringstack. Een ander voorbeeld van het gebruik van de stringstack is. 1234. STR$ 1 RIGHT$ $. Dit zet het getal 1234 om in een string, haalt er het laatste cijfer uit met RIGHT$ en drukt dit af. Het is daarmee equivalent met het BASIC statement PRINT RIGHT$(STR$(1234),1). Een ervaren FORTH programmeur bereikt hetzelfde effect met 1234. <# # #> TYPE wat sneller werkt en waar bovendien de stringroutines niet bij nodig zijn. 11.3 HET 'TO' CONCEPT. In standaard FORTH-83 geeft een variabele altijd een adres af en is de gebruiker ervoor verantwoordelijk dat de waarde in die variable wordt uitgelezen of opgeslagen. Hierbij moet gekozen worden uit de woorden @, C@, 2@, $@ !, C!, 2!, $! of $!LIM. Een vaak voorkomende programmeerfout be- rust op het vergeten van @, C@, 2! of $@ bij het uitlezen van een variable. Bij gebruik van het TO-concept draagt de variabele er zelf zorg voor, dat hij wordt gelezen of beschreven. De variable weet wat hij moet doen aan de hand van een toestand. Deze toestand geeft normaal gesproken aan dat de variabele moet worden gelezen maar door het woord TO te gebruiken kan men de toestand tijdelijk op 'schrijven' zetten. Nadat er een variabele is beschreven komt de toestand weer op 'lezen'. Men kan nu A B + C D + * TO E intypen in plaats van A @ B @ + C @ D @ + * E ! Ging het om dubble precisie variabelen, dan kan men in het eerste geval A B D+ C D D+ D* TO E intypen in plaats van A 2@ B 2@ D+ C 2@ D 2@ D+ D* E 2! In het eerste geval veranderen alleen de rekenkundige bewerkingen, in het tweede geval ook alle lees en schrijf operaties. In dit programma wordt de toestand bijgehouden terwijl het programma loopt. Dit maakt het machine-onafhankelijk maar minder snel. In andere systemen wordt de toestand vaak tijdens compileren bijgehouden, zodat FORTH er geen omkijken meer naar heeft als het programma loopt. 11.4 GESTRUCTUREERDE DATATYPEN Als men een variable volgens het TO-concept wil maken, die een wwarde bevat, dan typt men: VALUE is de naam, die de variabele moet krijgen. is een van de volgende dingen: BOOL voor logische varabelen (1 byte) CHAR voor tekens (1 byte) INT voor gehele getallen (2 bytes) LONG voor dubbele precisie ge tallen. (4 bytes) REAL voor floating point getallen. (4 bytes) n STR voor strings. n is hier een getal dat de maximum lengte aangeeft.(n+1 bytes maar niet minder dan 5). INT VALUE AANTAL REAL VALUE MAAT 10 STR VALUE NAAM maakt drie variabelen, een geheel getal, een floating point getal en een string van hoogstens 10 tekens. Een eendimensionale array maakt men met n ARRAY n is hierbij het aantal elementen, dat de array bevat. 3 LONG ARRAY VECTOR 9 5 STR ARRAY NAMEN maakt twee arrays, een met 3 dubbele precisie getallen en een met 9 namen met lengte hoogstens 5. Men kan VECTOR een waarde geven met bv. 1234. TO 0 VECTOR Indien A een integer variabele is, moet met 1234. A TO VECTOR gebruiken om VECTOR een waarde te geven en niet 1234. TO A VECTOR daar dan iets in A geschreven wordt en niet in VECTOR. Men selecteert een element van een array met een getal tussen 0 en het aantal elementen min 1. Een tweedimensionale array is te maken met: n1 n2 MATRIX Men krijgt dan een array van n1 maal n2 elementen. Men selecteert een element met 2 getallen, waarvan het eerste tussen 0 en n1-1 ligt en het tweede tussen 0 en n2-1. Het type van de elementen wordt onderscheiden aan de hand van de grootte. Elementen die 1 byte groot zijn, worden met C! en C@ bewerkt en zijn van type CHAR of BOOL. Elementen van 2 bytes zijn van type INT en worden met @,! en +! bewerkt. Elementen van 4 bytes groot zijn LONG of REAL en worden met 2@ en 2! bewerkt. Alle grotere elementen zijn strings. De datatypen maken geen onderscheid tussen bv REAL en LONG. men kan zelf met behulp van het CREATE DOES> mechanisme andere datatypen bouwen, zoals records met elementen van verschillend type, queues, stacks, lijsten etc. Men moet dan ergens het aantal bytes opslaan in de datastructuur. Aan de hand daarvan kan men het adres van het element opzoeken. Met (VAL) kan men dan de data bewerken, gegeven het adres en het type, waarbij de toestand in de variabele %TO staat. 11.5 DE WOORDEN. $ in de stacknotatie betekent een string op de stringstack. " --- (compileren) --- $ (interpreteren) Leest de invoertekst tot " en compileeert deze als een string-literal als de tekestinterpreter in de compilatietoestand is of zet de string op de stringstack. "" --- $ stringconstante, de lege string. $! $ addr --- Slaat de string op vanaf adres addr. $!LIM $ addr u --- slaat string $ op vanaf adres addr en kapt hem af als hij meer dan u tekens lang is. $+ $1 $2 --- $3 Concateneert de strings $1 en $2 $- $1 $2 --- n n is negatief als de string $1 kleiner is dan $2, dwz lager komt in de ASCII-lexicografische ordening, n=0 als de strings gelijk zijn en positief als $1 groter is dan $2. $. $ --- drukt de string $ af. $< $1 $2 --- f f is waar als $1 kleiner is dan $2, anders onwaar. $= $1 $2 --- f f is waar als $1 gelijk is aan $2, anders onwaar. $> $1 $2 --- f f is waar als $1 groter is dan $2, anders onwaar. $@ addr --- $ leest de string uit het geheugen vanaf adres addr. $CONSTANT $ --- (runtime) --- $ definierend woord. Cre‰ert een nieuw woord, dat tijdens runtime de eerder toegevoerde string op de stack zet. $DROP $ --- verwijdert string van stack. $DUP $ --- $ $ dupliceert string op stack. $OVER $1 $2 --- $1 $2 $1 dupliceert tweede string op stack. $S0 --- addr Hoogste waarde van de stringstackpointer. $SP --- addr variable die het adres van de strinstackpointer bevat. $SP! --- zet de strinstackpointer op zijn hoogste adres. $SWAP $1 $2 --- $2 $1 wisselt de strings om op de stack. %TO --- addr variabele die de toestand bevat, die aangeeft wat een TO-variabele moet doen. (") --- $ runtime deel van " (CHAR) addr --- c %TO=0 c addr --- %TO=1 verwerkt variabelen van type CHAR en BOOL. (INT) addr --- n %TO=0 n addr --- %To=1 of 2 verwerkt variabelen van type INT (LONG) addr --- d %TO=0 d addr --- %TO=1 verwerkt variabelen van type LONG en REAL. (STR) addr u --- $ %TO=0 $ addr u --- %TO=1 c n addr u --- %TO=4 n addr u --- c %TO=5 verwerkt variabelen van type string, waarbij addr het adres is van de string, u de maximale lengte, $ de string, c het teken in de string men wil lezen of schrijven en n geeft aan welk teken. (VAL) addr u --- verwerkt een variabele van een van de voorgaande typen. u geeft de grootte aan in bytes. addr het adres. +$ $1 $2 --- $3 concateneert de strings door $1 achter $2 te plaatsen. +TO --- geeft an dat bij een volgende variabele iets moet worden opgeteld. -RIGHT$ $1 u --- $2 $2 is $1 vanaf het u-de teken. >ELEM --- geeft aan dat bij de volgende variabele een teken in een string wodt geschreven. Als NAAM een stringvariable is, dan verandert &A 1 >ELEM NAAM het eerste teken van NAAm in een A. ?RANGE u1 u2 --- geef foutmelding als U1>u2 ARRAY u1 u2 --- maakt array van type u2 met u1 elementen. ASC $ --- c c is het eerste teken van $ BOOL --- 1 geeft type aan bij variabele. CHAR --- 1 geeft type aan bij variabele. CHR$ c --- $ $ is de string die uit het teken c bestaat. ELEM> --- geeft aan dat bij een volgende variabele een teken uit een string gelezen moet worden. ER --- geef foutmelding INVALID OP. GET$ --- $ leest string $ van het toetsenbord met EXPECT. INT --- 2 geeft type aan bij variabele. LEFT$ $1 u ---$2 $2 bestaat uit de eerste u tekens van $1. LEN $ --- u u is de lengte van string $ LONG --- 4 geeft type aan van variabele. MATRIX u1 u2 u3 --- maakt een mtrix van type u3 met u1 rijen en u2 kolommen. MID$ $1 u1 u2 --- $2 $2 bestaat uit u2 tekenst uit $1 beginnende vanaf het u1-de teken REAL --- 4 geeft type aan van variabele. RIGHT$ $1 u1 --- $2 $2 bestaat uit de laatste u1 tekens van $1. RV --- zet %TO wwer in de leestoestand STR u1 --- u2 geeft stringtype aan. STR$ d --- $ zet dubbel getal om in string. TO --- geeft aan dat bij een volgende variabele iets wordt geschreven. VAL $ --- d Zet string om in dubbel getal. VALUE u1 --- maakt variabele van type u1. WORD$ --- $ $ is het volgende woord uit de invoertekst. 11.6 AANPASSEN VOOR MULTITASKING Teneinde deze routines voor multitasking geschikt te maken, moet u in ieder geval de variabelen $SP en %TO als USER definieren, tenzij: - er slechts ‚‚n taak gebruik maakt van deze routines. - Iedere SWITCH gebeurt met een lege stringstack en de %TO variabele in de leestoestand. Wanneer iedere taak zijn eigen stringstackpointer heeft, moet men voor iedere taak een apart stringstackgebied reserveren en de stringstackpointer aan het eind van dit stackgebied initialiseren.