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