2>r 和 2r> 如何工作?



最近,在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>r2r> rdrop 2>r的短语.但是,我对他们在做什么感到困惑。我猜左括号处的堆栈深度以某种方式隐藏在返回堆栈上。但是,我不明白。

这些对返回堆栈有什么作用?

在 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 )保留了推送到返回堆栈的元素的顺序。 因此,如果您在数据堆栈上有( 1 0 ),其中 0 作为堆栈的顶部,那么2>r之后,返回堆栈的顶部将有 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 在该代码中所做的是将一个值滑到返回堆栈顶部下方。 如果他的(只是将深度推到返回堆栈的顶部,那么在退出这个词时,gforth 会尝试跳到深度作为地址。 如果您尝试以这种方式使用他的话,则会看到相同的错误条件:

: numbers  ( 1 2 ; 
: sum  +) ;
numbers sum
 output: :16: error: Invalid memory address
         >>>numbers<<< sum

但是,如果(+)与返回堆栈上的第三个元素而不是第二个元素协调,则该代码将起作用(并且正常使用将失败)。

此代码存在一些陷阱:

  1. 可以这么说,返回堆栈的普通居民不能保证只占用返回堆栈的一个单元格。

  2. j的使用依赖于有关j提取的返回堆栈的精确深度的知识 - 即,它依赖于有关如何实现DO ... LOOP和相关单词的知识。

这些单词可以作为即时单词移植实现,它们将深度保持在返回堆栈的顶部,但是你不能在定义之外使用它们。 这很简单,可以让它们在任何给定的 Forth 上正常工作。

这是

过早优化的典型示例。2>R 将两个项目移动到返回堆栈,但标准规定了两个项目到达那里的顺序。Coos Haak知道这一点,并利用了它。

将代码替换为等效代码

 : ( 
   R>     remember return address
   depth >R
   >R     restore return address.
;

现在你看看发生了什么。您希望记住堆栈深度,但如果它在堆栈上,则会干扰计算。因此,您将它放在代码的返回地址下,稍后将以类似的方式检索。

或者,您可以将其设置为机器代码定义,然后无需担心返回地址。

CODE (
   <DEPTH>  <to-r>
ENDCODE

其中实际的机器代码作为练习留下。

然而,另一种选择是使用宏,这也不必担心返回堆栈。

: (  POSTPONE DEPTH  POSTPONE >R  ;

我忽略了 1+ .是一种技术性,因为深度本身深度改变 1。因此,每当实际使用深度时,您始终必须明智地添加 1-1+

相关内容

  • 没有找到相关文章

最新更新