首页 > 解决方案 > 如何在 Forth 中输入数字

问题描述

Forthinput的 Basic 或C 中是否有类似的东西?scanf("%d")

可能会是这样的:

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

上面代码中的问题是,如何定义一个只传递数字而不传递任何单词、定义等的过滤器?

标签: forth

解决方案


该标准仅指定一个低级>NUMBER字来解释整数。OTOHEVALUATE用于将字符串转换为数字是一种快速而肮脏的方式。要么不检查就使用它(在可信输入的情况下),要么根本不使用它。尝试过滤之前的字符串EVALUATE是一个坏主意:它本身具有单词成本>NUMBER和低重用因子。

注意:既不>NUMBER也不EVALUATE检测数字溢出。

在任何情况下,您输入单格整数的单词都可以定义为:

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

在可信输入的情况下,您可以定义StoN如下

: 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
;

否则(在输入不受信任的情况下)您有两个选择:依赖特定 Forth 系统的特定单词或使用某些(可能是您自己的)库。

我使用以下词典来定义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
;

之后StoN可以定义为:

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

提到的库可以在 GitHub 上找到:


推荐阅读