2>r 和 2r> 是如何工作的?
How do 2>r and 2r> work?
最近在comp.lang.forth上发现了一些代码,好心的Coos Haak写的,我看不懂。
应该是对括号之间的数字求和或相乘。例如,
( 1 2 3 +) ok
. 6 ok
为方便起见,我将其复制在这里:
: (
depth 1+ r> 2>r
;
: cond
depth j >
;
: done
2r> rdrop 2>r
;
: +)
begin cond
while +
repeat
done
;
: *)
begin cond
while *
repeat
done
;
我看到了短语 r> 2>r
和 2r> rdrop 2>r
。但是,我对他们在做什么感到很困惑。我猜测左括号处的堆栈深度以某种方式隐藏在 return 堆栈中。但是,我不明白。
这些对 return 堆栈有什么作用?
在 Gforth 文档中我看到:
r> R:w – w core “r-from”
2>r d – R:d core-ext “two-to-r”
2r> R:d – d core-ext “two-r-from”
rdrop R:w – gforth “rdrop”
w Cell, can contain an integer or an address
d double sized signed integer
这跟w和d的转换有关系吗?
2>r
(以及 Forth 200x 词 n>r
)保留推入 return 堆栈的元素的顺序。因此,如果数据堆栈上有 ( 1 0 )
,堆栈顶部为 0,那么在 2>r
之后,return 堆栈顶部将有 0,其下方有 1 . 2>r
因此是可定义的,而不是
: 2>r ]] >r >r [[ ; immediate
但是作为:
: 2>r ]] swap >r >r [[ ; immediate
这些定义是等价的:
: a ]] 0 >r 1 >r [[ ; immediate
: b ]] 0 1 2>r [[ ; immediate
Coos Haak 在该代码中所做的是将一个值滑动到 return 堆栈顶部下方。如果他的 (
只是将深度推到 return 堆栈的顶部,那么在退出这个词时,gforth 将尝试跳转到深度作为地址。如果您尝试以这种方式使用他的话,则会看到相同的错误情况:
: numbers ( 1 2 ;
: sum +) ;
numbers sum
\ output: :16: error: Invalid memory address
\ >>>numbers<<< sum
如果 (
和 +)
与 return 堆栈上的第三个元素而不是第二个元素协调,则该代码将起作用(并且正常使用会失败)。
这段代码有一些缺陷:
可以说,return 栈中的正常居民不能保证只占据 return 栈中的一个单元格。
j
的使用依赖于对 j
从中提取的 return 堆栈的精确深度的了解 - 即,它依赖于了解如何DO ... LOOP
和相关词实现。
这些词可以作为直接词可移植地实现,它们将在 return 堆栈的顶部保持深度,但是你不能在定义之外使用它们。它很简单,可以让它们像在任何给定的 Forth 上一样工作。
这是一个典型的过早优化的例子。
2>R 将两个项目移动到 return 堆栈,但标准规定了两个项目到达那里的顺序。 Coos Haak 知道这一点并接受了 "advantage"。
用等效的代码替换代码
: (
R> \ remember return address
depth >R
>R \ restore return address.
;
现在你明白是怎么回事了。你想记住堆栈深度,但如果它在堆栈上就会干扰计算。所以你把它放在 ( 代码的 return 地址下,稍后以类似的方式检索。
或者,您可以将其设为机器代码定义,这样就没有 return 地址可担心了。
CODE (
<DEPTH> <to-r>
ENDCODE
实际的机器代码留作练习。
另一种选择是使用宏,也不必担心 return 堆栈。
: ( POSTPONE DEPTH POSTPONE >R ;
我忽略了 1+ 。是一种技术性,因为 depth 本身将 depth 改变 1。所以你总是必须明智地添加 1-'s 或 1+'s 每当你实际使用 depth .
最近在comp.lang.forth上发现了一些代码,好心的Coos Haak写的,我看不懂。
应该是对括号之间的数字求和或相乘。例如,
( 1 2 3 +) ok
. 6 ok
为方便起见,我将其复制在这里:
: (
depth 1+ r> 2>r
;
: cond
depth j >
;
: done
2r> rdrop 2>r
;
: +)
begin cond
while +
repeat
done
;
: *)
begin cond
while *
repeat
done
;
我看到了短语 r> 2>r
和 2r> rdrop 2>r
。但是,我对他们在做什么感到很困惑。我猜测左括号处的堆栈深度以某种方式隐藏在 return 堆栈中。但是,我不明白。
这些对 return 堆栈有什么作用?
在 Gforth 文档中我看到:
r> R:w – w core “r-from”
2>r d – R:d core-ext “two-to-r”
2r> R:d – d core-ext “two-r-from”
rdrop R:w – gforth “rdrop”
w Cell, can contain an integer or an address
d double sized signed integer
这跟w和d的转换有关系吗?
2>r
(以及 Forth 200x 词 n>r
)保留推入 return 堆栈的元素的顺序。因此,如果数据堆栈上有 ( 1 0 )
,堆栈顶部为 0,那么在 2>r
之后,return 堆栈顶部将有 0,其下方有 1 . 2>r
因此是可定义的,而不是
: 2>r ]] >r >r [[ ; immediate
但是作为:
: 2>r ]] swap >r >r [[ ; immediate
这些定义是等价的:
: a ]] 0 >r 1 >r [[ ; immediate
: b ]] 0 1 2>r [[ ; immediate
Coos Haak 在该代码中所做的是将一个值滑动到 return 堆栈顶部下方。如果他的 (
只是将深度推到 return 堆栈的顶部,那么在退出这个词时,gforth 将尝试跳转到深度作为地址。如果您尝试以这种方式使用他的话,则会看到相同的错误情况:
: numbers ( 1 2 ;
: sum +) ;
numbers sum
\ output: :16: error: Invalid memory address
\ >>>numbers<<< sum
如果 (
和 +)
与 return 堆栈上的第三个元素而不是第二个元素协调,则该代码将起作用(并且正常使用会失败)。
这段代码有一些缺陷:
可以说,return 栈中的正常居民不能保证只占据 return 栈中的一个单元格。
j
的使用依赖于对j
从中提取的 return 堆栈的精确深度的了解 - 即,它依赖于了解如何DO ... LOOP
和相关词实现。
这些词可以作为直接词可移植地实现,它们将在 return 堆栈的顶部保持深度,但是你不能在定义之外使用它们。它很简单,可以让它们像在任何给定的 Forth 上一样工作。
这是一个典型的过早优化的例子。 2>R 将两个项目移动到 return 堆栈,但标准规定了两个项目到达那里的顺序。 Coos Haak 知道这一点并接受了 "advantage"。
用等效的代码替换代码
: (
R> \ remember return address
depth >R
>R \ restore return address.
;
现在你明白是怎么回事了。你想记住堆栈深度,但如果它在堆栈上就会干扰计算。所以你把它放在 ( 代码的 return 地址下,稍后以类似的方式检索。
或者,您可以将其设为机器代码定义,这样就没有 return 地址可担心了。
CODE (
<DEPTH> <to-r>
ENDCODE
实际的机器代码留作练习。
另一种选择是使用宏,也不必担心 return 堆栈。
: ( POSTPONE DEPTH POSTPONE >R ;
我忽略了 1+ 。是一种技术性,因为 depth 本身将 depth 改变 1。所以你总是必须明智地添加 1-'s 或 1+'s 每当你实际使用 depth .