[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
- Attempt at implementing labeled loops,
JFLF <=