forth

How to enter numbers in Forth


Is there something like input in Basic or scanf("%d") in C in Forth?

Probably it will be something like this:

200 buffer: buf
: input ( -- n ) buf 200 accept 
  some-magic-filter
  buf swap evaluate ;

The problem in the above code, is how to define a filter that will pass only numbers, but not any words, definitions, etc?


Solution

  • The standard specifies only a low level >NUMBER word to interpret integer numbers. OTOH using EVALUATE to convert strings into numbers is a quick and dirty way. Either use it without checks (in the case of trusted input) or do not use it at all. Trying to filter the string before EVALUATE is a bad idea: it has cost of >NUMBER word itself and low reusing factor.

    NB: neither >NUMBER nor EVALUATE detects numeric overflow.

    In any case, your word to input a single-cell integer can be defined something like:

    : accept-number ( -- n )
      PAD DUP 80 ACCEPT ( addr u ) StoN ( n )
    ;
    

    In the case of trusted input you can define StoN like

    : StoN ( addr u -- x )
      STATE @ ABORT" This naive StoN should not be used in compilation state"
      DEPTH 2- >R
        EVALUATE
      DEPTH 1- R> <> IF -24 THROW THEN
      \ check depth to accept the single-cell numbers only
    ;
    

    Otherwise (in the case of untrusted input) you have two choices: to rely on the specific words of a particular Forth system or to use some (perhaps your own) library.

    I use the following lexicon to define StoN:

    \ ---
    \ The words from Substring Matching library
    \ (where length is counted in address units)
    
    : MATCH-HEAD ( a u a-key u-key -- a-right u-right true | a u false ) 
      2 PICK OVER U< IF  2DROP FALSE EXIT THEN 
      DUP >R
      3 PICK R@ COMPARE IF  RDROP FALSE EXIT THEN 
      SWAP R@ + SWAP R> - TRUE
    ; 
    
    \ ---
    \ The words from Literals interpreting library
    \ (where prefix 'I-' is shortcut for Interpret)
    
    : I-DLIT ( a u -- x x true | a u false ) 
      2DUP S" -"  MATCH-HEAD >R
      DUP 0= IF  NIP RDROP EXIT THEN 
      0 0 2SWAP >NUMBER NIP IF  RDROP 2DROP FALSE EXIT THEN 
      R> IF  DNEGATE THEN  2SWAP 2DROP TRUE
    ; 
    
    : I-LIT ( a u -- x true | a u false ) 
      I-DLIT IF  D>S TRUE EXIT THEN  FALSE
    ;
    

    After that StoN can be defined as:

    : StoN ( a u -- x ) I-LIT IF EXIT THEN -24 THROW ;
    

    The mentioned libraries can be found at GitHub: