Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reverse the data stack using loops

Tags:

forth

gforth

I'm trying to reverse the stack using two loops one to send items from the data stack to return stack. And another to get them from return stack to data stack. Unfortunately, it doesn't work & gforth returns the stack underflow error. Below is the code:

: srev ( n n2 n3 n4 n5 -- n5 n4 n3 n2 n)
 6 0 do >r loop 
 6 0 do r> loop ;

1 2 3 4 5 srev

like image 668
StackUnleased Avatar asked Oct 18 '25 20:10

StackUnleased


2 Answers

The trouble you've got here is that DO ... LOOP keeps the loop parameters (index and termination value) on the return stack and discards them at the end of the loop. That's why >R and R> must be in balanced pairs during a loop.

Your code puts a value on the return stack during the loop, which then gets discarded at the end of the loop, leaving a stray loop parameter still there and the whole thing goes haywire.

You can get the result you want like this ...

: REVERSE ( i*x i -- i*y ) 0 DO I ROLL LOOP ;

... though I'm a bit puzzled as to why you'd want to!

EDIT (after reading comments and ruvim's reply):

  1. Your initial reversing the stack algorithm wouldn't have worked anyway, as a series of R>s reverses the order onto the return stack, and the corresponding >Rs reverses it again back to the parameter stack leaving the order as it was.

  2. Alternative approach, similar to ruvim's but without recursion, is here

    : APPLY ( n*x xt n -- n*x' )
        DUP 1- -ROT                ( n*x n-1 xt n )
        0 DO                       ( n*x n-1 xt )
           2>R                     \ park n-1 xt on return stack 
           2R@ DROP ROLL           \ bring next item to top
           2R@ NIP EXECUTE         \ apply the function to it
           2R>                     \ clear junk off return stack for now
        LOOP                       ( n*x n-1 xt )
        2DROP
    ;

It won't work (because of using ROLL) with anything that affects the stack depth like DROP or DUP, but ' 2* 4 APPLY works just fine!

like image 147
phisheep Avatar answered Oct 21 '25 22:10

phisheep


There is no need to reverse N top stack items to apply some operation for each of them. A possible solution is the following.

: apply-top ( i*x u.i xt -- j*x ) \ xt ( x -- k*x )
  swap dup 0= if 2drop exit then ( ... x xt u.i )
  rot >r 1- swap dup >r recurse ( R: x xt )
  2r> execute
;

This word removes the arguments from the data stack and then applies xt to each x from i*x, starting with the bottom one and ending with the top one.

Usage examples:

2 3 4  3 ' 2* apply-top ( 4 6 8 ) . . .  \ it prints "8 6 4 "
2 3 4  3 ' drop apply-top ( ) \ it just drops 3 top items
2 3    2 ' dup apply-top ( 2 2 3 3 ) \ it duplicates each item
like image 22
ruvim Avatar answered Oct 21 '25 23:10

ruvim