第四:具有多个出口点的可移植不定循环



我需要实现一个具有多个出口点的idefinite循环。不幸的是,最明显的解决方案-带有多个WHILE的REPEAT-UNTIL在Gforth和swapforth中都不起作用(当然,下面例子中的循环可以用DO-loop实现。然而,该代码只是一个演示。真正的问题与嵌入式系统中的硬件控制有关,因此循环确实必须是不确定的):

: test1 ( step -- step count )
    0
    begin
      over +
      dup .
      dup 20 < while
      dup 13 = while
    repeat
;
3 test1 

在《向前思考》中引用了摩尔的声明:

很多时候,条件句是用来摆脱循环的。那个特别的可以通过具有多个出口点的循环来避免使用。这是一个实时主题,因为poly-Forth,但还没有渗透到Forth'83。这是一个简单的方法在同一个REPEAT中定义多个WHILE。还有Dean Sanderson[福特股份有限公司]发明了一种新的结构,引入了两个出口指向DO LOOP。考虑到这种结构,你的测试会更少。

不幸的是,我没能找到院长的解决方案。有没有任何可移植的方法来实现Forth中不确定循环中的多个出口点?

EXIT当然为一个定义提供了多个出口。您可以通过使用一个单独的单词,或者更巧妙地使用引号,使循环的主体与定义完全相同:

: test ( start step -- count step )
  swap [: begin
    over + dup .
    dup 20 > if ." >20" exit then
    dup 13 = if ." =13" exit then
    dup 17 = if ." =17" exit then
  again ;] execute
  ( EXITs from loop continue here ) ;

经过一些实验,我创建了一个基于DO+LOOP的解决方案。我不知道这是否与迪恩·桑德森提出的建议相同。

我已经在Gforth和swapforth成功地测试了它。似乎可以创建任意数量的出口点。不确定循环是通过以下方式创建的:0 1 DO循环内容此处为0+loop。出口点由放置在IF THEN中的LEAVE创建。

示例代码:

: test1 ( start step -- count step )
    swap
    1 0 do
      over +
      dup .
      dup 20 > if 
        ." >20 "
        leave
      then
      dup 13 = if
        ." =13 "
        leave
      then
      dup 17 = if
        ." =17 "
        leave
      then
    0 +loop
;

测试结果:

> 1 3 test1
 4 7 10 13 =13  ok
> 2 3 test1
 5 8 11 14 17 =17  ok
> 0 3 test1
 3 6 9 12 15 18 21 >20  ok

根据ruvim给出的注释,我测试了一个基于多个WHILE的解决方案,该解决方案使用额外的THEN:解决

: test1 ( step start -- step count )
    cr
    begin
      over +
      dup . cr
      dup 30 < while
      dup 13 <> while
      dup 17 <> while
    repeat
        ." before 1st else" cr
    else
        ." after 1st else" cr
    then
        ." before 2nd else" cr
    else 
        ." after 2nd else" cr
    then
;

确实有效。下面的测试显示了出于不同的原因执行哪些代码部分以退出循环。

循环在第一次之后退出:

5 1 test1 
6 
11 
16 
21 
26 
31 
after 2nd else
 ok

循环在第2次之后退出,同时:

5 3 test1 
8 
13 
after 1st else
before 2nd else
 ok

循环在第3次之后退出,同时:

5 2 test1 
7 
12 
17 
before 1st else
before 2nd else
 ok

因此,如果有人想将操作分配给每个WHILE,则应该按照以下方式进行:

: test1 ( step start -- step count )
    cr
    begin
      over +
      dup . cr
      dup 30 < while
      dup 13 <> while
      dup 17 <> while
    repeat
    ." exited after the 3rd while" cr
    else
    ." exited after the 2nd while" cr
    then
    else
    ." exited after the 1st while" cr
    then
;

有趣的是,上面的情况会持续更长的时间。适用于4个WHILE的语法如下所示:

: test1 ( step start -- step count )
    cr
    begin
      over +
      dup . cr
      dup 30 < while
      dup 13 <> while
      dup 17 <> while
      dup 19 <> while
    repeat
    ." exited after the 4th while" cr
    else
    ." exited after the 3nd while" cr
    then
    else
    ." exited after the 2nd while" cr
    then
    else
    ." exited after the 1st while" cr
    then
;

上面的代码在Gforth和swapforth都进行了测试。有趣的问题是不同可能的解决方案中的返回堆栈占用率。(例如,在J1B CPU中,返回堆栈深度仅为32级)。

相关内容

  • 没有找到相关文章

最新更新