|
| ||||
|
Rood en wit |
Antonio heeft een winkeltje. Hij verkoopt wijn. Er komt iemand binnen
die 2 flessen wil.
990 value ROOD-PRIJS \ Prijs per fles rode wijn 890 value WIT-PRIJS \ Prijs per fles witte wijn : ERBIJ * dup . + ; \ Bedrag afdrukken en bijtellen : ROOD rood-prijs erbij ; : WIT wit-prijs erbij ; : NUL 0 dup . ; \ Begin met subtotaal nul. : TOTAAL . ; \ Einde van de bestellingNa een \ is de rest van de regel commentaar. Namen van nieuwe definities zijn voor de duidelijkheid vet gedrukt. |
Woorden definiëren |
Een commando heet in Forth een «woord».
Woorden definiëer je met «definiërende woorden». In bovenstaand programma komen twee van die definiërende woorden voor:
990 value ROOD-PRIJSROOD-PRIJS is een soort variabele. Als je het later uitvoert (intypt en dan op [enter] drukt), zet het 990 op stack.
: ERBIJ * dup . + ;ERBIJ is een soort macro. Als je het later intypt wordt de reeks commando's * dup . +uitgevoerd. Punt-komma is de afsluiter. Omdat je in een Forth-programma steeds nieuwe woorden maakt kan het
er heel nederlands uit gaan zien, want niemand verplicht je om voor de
namen engelse woorden te kiezen.
|
ERBIJ van dichtbij |
Het woord ERBIJ is het interessantste nieuwe woord van het bovenstaande
programma. Het verwacht 3 getallen op de stack:
Alleen dat subtotaal blijft achter op de stack. In Forth geef je dat aan met een stackdiagram: ERBIJ ( subtotaal1 #flessen stuksprijs -- subtotaal2 )Het valt op dat er in ERBIJ alleen bewerkingen staan. Je ziet geen verwijzingen naar de te bewerken data, want de gegevens worden naamloos op de stack verwacht. ERBIJ komt voor in ROOD en WIT en het is nauwelijks zinvol om het interactief (bij de klant in de winkel) te gebruiken. Natuurlijk is het wel interactief te gebruiken, bijvoorbeeld om het te testen. Zorg er dan voor dat er geschikte data op de stack klaarstaat: 1000 25 105 erbij [enter] 2625 . [enter] 3625D.w.z., 25 dingen van 105 kosten 2625, en het subtotaal dat 1000 was, is 3625 geworden. |
Wat gebeurt er nu eigenlijk? |
In onderstaand schema kun je de nesting van Forth-woorden en stack-data van de bestelling van 1 ROOD en 1 WIT tot in details volgen.
|
Olie, azijn en dozen |
Antonio verkoopt ook olijfolie en azijn. Bovendien zijn alle artikelen per doos van 12 stuks verkrijgbaar. Op dozen geeft Antonio korting: 12 halen, 11 betalen. 490 value OLIE-PRIJS \ Prijs per fles olijfolie 90 value AZIJN-PRIJS \ Prijs per fles azijn : OLIE olie-prijs erbij ; : AZIJN azijn-prijs erbij ; : DOZIJN 11 * ; \ 12 halen 11 betalen Een klant wil 4 flessen olijfolie, 3 dozen met 12 flessen azijn en twee flessen rode wijn:
Dit vindt Antonio nog te veel typewerk. Hij bedenkt afkortingen: : RW rood ; : WW wit ; : OL olie ; : AZ azijn ; : DOZ dozijn ; : N nul ; : TT totaal ; Nu ziet dezelfde bestelling er zo uit:
|
Kort, korter, kortst |
Het hele programma samengevat, met stackdiagrammen:
990 value RW-PRIJS ( -- x ) \ Prijs per fles rode wijn 890 value WW-PRIJS \ Prijs per fles witte wijn 490 value OL-PRIJS \ Prijs per fles olijfolie 90 value AZ-PRIJS \ Prijs per fles azijn : ERBIJ ( st1 x y -- st2 ) * dup . + ; : ROOD ( st1 x -- st2 ) rw-prijs erbij ; : WIT ww-prijs erbij ; : OLIE ol-prijs erbij ; : AZIJN az-prijs erbij ; : NUL ( -- 0 ) 0 dup . ; \ Begin met subtotaal nul. : TOTAAL ( st -- ) . ; \ Einde van de bestelling : DOZIJN ( x1 -- x2 ) 11 * ; \ 12 halen, 11 betalen : RW ( st1 x -- st2 ) rood ; : WW wit : OL olie ; : AZ azijn ; : N ( -- 0 ) nul ; : TT ( st -- ) totaal ; : DOZ ( x1 -- x2 ) dozijn ; Als je direct de korte woorden definiëert en de lange achterwege laat, blijft er dit over: 990 value RW-PRIJS ( -- x ) \ Rode wijn 890 value WW-PRIJS \ Witte wijn 490 value OL-PRIJS \ Olijfolie 90 value AZ-PRIJS \ Azijn : ERBIJ ( st1 x y -- st2 ) * dup . + ; : RW ( st1 x -- st2 ) rw-prijs erbij ; : WW ww-prijs erbij ; : OL ol-prijs erbij ; : AZ az-prijs erbij ; : N ( -- 0 ) 0 dup . ; : TT ( st -- ) . ; : DOZ ( x1 -- x2 ) 11 * ; \ 12 halen, 11 betalen En in de beruchte onleesbare stijl, onmenselijk kort, maar probleemloos voor Forth ...
... liever niet doen dus. |
Re-entrant |
Er is een klant in de winkel. Zij neemt 1 fles olijfolie en aarzelt of
ze nog meer aan zal schaffen. Dan komt er iemand binnen die kennelijk
haast heeft. Hij wil 2 flessen olijfolie en een fles azijn, rekent 1070
af en verdwijnt weer. De andere klant heeft ondertussen haar besluit
genomen en wenst nog 1 fles rode wijn. Zij betaalt 1480.
|
Idiot proof |
Als je niet wilt dat de gebruiker direct in de Forth-omgeving werkt (met
alle vrijheden en dus risico's van dien) moet je het accepteren en
interpreteren van toetsaanslagen expliciet in het programma regelen. Je
kunt dan precies vastleggen wat de gebruiker moet en mag doen.
Het programma start met KASSA [enter]De gebruiker blijft deze cyclus van mogelijkheden doorlopen totdat hij een keer op [escape] drukt. Regels tussen haakjes zijn optioneel:
create PRODUCTENLIJST ( -- adr ) char R , 990 , char W , 890 , char O , 490 , char A , 90 , char ? , 0 , 4 constant #PRODUCTEN ( -- x ) : ERBIJ ( st1 x y -- st2 ) * dup . + ; : PRODUCT ( st x ch -- st ) productenlijst #producten 0 do 2dup @ = if leave then cell+ cell+ loop nip @+ emit space @ erbij ; : TOTAAL ( st 0 ch -- ) emit space drop . ; : 1..9? ( ch -- ch vlag ) dup [char] 1 - 9 u< ; : 0..9? ( ch -- ch vlag ) dup [char] 0 - 10 u< ; : CIJFER ( st x1 ch -- st x2 ) dup emit [char] 0 - swap 10 * + ; : DOOS ( st x1 ch -- st x2 ) emit 11 * ; : ?ESCAPE ( st 0 ch -- .. ) 27 over = if abort then ; : N ( -- ) 0 \ subtotaal BEGIN cr 0 \ x BEGIN key ?escape \ uitgang via [escape] [char] T over = if totaal exit then \ T 1..9? and ?dup UNTIL cijfer key \ 1..9 0..9? if cijfer key then \ 0..9 [char] D over = if doos key then \ D space product \ R,W,O,A of .. AGAIN ; : KASSA ( -- ) begin n again ; Een paar verduidelijkingen:
|