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 ;
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
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 ! ;
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
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 .
Right, the dictionary pointer stays the same and the stack is reversed. Fine.