|
|
[rtn]
.
Met [rtn]
is de Return toets of de Enter toets bedoeld.
) 65 emit [rtn] A ok ) ) 66 emit [rtn] B ok ) ) 56 . [rtn] 56 okEen getal wordt ook als een woord opgevat.
EMIT
kan vervolgens over dat getal beschikken,
beschouwt het als een ASCII code
en laat het bijbehorende karakter op het scherm verschijnen.
) decimal [rtn]en probeer het dan nog eens.
) 65 emit 66 emit [rtn] AB ok ) ) 65 66 emit emit [rtn] BA ok ) ) 65 74 emit emit emit [rtn] JA Empty stack ) ) 1000 45 emit . [rtn] -1000 okEen woord dat een getal nodig heeft, pakt altijd het getal dat als laatste binnengekomen is.
EMIT ( getal -- )
Haal het getal van de stack af,
beschouw het als een ASCII code en druk het bijbehorende karakter af.
. ( getal -- )
Haal het getal van de stack af
en druk het af met een spatie erachter.
KEY ( -- getal )
Wacht totdat er een toets
ingedrukt is en zet de ASCII code van die toets als getal op stack.
CR ( -- )
Ga naar een nieuwe regel.
Geen verandering op de stack.
) key . [rtn] ? ) key emit [rtn] ? ) cr key . [rtn] ? ) key cr . [rtn] ? ) key . cr [rtn] ? ) key key emit emit [rtn] ?
+ ( x y -- z )
Haal twee getallen van de stack af,
tel ze op en zet het resultaat weer op stack.
) 1 4 + [rtn] ok ) . [rtn] 5 ok ) 2 3 + 4 + . [rtn] 9 ok ) 2 3 4 + + . [rtn] 9 ok
- ( x y -- z )
Aftrekken: z = x - y
* ( x y -- z )
Vermenigvuldigen: z = x * y
) 1 4 - . [rtn] -3 ok ) 2 3 * . [rtn] 6 okJe kunt de volgorde van getallen op stack veranderen:
SWAP ( x y -- y x )
Verwissel de laatste
twee getallen op stack onderling.
) 1 4 swap - . [rtn] 3 ok
DUP ( x -- x x )
Maak een extra exemplaar
van het laatste getal.
) key dup . emit [rtn] ?? Als je moet uitrekenen hoeveel
500+14*(61-52)
is,
welke van de onderstaande uitwerkingen zijn dan onjuist?
En welke vind je het overzichtelijkst?
) 500 14 61 52 - * + . [rtn] ? ) 61 52 - 14 * 500 + . [rtn] ? ) 500 14 52 61 swap - * + . [rtn] ? ) 14 61 52 - * 500 + . [rtn] ? ) 500 14 61 dup emit 52 - * + . [rtn] ? ) 500 14 61 52 - dup . * dup . + . [rtn] ? ) 61 52 - dup . 14 * dup . 500 + . [rtn] ?
WORDS ( -- )
Laat de woorden zien die Forth kent.
De nieuwste woorden staan voorop.
) : PILS 105 * . ; [rtn] ok
PILS.
Je vermoedt al dat het geen bestaand Forth woord is.
Het eerste woord achter een dubbele punt
wordt de naam van het nieuw te vormen woord.
Die naam kun je vrij kiezen (lengte hoogstens 31 karakters,
geen spaties, want die werken als woordscheiding).
Als je liever KOFFIE
hebt, kan dat.
PILS
.
) WORDS [rtn] ?Technisch onderscheidt
PILS
zich niet van de bestaande Forth woorden.
Het is geen tweederangs woord
en het werkt ook niet trager dan de bestaande woorden.
: ccc ( -- )
Maak een definitie
met de naam ccc
. Met ccc
bedoel ik een willekeurige naam.
; ( -- )
Beëindig een definitie.
PILS ( x -- )
Druk de rekening
voor x
pilsjes af.
) 1 pils [rtn] ? ) 4 pils [rtn] ? ) 10 pils [rtn] ? ) : KRAT 24 * ; [rtn] ok ) 2 krat pils [rtn] ?
.S ( -- )
Laat zien welke getallen er op stack staan
zonder de stack te veranderen (punt S).
DROP
en OVER
doen.
Schrijf iedere keer voordat je op [rtn]
drukt
op een papier welk resultaat je verwacht.
) arnhem [rtn] ? ) 15 .s [rtn] ? ) dup .s [rtn] ? ) + .s [rtn] ? ) 2 .s [rtn] ? ) over .s [rtn] ? ) + .s [rtn] ? ) emit .s [rtn] ? ) drop .s [rtn] ? ) drop .s [rtn] ?
ARNHEM
is geen Forth woord en veroorzaakt een foutmelding.
Dat is natuurlijk flauw,
maar bij een foutmelding wordt de stack altijd leeggemaakt
en daar ging het mij om.
DROP
een getal
van stack te verwijderen.
Maar de stack is leeg.
Dat veroorzaakt een foutmelding.
De .S
die erachter staat, wordt niet meer uitgevoerd.
BL ( -- 32 )
Zet de ASCII code van de spatie op stack.
) : WIJD ( k -- ) emit bl emit ; [rtn] okTekst tussen haakjes is ter informatie. Die hoef je dus niet in te typen. Je zou dat echter wel kunnen doen, want Forth slaat alles over wat tussen haakjes staat. Het haakje openen is een Forth woord en moet daarom gevolgd worden door een spatie, daarna kan de informatie komen.
) 12 ( onzin ) . .S [rtn] ? ) ) 65 wijd 66 wijd 67 wijd [rtn] ?
( ( tekst -- )
Sla de tekst t/m het eerstvolgende
haakje sluiten over.
) 12 constant DOZIJN [rtn] ok ) dozijn . [rtn] 12 ok
CONSTANT ccc ( x -- )
Definiëer een konstante
met de waarde x
en de naam ccc
.
DOZIJN ( -- 12 )
Zet de waarde van de konstante
op stack.
VALUE
met de hulpwoordjes TO +TO
) value BEDRAG [rtn] ok
VALUE ccc ( -- )
Definieer de ruimte voor
een veranderbare waarde met de naam ccc
.
BEDRAG ( -- x )
Zet x, de waarde
van de value, op stack.
) 200 to bedrag [rtn] ok ) bedrag . [rtn] 200 ok
TO ccc ( x -- )
Schrijf de waarde x
in de value ccc
.
) 10 +to bedrag [rtn] ok ) bedrag . [rtn] 210 ok
+TO ccc ( y -- )
"plus-to" Tel y
op bij
de inhoud van de value ccc
.
0 value ccc
VARIABLE
met de hulpwoordjes @ ! +!
) variable BEDRAG [rtn] ok
VARIABLE ccc ( -- )
Definieer de ruimte voor
een veranderbare waarde met de naam ccc
.
BEDRAG ( -- a )
Zet a, het adres
van de variabele, op stack.
) 200 bedrag ! [rtn] ok ) bedrag @ . [rtn] 200 ok
! ( x a -- )
uitspr. "store"
Schrijf de waarde x
in het adres a
.
@ ( a -- x )
"fetch" Zet de inhoud van
adres a
op stack.
) 10 bedrag +! [rtn] ok ) bedrag @ . [rtn] 210 ok
+! ( y a -- )
"plus-store" Tel y
op
bij de inhoud van adres a
.
! @
en +!
gebruikt.
Vooral !
en +!
zijn gevaarlijke woorden.
Als je er fouten mee maakt, overschrijf je ongewild ergens iets
in het geheugen
en dat kan "fatale" gevolgen hebben. Dus:
! @
en +!
alleen direkt achter een adres.
Values : APPELS ( n -- ) 80 * +to bedrag ; : PEREN ( n -- ) 70 * +to bedrag ; : TOTAAL ( -- ) bedrag . 0 to bedrag ; totaal [rtn] ? 5 appels 3 peren totaal [rtn] ? : EIEREN ( n -- ) 60 * +to bedrag ; 2 peren 2 eieren totaal [rtn] ? dozijn eieren 10 appels 10 peren totaal [rtn] ? |
Variables : APPELS ( n -- ) 80 * bedrag +! ; : PEREN ( n -- ) 70 * bedrag +! ; : TOTAAL ( -- ) bedrag @ . 0 bedrag ! ; totaal [rtn] ? 5 appels 3 peren totaal [rtn] ? : EIEREN 60 * bedrag +! ; 2 peren 2 eieren totaal [rtn] ? dozijn eieren 10 appels 10 peren totaal [rtn] ? |
( ... -- ... )
ccc
aan dat het woord een naam nodig heeft.
EMIT . DECIMAL KEY CR + - * SWAP DUP WORDS : ; .S DROP OVER BL ( CONSTANT VALUE TO +TO VARIABLE @ ! +!In sommige Forth systemen laat de dubbele punt tijdens het compileren een waarde achter op stack die er door de puntkomma weer afgehaald wordt. Deze waarde wordt in het systematische deel achter deze kursus met
sys?
aangeduid.
' ccc ( -- s )
Zet de sleutel
van het woord ccc
op stack.
Als het woord niet gevonden wordt, komt er een foutmelding.
) ' drop . [rtn] ? ) ' words . [rtn] ? ) ' arnhem . [rtn] ? ) ' 0 . [rtn] ? ) ' 75 . [rtn] ?De waarde van een sleutel is systeemafhankelijk. Getallen hebben over het algemeen geen naam en geen sleutel.
EXECUTE ( s -- )
Voer het woord
dat de sleutel s
heeft uit.
) 3 4 .S [rtn] ? ) ' swap execute [rtn] ok ) .s [rtn] ?Het is aan de programmeur om ervoor te zorgen dat de sleutel voor
EXECUTE
een geldige sleutel is,
dwz. verkregen is met het woordje '
(Tick).
) : ZEVEN 7 ; ) zeven 2 * . [rtn] ? ) : 7 7 ; ) 7 7 * . [rtn] ? ) zeven constant SEVEN ) seven . [rtn] ? ) ' 7 execute . [rtn] ? ) : 8 100 ; ) 8 1 + . [rtn] ?
: NUL? ( x -- ) ." (" 0 = if ." ja" else ." nee" then ." ) " ;Probeer
NUL?
uit op verschillende getallen.
." ccc" ( -- )
Druk de tekst ccc
af.
Omdat ."
(punt aanhaling) een woord is,
moet hij door een spatie gescheiden worden van de af te drukken tekst.
Het tweede aanhalingsteken geeft het teksteinde aan
en maakt geen deel uit van de tekst.
Er mogen nu wel spaties maar uiteraard geen aanhalingstekens
in ccc
voorkomen.
= ( x y -- vlag )
Test of x
gelijk is
aan y
en laat een vlag achter op de stack.
De True vlag is gelijk aan -1 en de False vlag is gelijk aan 0.
TRUE ( -- x )
x=-1
d.w.z. alle bits van x
zijn gezet.
FALSE ( -- x )
x=0
d.w.z. alle bits van x
zijn nul.
IF ( vlag -- )
Haal een vlag van stack
en reageer aldus:
[true?] IF [zo ja, doe dan dit]
ELSE [zo nee, doe dan dit]
THEN [enz.]
IF
beschouwt ieder getal dat niet nul is als een True vlag.
ELSE
voorkomen.
: TEST ( x -- ) dup . ." is " dup 0 < if ." kleiner dan " then dup 0 > if ." groter dan " then drop ." nul " ;Probeer
TEST
uit op verschillende getallen.
< ( x y -- vlag )
Test of x<y
.
> ( x y -- vlag )
Test of x>y
.
CIJFER? ( -- )
dat vaststelt
of een ingetypte toets een cijfer is.
Op het scherm moet de mededeling 'cijfer' of 'geen cijfer' verschijnen.
Gebruik het woord KEY
hierbij.
) : TEL ( -- ) ) 20 0 do i . loop ;
DO ( grenswaarde beginwaarde -- )
Start een lus.
De teller begint met beginwaarde.
Grens- en beginwaarde (let op hun volgorde) worden van stack gehaald
en intern opgeborgen.
LOOP ( -- )
Verhoog de teller met 1
en spring terug naar het eerste woord dat achter code> DO staat,
maar ga verder als de teller gelijk is geworden aan de grenswaarde.
I ( -- t )
Zet de waarde van de teller
van de Do-Loop op stack. I
is een afkorting van Index.
BASE
als grondtal.
Door de waarde van BASE te veranderen kun je in andere talstelsels werken.
HEX BINARY
en DECIMAL
zijn Forth woorden die omschakelen naar een bepaald talstelsel.
Als BINARY
nog niet bestaat:
: BINARY ( -- ) 2 BASE ! ;
) decimal tel [rtn] ? ) base @ . [rtn] ? ) hex tel [rtn] ? ) base @ . [rtn] ? (strikvraag) ) binary tel [rtn] ? ) 10 decimal . [rtn] ? ) 10 hex . [rtn] ? ) 10 1 - . [rtn] ? ) 10 decimal . [rtn] ?? Leg uit wat het woord
LIJST
doet:
decimal : LIJST ( -- ) 17 0 do cr i hex . i decimal . i binary . loop decimal ;
) lijst [rtn] ?
: TEL-DOOR ( x -- y ) begin dup . 1 + key? until key drop ;Nieuwe woorden:
BEGIN ( -- )
Start een lus.
UNTIL ( vlag -- )
Ga verder als de vlag True is,
maar spring terug naar het eerste woord achter BEGIN
als de vlag False is.
KEY? ( -- vlag )
Test of er een toets ingedrukt is.
KEY
de ASCII code van die toets op stack gezet worden.
) 0 tel-door . [rtn] ? ) 0 tel-door tel-door . [rtn] ?voorbeeld:
value TEKEN #43 to teken teken emit [rtn] ? : TEKENS ( n -- ) begin dup 0 > while 1 - teken emit repeat drop ;
) 5 tekens [rtn] ?
WHILE ( vlag -- )
Ga verder als de vlag True is,
maar spring uit de lus, over REPEAT
heen,
als de vlag False is.
TEKENS
zes minnetjes te laten verschijnen?
TEKENS
maken
met behulp van Do-Loop in plaats van met Begin-While-Repeat ?
TEKST
?
) : TEKST ( -- ) ) key cr ) begin key ) dup emit ) over = until ) drop ; ( Ik hoop dat je hier uitkomt. )
BASE
een rol.
.
bijvoorbeeld), moet de weg terug afgelegd worden.
BASE
heeft daar geen invloed meer op.
0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111De patronen die met een 0 beginnen zijn zwart, de andere, die met een 1 voorop, maak even ik blauw.
0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1000 1001 1010 1011 1100 1101 1110 1111 0000 0001 0010 0011 0100 0101 0110 0111 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7
.
(punt) bestaat U.
(u punt).
.
(punt) vertaalt naar Signed getallen.
U.
(u punt) vertaalt naar Unsigned getallen.
) -1 u. [rtn] ?Naast
<
(kleiner dan) bestaat U<
(u kleiner dan).
) -5 5 < . [rtn] ? ) -5 5 u< . [rtn] ?Voor optellen en aftrekken hoeft er geen onderscheid gemaakt te worden tussen Signed en Unsigned. Dat is mogelijk doordat Forth daarbij geen kontrole uitvoert op het te groot of te klein worden van de uitkomst. Overflow en underflow worden niet gemeld, de programmeur moet dat zelf opvangen. Het gaat als bij een kilometerteller in de auto. Als het hoogste getal verschijnt, allemaal negens, en je rijdt toch verder, dan komt er geen melding op het dashboard in de trant van
END-OF-AUTO-ERROR
.
) binary false . [rtn] ? ) false u. [rtn] ? ) true . [rtn] ? ) true u. [rtn] ? ) decimal true u. [rtn] ? ) 3 5 - u. [rtn] ?? Hoeveel bits gaan er per getal op de stack?
CELLS ( x -- y )
y
is het aantal bytes
dat nodig is voor x
cellen.
) 10 cells . [rtn] ?? Hoeveel bytes gaan er per getal op de stack?
LOOP
in hoofdstuk 11 nog eens nauwkeurig
en bedenk hoevaak er 'ha '
verschijnt
als je het woord HOEVAAK?
uit zou voeren.
) : HOEVAAK? 0 0 do ." Ha " loop ; [rtn] ( Bezint eer gij begint )
HERE
kun je zien hoever het woordenboek doorloopt,
en waar het geheugengebied dat nog vrij is, begint.
HERE ( - a )
a
is het adres
waar nieuwe woorden terecht komen.
Bij het definiëren van een woord verandert dat adres.
) here . [rtn] ? ) : punt . ; [rtn] ok ) here . [rtn] ? ) here punt [rtn] ? ) forget punt [rtn] ok ) here . [rtn] ?Een Forth woord bestaat in principe uit drie elementen:
CREATE ccc ( -- )
Maak een woord ccc
waarvan
de Body nog leeg is.
CREATE
gemaakt is,
doet niets anders dan het adres van zijn Body op stack zetten.
) here . [rtn] ? ) create DAAR [rtn] ) here . [rtn] ?
DAAR ( -- Body )
Zet het adres van de Body van DAAR
op stack.
) daar . [rtn] ?Dat is dus
HERE
) 10 cells allot [rtn] ok ) here . [rtn] ?
ALLOT ( n -- )
Reserveer n
bytes
bij HERE
DAAR
heet.
Je kunt ermee doen wat je wilt, Forth zal er uit zichzelf niet meer aankomen.
DAAR
levert een adres.
Dan kun je er dus ook @
en !
op loslaten.
) daar @ . [rtn] ? ) 1992 daar ! [rtn] ok ) 1 daar +! [rtn] ok ) daar @ . [rtn] ? ) daar @ daar 8 + ! [rtn] ok ) 7 daar +! [rtn] ok ) daar @ . [rtn] ? ) daar 8 + @ . [rtn] ?Je moet er zelf voor zorgen dat je niet buiten het gereserveerde gebied komt. Iets als
7 daar 100 - !zal waarschijnlijk een verrassend, maar zeker een ongewenst effekt hebben.
DUMP ( a n -- )
Laat vanaf adres a
de inhoud van een gebied van n
bytes zien.
) daar 40 dump [rtn] ?
ACCEPT ( a n -- m )
Ontvang maximaal n
karakters via het toetsenbord
en noteer die bij adres a
.
m
is het het aantal karakters dat werkelijk ingevoerd is.
De Return toets sluit de invoer af en telt zelf niet mee.
) daar 10 accept [rtn] ...... ok ) . [rtn] ? ) daar 40 dump [rtn] ?
CELL+ ( a1 -- a2 )
a2
is het adres
dat een cel verder ligt dan a1
.
) daar cell+ 10 accept daar ! [rtn] ...... ok ) daar 40 dump [rtn] ?[wordt vervolgd]
CHAR+ ( a1 -- a2 )
Adres a2
ligt een karakter verder dan a1
.
CHARS ( x -- y )
Voor x
karakters
zijn y
bytes nodig.
C@ ( a -- k )
Lees karakter k
uit adres a
.
C! ( k a -- )
Zet karakter k
in adres a
.
) daar char+ 10 accept daar c! [rtn] ok ) daar 11 chars dump [rtn] ? ) daar c@ . [rtn] ?In bovenstaand voorbeeld zet
C!
een bitpatroon in DAAR
dat aangeeft hoeveel karakters er ingevoerd zijn.
De programmeur moet zelf bijhouden dat het hier om een (klein) getal gaat
en niet om een karakter.
C!
en C@
onderscheiden zich
van !
en @
door de lengte van de bitpatronen die ze verplaatsen.
Met de inhoud of de betekenis ervan houden ze zich niet bezig.
C!
komt niet het volledige bitpatroon
dat op stack staat in RAM terecht;
het voorste stuk wordt domweg genegeerd.
Bij het teruglezen met C@
komen daar weer nullen voor in de plaats.
) -1 daar 8 + c! [rtn] ok ) daar 8 + c@ [rtn] ok ) dup hex . [rtn] ? ) dup binary . [rtn] ? ) decimal . [rtn] ?? Hoeveel bits leest
C@
?
) daar char+ daar c@ type [rtn] ?
TYPE ( a len -- )
Druk de tekst af
die op adres a
begint en uit len
karakters bestaat.
) daar count type [rtn] ?
COUNT ( a1 -- a2 k )
Zet de inhoud
van de karaktercel bij adres a1
op stack.
Het adres a2
is een karakter verder dan a1
.
Je kunt met COUNT
door een tekst heenlopen:
) daar count . [rtn] ? ) count emit [rtn] ? ) count emit [rtn] ? ) count emit [rtn] ? ( enzovoort ) ) drop [rtn] ok
COUNT
aldus kunnen definiëren:
: COUNT ( a1 -- a2 k ) dup ( a1 a1 ) char+ swap ( a2 a1 ) c@ ( a2 k ) ;Tussen haakjes vermeld ik steeds de situatie op de stack.
: TYPE ( a len -- ) dup 0 > ( a len groter-dan-nul? ) if 0 ( a len 0 ) do ( a ) count ( a+ k ) emit ( a+ ) loop \ ga terug naar COUNT else drop \ drop len then drop \ drop adres ;
\ ( -- )
Negeer de rest van de regel.
Dit geldt voor Forth, niet voor de lezer!
.. IF .. DO .. THEN .. LOOP ..
is dus niet mogelijk.
.. IF .. IF .. THEN .. THEN ..
.. IF .. THEN .. IF .. THEN ..
.. BEGIN .. IF .. UNTIL .. THEN ..
.. DO .. IF .. BEGIN .. UNTIL .. THEN .. LOOP ..
.. IF .. IF .. THEN .. ELSE .. IF .. ELSE .. THEN .. THEN ..
) 29 10 /mod .s [rtn] ? ) . . [rtn] ?
/MOD ( x y -- r )
Deel x
door y
.
(een geheel getal!) is het resultaat,
en r
is de rest. Uitspraak: "slash-mod".
) 29 10 / . [rtn] ? ) 29 10 mod . [rtn] ?
/ ( x y -- )
Deel x
door y
.
is het uotient, een geheel getal!
MOD ( x y -- r )
Deel x
door y
.
r
is de rest. MOD is een afkorting van de wiskunde term Modulo.
) : MET1 ( prijs-zonder-BTW -- ) 100 / 117 * . ; ) : MET2 ( prijs-zonder-BTW -- ) 117 * 100 / . ;? Welke methode (proberen!) voldoet het beste,
MET1
of MET2
? Kun je de verschillen verklaren?
) : MET3 ( netto-prijs -- ) 117 100 */ . ;
*/ ( x y z -- x*y/z )
Het voordeel van */
boven een losse *
en /
is,
dat bij */
het tussenresultaat x*y
een getal
(een bitpatroon) mag worden dat te groot (te lang) is voor de stack.
Uitspraak: "star-slash".
value PERCENTAGE 17 to percentage ! : MET ( netto-prijs -- eindbedrag) 100 percentage + 100 */ ; : .MET met . ;
MET
is niet meer afhankelijk van de hoogte van de BTW.
Je kunt er zelfs kortingen mee berekenen:
) -15 to percentage ) 1745 .met [rtn] ? ) 495 .met [rtn] ? ) 1245 met .met [rtn] ? ( dubbele korting )
*/MOD ( x y z -- rest x*y/z )
) 4 5 6 */mod . . [rtn] ?Overzicht van de delingen tot nu toe:
*/MOD */ /MOD /
en MOD
AND ( x y -- z )
x
en y
worden
bit voor bit ge-AND. Een z-bit is 1 als het x-bit en het y-bit beide 1 zijn.
Zo ook:
OR ( x y -- z )
Een z-bit is 1 als het x-bit
en het y-bit niet beide 0 zijn.
XOR ( x y -- z )
Een z-bit is 1 als het x-bit
en het y-bit verschillend zijn.
) : NEGATIEF? ( x y -- vlag ) ) xor 0 < ;? Wat is het verband tussen de vlag die
NEGATIEF?
levert en het teken van x
en y
?
2DROP ( x y -- )
Verwijder 2 getallen van de stack.
2DUP ( x y -- x y x y )
2DROP
als volgt definiëren:
: 2DROP DROP DROP ;
2DUP
eruit zien?
) : STIP ." ." ;
STIP
?
.R ( x n -- )
Druk het getal x
af,
rechtsgericht in een veld van n
posities, zonder afsluitende spatie.
Als het getal daar niet in past, wordt het toch volledig afgedrukt. (punt r)
) cr 1 4 .r [rtn] ? ) cr 20 4 .r [rtn] ? ) cr 300 4 .r [rtn] ? ) cr 2000 4 .r [rtn] ? ) cr 10000 4 .r [rtn] ? ) cr 7 0 .r 8 0 .r [rtn] ?
ABS ( x -- y )
y
is de absolute waarde van x
.
: 1+ 1 + ; : 1- 1 - ; : TUCK swap over ; : 2* 2 * ; : 2/ 2 / ; : NIP swap drop ; : 0> 0 > ; : 0< 0 < ; : 0= 0 = ; : 0<> 0 <> ;? Geef het stackeffect van deze woorden.
+ - SWAP DUP DROP OVER ! @ +! = TRUE FALSE
<> U< CELL+ C! C@
enz. Ook COUNT
waar ik een paar hoofdstukken terug een Hi-level definitie van heb gegeven,
zal meestal een primitieve zijn.
SEE
.
SEE ccc ( -- )
SEE
gevolgd
door de naam van een Hi-level woord geeft inzage in de bouw van dat woord.
x
en y
is
het grootste getal (GGD) waarvoor
de delingen x/GGD
en y/GGD
opgaan,
d.w.z. nul als rest hebben.
Als je de breuk x/y
wilt vereenvoudigen,
moet je teller en noemer door hun GGD delen.
g
en het kleinste getal k
.
g=0
dan GGD=1
.
k=0
dan GGD=g
.
g
door de rest die onstaat
als je g
door k
deelt.
: GGD ( x y -- ggd ) 2dup or 0= if drop 1 then abs swap abs 2dup < if swap then begin dup while tuck mod repeat drop ;? Beantwoord de volgende vier vragen door met de hand, d.w.z. met potlood en papier en zonder computer, het programma woord voor woord uit te voeren.
x=0
en y=0
?
x=0
en y=5
?
x=-4
en y=0
?
x=3
en y=-6
?
>R ( x -- ) ( R: -- x )
Zet x
op
de Return stack.
R> ( -- x ) ( R: x -- )
Haal x
weer
van de Return stack af.
R@ ( -- x ) ( R: x -- x )
Lees de x
die op de Return stack staat.
\ Vereenvoudig de breuk x1/y1 tot x2/y2. : VEREENVOUDIG ( x1 y1 -- x2 y2 ) 2dup ggd tuck / >r / r> ;? Zet, voordat je verder leest, de situatie op stack achter iedere regel.
\ Vereenvoudig de breuk x1/y1 tot x2/y2. : VEREENVOUDIG ( x1 y1 -- x2 y2 ) 2dup ggd ( x1 y1 ggd ) tuck ( x1 ggd y1 ggd ) / ( x1 ggd y2 ) >r ( x1 ggd ) ( r: y2 ) / ( x2 ) ( r: y2 ) r> ( x2 y2 ) ;
Omdat ik VEREENVOUDIG
zo'n lang woord vind,
geef ik hem een kortere naam.
) : VV vereenvoudig ;
) 1234 2468 vv . . [rtn] ?
De woorden :
en ;
maken gebruik van de Return stack.
DO I
en LOOP
meestal ook.
Daarom gelden de volgende beperkingen:
>R
en R>
moeten genest zijn
t.o.v. : ;
en DO LOOP
.
>R
en R>
mogen alleen binnen een definitie voorkomen.
- In een Do-Loop geeft
I
tussen >R
en R>
een onjuiste waarde.
) : PLUS + ; ) : + ( x y -- ) ) 2drop cr ." vandaag wordt er niet opgeteld " ;Tijdens het definiëren van
+
zal Forth meedelen
dat er al een definitie met de naam +
bestaat.
Dat is geen foutmelding. Het is slechts een mededeling voor de programmeur.
Het woord wordt wel gebouwd.
+
aanroepen.
) 4 5 + . [rtn] ?De oude betekenis bestaat nog wel en definities waar de oude
+
in voorkomt blijven op de oude manier werken.
) 4 5 plus . [rtn] ?Na
) FORGET + [rtn] okzal de oude
+
weer aanspreekbaar zijn,
want FORGET
heeft alleen de nieuwe +
gevonden.
) 4 5 + . [rtn] ?? Wat zal het gevolg zijn van de volgende definitie?
: FORGET ." Nooit! " ;In de programmeertaal Forth heb je grote vrijheden. Het devies is: alles moet mogelijk zijn. De prijs daarvan is, dat je niet gewaarschuwd kunt worden als je iets onhandigs doet. De programmeur draagt de verantwoordelijkheid voor wat hij doet en moet daarom ook begrijpen wat hij doet.
PIEP - Syntax Error
of wat voor Error dan ook, of op een struktureler manier,
tegen zichzelf beschermd te worden.
De ander bejubelt het feit dat Forth
de volledige toegang verschaft tot de computer, "je kunt overal aankomen".
S>D ( x -- xlo xhi )
Breid een Signed Single Number uit tot een Signed Double Number
met dezelfde waarde. (xlo=x)
D. ( xlo xhi -- )
Druk de laatste twee getallen op de stack
samen af als een dubbelgetal.
) 3 S>D .S [rtn] ? ) D. [rtn] ? ) -3 S>D .S D. [rtn] ?Als je een punt gebruikt bij de invoer van een getal maakt Forth er een dubbelgetal van.
) 30. .S [rtn] ? ) D. [rtn] ? ) -30. .S D. [rtn] ? ) 3.0 .S D. [rtn] ? ) .30 .S D. [rtn] ?De plaats van de punt in het getal is niet van belang.
D>S ( xlo xhi -- x )
Kort een dubbelgetal in
tot een gewoon getal.
Omdat er geen foutmelding komt als de waarde niet in een cel past,
kan de waarde hierdoor veranderen.
) 3. D>S .S . [rtn] ?Meer woorden voor dubbelgetallen.
2DROP ( xlo xhi -- )
2DUP ( ? )
2OVER ( ? )
2SWAP ( ? )
2ROT ( ? )
D+ ( xlo xhi ylo yhi -- zlo zhi )
z
is de som van x
en y
.
D- ( ? )
D2* ( xlo xhi -- ylo yhi )
D2/ ( xlo xhi -- ylo yhi )
D= ( ? )
D< ( ? )
DNEGATE ( ? )
S>D
is
: S>D DUP 0< ;Bij een negatief getal wordt er True voorgezet, anders False.
) 3 S>D .S [rtn] ? ) DNEGATE .S D. [rtn] ? ) -3 S>D .S [rtn] ? ) DNEGATE .S D. [rtn] ?Definitie van
D>S
: D>S DROP ;De voorste cel wordt domweg weggegooid.
: ENKEL? ( xlo xhi -- xlo xhi vlag ) over s>d ( xlo xhi xlo xhi' ) 2over ( xlo xhi xlo xhi' xlo xhi ) d= ; ( xlo xhi vlag )Dat kan korter.
: ENKEL? ( xlo xhi -- xlo xhi vlag ) over 0< ( xlo xhi xhi' ) over = ;? Wat is de betekenis van de vlag die
ENKEL?
levert?
MAX-N
het grootste (positieve) Signed enkelgetal geeft.
) : MAX-N -1 0 D2/ DROP ;? Leg uit, waarom
MIN-N
het kleinste (negatieve) Signed enkelgetal geeft.
) : MIN-N 0 1 D2/ DROP ;? Maak zo ook de woorden
MAX-DN
en MIN-DN
voor dubbelgetallen.
.(
(Dot Paren)
heeft die taak van mij overgenomen,
met dit verschil dat zij naar een haakje sluiten zoekt
in plaats van naar een aanhalingsteken.
Ik gun ieder zijn eigenaardigheden.
Zij is wel een Immediate word, in dienst van de Klantenservice
en een snelle typiste, maar van Compileren heeft ze geen verstand.
En ik ben nu Only Compiling.
."
(Dot Quote)
) : DOT-QUOTE ." waterval " ; [rtn] ? ) SEE DOT-QUOTE [rtn] ? ) DOT-QUOTE [rtn] ? ) ) : DOT-PAREN .( Tot Ziens! ) ; [rtn] ? ) SEE DOT-PAREN [rtn] ? ) DOT-PAREN [rtn] ?De programmatekst die Forth te verwerken krijgt, heet de invoerstroom.
."
en .(
lezen zelf tekst van de invoerstroom.
Omdat ze Immediate zijn, doen ze dat ook tijdens het definiëren.
CHAR ( ccc -- k )
Lees het volgende woord
van de invoerstroom en zet de ASCII code van de eerste letter op stack.
) CHAR A . [rtn] ? ) CHAR a . [rtn] ? ) CHAR . . [rtn] ?Omdat
CHAR
niet Immediate is,
doet hij tijdens het definiëren nog niets.
Pas als het nieuwe woord uitgevoerd wordt,
leest CHAR
de invoerstroom.
) : LETTER ( ccc -- ) ) ." heeft ASCII code " ) CHAR . ; ) LETTER A [rtn] ? ) LETTER a [rtn] ?
CHAR
heeft een variant die [CHAR]
heet.
[CHAR] ( ccc -- )
Zet tijdens het compileren
de ASCII code van de eerste letter van ccc
als een getal in de definitie.
Omdat [CHAR]
Immediate is, komt hij tijdens het compileren in aktie.
Buiten een definitie heeft hij geen betekenis.
) : A-KODE ( -- k ) ) 65 ; ) : KODE-A ( -- k ) ) [CHAR] A ; ) SEE A-KODE [rtn] ? ) SEE KODE-A [rtn] ?Voor lezers die geen
SEE
in hun Forth hebben:
A-KODE
en KODE-A
leveren niet alleen hetzelfde resultaat,
ze zijn ook hetzelfde gebouwd.
[CHAR] Azet tijdens het definiëren het getal 65 in de definitie.
IMMEDIATE ( -- )
Maak het laatst gedefinieerde woord Immediate.
) : [.S] ( -- ) ) .S ; IMMEDIATE
.S
laat de getallen op stack zien. [.S]
doet hetzelfde,
maar dan tijdens het compileren, en laat geen sporen na in de definitie.
) 5 5555 [rtn] ok ) : TEST1 .S ; [rtn] ? ) : TEST2 [.S] ; [rtn] ? ) TEST1 [rtn] ? ) TEST2 [rtn] ? ) .S [rtn] ? ) [.S] [rtn] ? ) SEE TEST1 [rtn] ? ) SEE TEST2 [rtn] ?? Kun je aannemelijk maken waarom
;
een Immediate woord zal zijn?
."
is een Compiler woord, en dus ook Immediate. Only Compiling.
.(
is Immediate, maar geen Compiler woord
en heeft geen effekt op definities.
IF ELSE THEN BEGIN UNTIL WHILE REPEAT DO LOOP
enz.
noemt men besturingswoorden.
Zij organiseren tijdens het compileren de vertakkingen.
Besturingswoorden zijn dus Compiler woorden, onbruikbaar buiten definities.
?DO ( n2 n1 -- )
Bijna hetzelfde als DO
.
?DO
naar het eerste woord achter LOOP
springt als n2
gelijk is aan n1
.
?DO
is heel slordig. Juister is:
?DO ( -- )
(compilerend:) Installeer ?LUSJESMAN
in de definitie.
?LUSJESMAN ( n2 n1 -- )
(uitvoerend:)
Begin aan een lus, tenzij n1=n2
.
LEAVE ( -- )
Ga naar het eerste woord achter
LOOP
(alleen tussen DO
en LOOP
te gebruiken).