How to reverse the stack

At euroForth 2013 we raised the question how to reverse (parts of) the stack.

Here is a definition of the word nreverse that reverses the order of the topmost n items.


In [24]:
%%gforth

: nreverse ( n*x n -- n*x' )
   1 DO  I roll  LOOP ;


 ok

What? How does it work? It moves the topmost item to the top, then the second and so on until it moves the nth item to the top, alas the topmost n items are reversed.

So let's try it:


In [25]:
%%gforth

clearstack

1 2 3   10 20 30 40 50 5 nreverse .s


<8> 1 2 3 50 40 30 20 10  ok

Fine - works as expected.

But - it uses roll that is rather inefficient. Can't we find another implementation of nreverse?

Sure - we could copy the stack items to main memory and then read them back to the stack in required order:


In [26]:
%%gforth

: nreverse ( n*x n -- n*x' )
   here >r dup >r here >r
   0 DO , LOOP
   r> r> cells bounds DO  I @  1 cells +LOOP
   r> dp ! ;


redefined nreverse   ok

Temporary space in the dictionary is allocated by ,-ing the items from the stack. After reading the items back to the stack, the dictionary pointer is restored.

So, what is this bounds word? bounds is defined like this:


In [27]:
%%gforth

see bounds


: bounds  
  over + swap ; ok

Essentially it converts addr count to end-addr start-addr so that the DO loop can iterate over addresses.

OK, let's test this new implementation.


In [28]:
%%gforth

clearstack here .

1 2 3   10 20 30 40 50 5 nreverse .s

cr here .


4312103552 <8> 1 2 3 50 40 30 20 10 
4312103552  ok

Right, the dictionary pointer stays the same and the stack is reversed. Fine.