如何在 Forth 中输入数字
How to enter numbers in Forth
Basic 中是否有类似 input
或 Forth 中 C 中的 scanf("%d")
之类的东西?
大概是这样的:
200 buffer: buf
: input ( -- n ) buf 200 accept
some-magic-filter
buf swap evaluate ;
上面代码中的问题是,如何定义一个只传递数字而不传递任何单词、定义等的过滤器?
Rosetta Code 建议此代码片段与 GForth 0.6.2 配合使用,以确定输入字符串是否为数字:
: is-numeric ( addr len -- )
2dup snumber? ?dup if
0< if
-rot type ." as integer = " .
else
2swap type ." as double = " <# #s #> type
then
else 2dup >float if
type ." as float = " f.
else
type ." isn't numeric in base " base @ dec.
then then ;
该标准仅指定了一个低级别的 >NUMBER
词来解释整数。
OTOH 使用 EVALUATE
将字符串转换为数字是一种快速而肮脏的方法。要么在不检查的情况下使用它(在可信输入的情况下),要么根本不使用它。尝试在 EVALUATE
之前过滤字符串是一个坏主意:它具有 >NUMBER
字本身的成本和低重用因子。
注意: >NUMBER
和 EVALUATE
均未检测到数字溢出。
在任何情况下,您输入单格整数的单词可以定义为:
: accept-number ( -- n )
PAD DUP 80 ACCEPT ( addr u ) StoN ( n )
;
在可信输入的情况下你可以定义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
;
否则(在不受信任的输入的情况下)您有两个选择:依赖特定 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:
找到提到的库
- Substring matching functions图书馆
- Resolvers 示例(针对各种词位)
我为 Camel Forth 构建了一个类似于 #INPUT word 的 BASIC,以便为 BASIC 用户提供更熟悉的东西。这比人们想象的要多。它以 $ACCEPT 开头,可用于喜欢输入字符串变量或内存块。
NUMBER的定义?这里仅适用于单个整数,但它在 GForth 上编译。如果转换不好则输出 true; SNUMBER 的反转?
DECIMAL
: NUMBER? ( addr len -- n ?) \ ?=0 is good conversion
( -- addr len) \ bad conversion
OVER C@ [CHAR] - = DUP >R \ save flag for later
IF 1 /STRING THEN \ remove minus sign
0 0 2SWAP >NUMBER NIP NIP \ convert the number
R> IF SWAP NEGATE SWAP THEN \ negate if needed
;
: $ACCEPT ( $addr -- ) CR ." ? " DUP 1+ 80 ACCEPT SWAP C! ;
: #INPUT ( variable -- ) \ made to look/work like TI-BASIC
BEGIN
PAD $ACCEPT \ $ACCEPT text into temp buffer PAD
PAD COUNT NUMBER? \ convert the number in PAD
WHILE \ while the conversion is bad do this
CR ." Input error "
CR DROP
REPEAT
SWAP ! ; \ store the number in the variable
\ USAGE: VARIABLE X
\ X #INPUT
Basic 中是否有类似 input
或 Forth 中 C 中的 scanf("%d")
之类的东西?
大概是这样的:
200 buffer: buf
: input ( -- n ) buf 200 accept
some-magic-filter
buf swap evaluate ;
上面代码中的问题是,如何定义一个只传递数字而不传递任何单词、定义等的过滤器?
Rosetta Code 建议此代码片段与 GForth 0.6.2 配合使用,以确定输入字符串是否为数字:
: is-numeric ( addr len -- )
2dup snumber? ?dup if
0< if
-rot type ." as integer = " .
else
2swap type ." as double = " <# #s #> type
then
else 2dup >float if
type ." as float = " f.
else
type ." isn't numeric in base " base @ dec.
then then ;
该标准仅指定了一个低级别的 >NUMBER
词来解释整数。
OTOH 使用 EVALUATE
将字符串转换为数字是一种快速而肮脏的方法。要么在不检查的情况下使用它(在可信输入的情况下),要么根本不使用它。尝试在 EVALUATE
之前过滤字符串是一个坏主意:它具有 >NUMBER
字本身的成本和低重用因子。
注意: >NUMBER
和 EVALUATE
均未检测到数字溢出。
在任何情况下,您输入单格整数的单词可以定义为:
: accept-number ( -- n )
PAD DUP 80 ACCEPT ( addr u ) StoN ( n )
;
在可信输入的情况下你可以定义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
;
否则(在不受信任的输入的情况下)您有两个选择:依赖特定 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:
找到提到的库- Substring matching functions图书馆
- Resolvers 示例(针对各种词位)
我为 Camel Forth 构建了一个类似于 #INPUT word 的 BASIC,以便为 BASIC 用户提供更熟悉的东西。这比人们想象的要多。它以 $ACCEPT 开头,可用于喜欢输入字符串变量或内存块。
NUMBER的定义?这里仅适用于单个整数,但它在 GForth 上编译。如果转换不好则输出 true; SNUMBER 的反转?
DECIMAL
: NUMBER? ( addr len -- n ?) \ ?=0 is good conversion
( -- addr len) \ bad conversion
OVER C@ [CHAR] - = DUP >R \ save flag for later
IF 1 /STRING THEN \ remove minus sign
0 0 2SWAP >NUMBER NIP NIP \ convert the number
R> IF SWAP NEGATE SWAP THEN \ negate if needed
;
: $ACCEPT ( $addr -- ) CR ." ? " DUP 1+ 80 ACCEPT SWAP C! ;
: #INPUT ( variable -- ) \ made to look/work like TI-BASIC
BEGIN
PAD $ACCEPT \ $ACCEPT text into temp buffer PAD
PAD COUNT NUMBER? \ convert the number in PAD
WHILE \ while the conversion is bad do this
CR ." Input error "
CR DROP
REPEAT
SWAP ! ; \ store the number in the variable
\ USAGE: VARIABLE X
\ X #INPUT