PiF 4

  <terug>
SCAN
WHILE nader bekeken
Menu's zonder CASE
DOES>


SCAN ( a1 n1 ch -- a2 n2 )

Het woord SCAN hebben we nodig voor "Menu's" in deel 2 van deze PiF.

Hoewel SCAN geen standaard Forthwoord is, heeft iedere Forth wel zo'n functie (in machinetaal). Die functie is namelijk nodig voor het lezen van de inputstroom. Als je geluk hebt, kent je Forth SCAN als los woord, als je pech hebt bestaat de functie alleen als onderdeel van een complexer woord waardoor je hem niet apart aan kunt spreken.

SCAN zoekt in de string 'a1,n1' naar de plek waar het karakter 'ch' voor de eerste keer voorkomt. SCAN kapt het stuk string weg dat voorafgaat aan het gevonden karakter. De reststring 'a2,n2' begint dus met karakter 'ch', behalve als 'n2' nul is, want dat betekent dat 'ch' niet gevonden is.

Voorbeelden:

 S" Forth-gg" CHAR F  SCAN  TYPE  [rtn] Forth-gg OK
 S" Forth-gg" CHAR g  SCAN  TYPE  [rtn] gg OK
 S" Forth-gg" CHAR h  SCAN  TYPE  [rtn] h-gg OK
 S" Forth-gg" CHAR i  SCAN  TYPE  [rtn]  OK

 1000 500 55 SCAN DUMP [RTN] ...
In het laatste voorbeeld hangt het resultaat natuurlijk af van de inhoud van [1000,1500).

Controleer of jouw Forth SCAN kent en of het net zo werkt als hier beschreven.

Hier volgen een paar SCAN definities om het gebruik van WHILE te demonstreren.

: scan1 ( a1 n1 ch -- a2 n2 )               \ n is unsigned
  >r                       \ a1 n1  r: ch
  begin dup                \ Nog meer?
  while over c@ r@ <>      \ Niet gevonden?
  while 1 /string          \ Volgende positie
  again
  then
  then
  r> drop ;
De laatste THEN hoort bij de eerste WHILE.
: scan2 ( a1 n1 ch -- a2 n2 )               \ n is unsigned
  >r over + swap          \ Eindadres Beginadres
  begin  2dup -           \ Nog meer?
  while  count r@ =       \ Gevonden?
  until  1-               \ Laatste COUNT terugdraaien
  then   tuck -           \ a2  n2
  r> drop ;
Als WHILE een verschil van nul aantreft, springt hij naar THEN.
Let op de positie van '1-' tussen UNTIL en THEN.

Wat gebeurt er als 'n1' nul is?
Wat zal er gebeuren als 'n1' gelijk aan -1 is?
Welke van de twee definities is de beste?

REPEAT is gelijk aan een AGAIN gevolgd door een THEN.


Menu's

Een menu laat de gebruiker kiezen uit een aantal 1-letter-commando's en voert de gekozen optie meteen uit. De commandokarakters hoeven geen aaneengesloten rij van ASCII-codes te vormen.

We gebruiken straks

: -positie ( ch a n -- -pos ) rot scan nip ;

Wat stelt die '-pos' voor?

\ ----- RISP - Windrichtingen in het Spaans
decimal
\ ----- Algemene menu tools -----
: hoofdletter ( ch -- CH ) dup [char] a - 26 u< bl and xor ;
: -positie ( ch a n -- -pos ) rot scan nip ;
: doexe does> ( index -- ) swap cells + @ execute ;

\ ----- Menu-specifieke code -----
\ ( Commando) Token van de actie
  ( N) :noname ." Norte  " ;
  ( O) :noname ." Este   " ;
  ( Z) :noname ." Sur    " ;
  ( W) :noname ." Oveste " ;
create risp.exe , , , ,                                  \ 1a)
doexe

: risp ( -- )
  cr ." Windrichtingen in het Spaans. N,O,Z,W:  "
  begin key hoofdletter
        s" NOZW" -positie
        ?dup
  until 1- risp.exe ;                                    \ 1b)
\ ----- Einde -----

1a) In omgekeerde volgorde dus! Waarom gaat dit toch goed?
1b) Waarom 1- ?

Als je DOEXE uitvoert, komt DOES> in actie. DOES> zoekt het nieuwste woord op in het woordenboek (in dit geval RISP.EXE) en schrijft daar het adres in van de code die achter DOES> staat. Klaar. Die code zelf wordt op dat moment niet uitgevoerd!

DOES> vertelt aan een datastructuur wat het met zijn data moet doen. DOES> richt zich altijd tot het nieuwste woord in het woordenboek.

Wat doet RISP.EXE nu als je het aanroept?
  1. het zet zijn data-adres op stack
  2. het voert de code swap cells + @ execute uit. Deze code verwacht dat er onder het data-adres een 'index' op stack staat.
Het data-adres zelf krijgen we niet meer te zien.


Het is handig om de menu-specifieke code kort te houden, want die moet je bij ieder menu opnieuw schrijven. De algemene menu tools hoef je maar één keer te maken.
Met DOES> hevel je code over naar de algemene menu tools. De voordelen hiervan merk je, als je meer menu's binnen een programma moet maken.
 
Groeten,
A.N.
  <terug>