forthgforth

A weird problem in Forth when printing out the data stack and floating-point stack


I've started exploring Forth using Gforth on a Kali Linux computer. Thinking about stacks I always imagine the picture of the HP calculator stacks like so:

T <- bottom of the stack
Z
Y
X <- top of the stack

So I have written two words, the first one prints out the inverted stack, the second prints the floating point stack in inverted form. My assumption was that both routines should be 100% identical with the exception of stack-specific words, e.g. pick and fpick, . and f.. But it turned out that I had to modify the fprstinv word in one line. Here they go, prstinv and after that fprstinv:

: prstinv ( print inverted stack, works correctly )
  depth 0 >
  if
    cr
    depth 1 + 1
    do
      depth i - pick .
      i 1 =
      if
        ."  <- Bottom" cr
      else
        i depth 1 - <
        if
          cr
        then
      then
    loop
    ."  <- T O P"
  then
;
: fprstinv ( print inverted f-stack, works incorrectly )
  fdepth 0 >
  if
    cr
    fdepth 1 + 1
    do
      fdepth i - fpick f.
      i 1 =
      if
        ."  <- Bottom" cr
      else
        i fdepth 1 - < \ creates the error in the formatting
        if
          cr
        then
      then
    loop
    ."  <- T O P"
  then
;

fprstinv messes up the formatting:

3.  <- Bottom
2. 1.  <- T O P ok

For the correct formatting see below...

If you run prstinv with three numbers on the stack and then prstinv, you'll see the correct output. The following version of fprstinv works correctly when altered to look as follows:

: fprstinv ( print inverted f-stack, works correctly but differs from prstinv in one line )
  fdepth 0 >
  if
    cr
    fdepth 1 + 1
    do
      fdepth i - fpick f.
      i 1 =
      if
        ."  <- Bottom" cr
      else
        i fdepth < \ does not create an error
        if
          cr
        then
      then
    loop
    ."  <- T O P"
  then
;

The correct outputs as intended by me are:

.s <3> 3 2 1  ok
f.s <3> 3.000000000000E0 2.000000000000E0 1.000000000000E0  ok
prstinv 
3  <- Bottom
2 
1  <- T O P ok
fprstinv 
3.  <- Bottom
2. 
1.  <- T O P ok

I don't understand the different behavior: Both stacks should be the same in terms of structure and analog properties like depth and fdepth. So, both words should be the same in terms of structure, looping parameters and if-conditionals.

I appreciate even small hints as well as assumptions which could help to find further information!

Thanks a lot!


Solution

  • The reason of divergent behavior in your code is as follows.

    In the case of the data stack:

      i depth 1 - <
    

    i places a number on the data stack, and this number is counted in the result of depth. And 1 - eliminates this contribution of i.

    In the case of the floating-point stack:

      i fdepth 1 - <   \ creates the error in the formatting
    

    i places a number on the data stack, and this number is not counted in the result of fdepth (since it counts the items on the floating-point stack only).

    To make behavior in the second case as in the first case you have to remove 1 -, as:

      i fdepth < 
    

    Or you can change both variant as follows:

      depth i >
    
      fdepth i >
    

    (I.e., place the depth on the stack before placing other arguments)

    One more advice: use early exit to decrease the number of nesting levels.

    Instead of:

      ... \ A
      if
        ... \ B
      then
    ;
    

    do:

      ... \ A
      0= if exit then
      ... \ B
    ;
    

    Rationale: Why I Don't Use Else When Programming (YouTube)