gforth
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Attempt at implementing labeled loops


From: JFLF
Subject: Attempt at implementing labeled loops
Date: Wed, 3 Feb 2021 17:01:28 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.7.0

Hello all,

Apologies if this is not the right place to ask. I have been attempting for a 
few days to solve a specific problem with GForth 0.7.3, but so far I have 
failed. Could anyone provide some advice? Disclaimer: I'm still learning Forth.

I have been trying to implement something akin to continue in C loops, but with 
labels. Ideally I'd like to achieve this:

    *: begin looplabel: loop1**
    **
    **    <condition>**
    **    while**
    **        ...**
    **        <test> if loop1 again then**
    **        ...**
    **    repeat**
    **;*


Essentially I'm looking at replacing *[ x cs-pick ] again* by something a bit 
more manageable, especially with nested control-flow items.

Side note: the way *while* tucks its orig cf item under *begin*'s dest also 
caused me quite a bit a trouble, as it disrupts the obvious index progression 
of cf items on the cf stack. It's defined as such in the standard, but does it 
make sense?

My current implementation and a test word look like this:

    *: looplabel:

        create
            2 pick , 2dup 2,
        does> immediate
            dup @ swap cell+ 2@
    ; immediate*


    *: testbegin     ( -- )

        3
        begin looplabel: loop2
            1- dup 0<>
        while
            dup 2 = if ." IF taken" cr loop2 again then
            ." After the test: " dup . cr
        repeat
        drop
    ;*



Dumping the control stack at compilation time (with additional instrumentation 
in the *testbegin* word), things /seem/ to be fine. For example:

    *Before begin:  <4> 0 140421634250120 140421634250152 0
    After begin    <7> 0 140421634250120 140421634250152 0 0 140421634250184 3
    After llabel:  <7> 0 140421634250120 140421634250152 0 0 140421634250184 3
    loop2          0 140421634250184 3
    After while    <10> 0 140421634250120 140421634250152 0 0 140421634250408 1 
0 140421634250184 3
    After if       <13> 0 140421634250120 140421634250152 0 0 140421634250408 1 
0 140421634250184 3 0 140421634250456 1
    After loop2    <16> 0 140421634250120 140421634250152 0 0 140421634250408 1 
0 140421634250184 3 0 140421634250456 1 0 140421634250184 3
    After again    <13> 0 140421634250120 140421634250152 0 0 140421634250408 1 
0 140421634250184 3 0 140421634250456 1
    After then     <10> 0 140421634250120 140421634250152 0 0 140421634250408 1 
0 140421634250184 3
    After repeat   <4> 0 140421634250120 140421634250152 0 *


But any attempt at executing *testbegin* gives that kind of result:

    *testbegin 
    :2: Invalid memory address
    >>>testbegin<<<
    Backtrace:
    $7FF9C41F95C0 lit *


The exact error changes, I have seen some stack underflows for example.

*see*-ing the words includes a few surprises:

    *see looplabel:  *
    *: looplabel:  *
    *  Create 2 pick , 2dup 2, 140710713988408 (does>2) ; immediate ok*

    *see testbegin *
    *noname : *
    *  3 *
    *  BEGIN  BEGIN  <140710713988240> <-4611686018427387899> 
<2314885609475239788> <94220049618193> <140710713988424> <0> <3> 
<140710713988552> .\" In begin:    TOS " dup . cr 1- dup 0<> *
    *         WHILE  dup 2 = *
    *         WHILE  .\" IF taken" cr *
    *         REPEAT *
    *         .\" After the test" cr *
    *  REPEAT *
    *  drop ; ok*


Replacing *looplabel:* by *cs-pick* produces the right results, but *see* still 
looks weird:

    *: testbegin2     ( -- )

        cr 3
        begin
            1- dup 0<>
        while
            dup 2 = if ." IF taken" cr [ 1 cs-pick ] again then
            ." After the test: " dup . cr
        repeat
        drop
    ;*


    *testbegin2 
    IF taken
    After the test: 1
     ok*


    *see testbegin2 
    noname :
      cr 3
      BEGIN  BEGIN  1- dup 0<>
             WHILE  dup 2 =
             WHILE  .\" IF taken" cr
             REPEAT
             .\" After the test: " dup . cr
      REPEAT
      drop ; ok*



So here are my questions:

1) I feel that I am missing some compile-time side effect of the *looplabel:* 
word but after two days of going through the GForth doc I can't figure out 
what. Any hint?

2) In both test words, the nested *if* compiles as a second *begin while 
repeat*. Why is that?

3) I don't like my current implementation anyway as it hardcodes the number of 
cells in a cf item. Also, it copies those cells to a word, but I can't just 
point to a certain stack level in a generic, nestable way due to the while cf 
item inversion. Would anyone have a suggestion about this? (no code, just the 
idea -- it's a learning process)

4) Ideally I would want the scope of those loop labels to be strictly limited 
to the current word definition. I thought of locals, but I believe that they're 
still visible in called words, right? Is there a mechanism to limit the scope 
of locals in GForth? The idea behind this is to be able to re-use labels in 
separate words without having to worry about picking up a label definition from 
a parent loop in a different word.


Thank you very much for your help and ideas!
JF



reply via email to

[Prev in Thread] Current Thread [Next in Thread]