Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 15:13 02 May 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Exiting Nested "FOR . . . NEXT"  loops

     Page 2 of 3    
Author Message
Volhout
Guru

Joined: 05/03/2018
Location: Netherlands
Posts: 3550
Posted: 09:14pm 04 Oct 2022
Copy link to clipboard 
Print this post

There is a problem with goto exit a loop.
Geoff has apparently fixed it, but in the loop, the return address, and maybe more, is pushed on stack.
When you exit with goto, the return address remains on stack. Slowly your stack will fill up, with every goto exit.
That is what the EXIT DOs do, they clean up the stack.
PicomiteVGA PETSCII ROBOTS
 
Martin H.

Guru

Joined: 04/06/2022
Location: Germany
Posts: 903
Posted: 04:51am 05 Oct 2022
Copy link to clipboard 
Print this post

  Volhout said  There is a problem with goto exit a loop.
Geoff has apparently fixed it, but in the loop, the return address, and maybe more, is pushed on stack.
When you exit with goto, the return address remains on stack. Slowly your stack will fill up, with every goto exit.

you are right.
If you dont act carefull, you might get a recursion and stack overflow

here my example without Goto but 3 nested Loops  

initialise:
'some Variables
do
 Intro:
 cls:Print "Bla Bla Bla"
 prepare_Playfield
 Live%=5
 Do
   next_Live:
   LIveLost%=0
   If not Live% the exit do
   do
     something
     something_else
     If LIveLost% then inc Live%,-1: exit do
   loop
 loop
loop
'---------
sub prepare_Playfield
end sub
sub something
end sub
sub
something_else
end sub

Edited 2022-10-05 14:55 by Martin H.
'no comment
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3165
Posted: 10:11am 05 Oct 2022
Copy link to clipboard 
Print this post

Volhout, I guess that you are talking about some other language but the subject is MMBasic and you imply a problem here.  To be clear, MMBasic does not push a return address on the general stack.  It maintains its own "do loop stack" and it automatically cleans it up if EXIT DO was not used.  Same for FOR...NEXT loops.

So "Slowly your stack will fill up, with every goto exit" does not apply to MMBasic.

Martin H, your code does not prove anything as it uses EXIT DO.  After fixing the obvious errors it runs fine forever.  

If you want to test using GOTO to jump out of a loop, try this.  It runs forever with no "stack overflow" or any other error:

DO
 DO
   DO
     PRINT "-";
     GOTO JumpOutOfLoop
   LOOP
 LOOP
 JumpOutOfLoop:
 PRINT ".";
LOOP


Geoff

P.S.  TassyJim's solution is excellent and MMBasic will handle it with ease.  As a bonus the GOTO police will not be upset.
Edited 2022-10-05 20:24 by Geoffg
Geoff Graham - http://geoffg.net
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3848
Posted: 10:24am 05 Oct 2022
Copy link to clipboard 
Print this post

  Geoffg said  ... To be clear, MMBasic does not push a return address on the general stack.


Hi Geoff, obviously I've been poking quite deep into MMBasic internals for a while now and it doesn't implement a "general" all-purpose stack at all does it ? Just a handful of specialised stacks (dostack/forstack/gosubstack/errorstack) and the rest is handled within the C stack itself because FUNCTION/SUB call is handled by a recursive call to the main C ExecuteProgram() function. My experience on interpreter implementation isn't huge, but I would classify MMBasic as "interesting" but very effective .

Best wishes,

Tom
Edited 2022-10-05 20:25 by thwill
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3165
Posted: 10:41am 05 Oct 2022
Copy link to clipboard 
Print this post

  thwill said  it doesn't implement a "general" all-purpose stack at all?

Yes, correct.  The original implementations of BASIC did not use a general stack and allowed GOTO to be used everywhere.  As a result more modern versions such as MMBasic had to accommodate programmers who were used to jumping around.  This is an unfortunate feature of BASIC that other modern languages avoided.

With MMBasic I had to draw the line with jumping out of subroutines and functions.  Repeated abuse of this will cause a stack error and possibly make your hair go prematurely grey (if you have any).

Geoff
Edited 2022-10-05 20:47 by Geoffg
Geoff Graham - http://geoffg.net
 
toml_12953
Guru

Joined: 13/02/2015
Location: United States
Posts: 326
Posted: 12:47am 06 Oct 2022
Copy link to clipboard 
Print this post

  Volhout said  @Jim

I use
Do
Loop


All the time. No need for the 1=1......
probably a remainder of the Arduino world....


DO...LOOP is the same as

DO...WHILE 1=1

but it is NOT the same as DO...UNTIL 1=1 which only executes one time.

It's this last one they were talking about in this thread
 
zeitfest
Guru

Joined: 31/07/2019
Location: Australia
Posts: 385
Posted: 09:41am 06 Oct 2022
Copy link to clipboard 
Print this post

[ question from non-Basic universe here    ]

In Basic, if a GOTO jumps to a code point inside a loop(s), is the loop ignored ?
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3848
Posted: 09:48am 06 Oct 2022
Copy link to clipboard 
Print this post

  zeitfest said  [ question from non-Basic universe here    ]

In Basic, if a GOTO jumps to a code point inside a loop(s), is the loop ignored ?


Assuming someone doesn't just punch you, then I believe you would expect an error equivalent to "NEXT without FOR" or "LOOP without DO" at the point you reach a loop closing statement but the appropriate stack of open loops is empty. Something similar would probably happen if you use GOTO to jump into an old fashioned GOSUB/RETURN subroutine.

Best wishes,

Tom
Edited 2022-10-06 19:51 by thwill
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
Martin H.

Guru

Joined: 04/06/2022
Location: Germany
Posts: 903
Posted: 10:06am 06 Oct 2022
Copy link to clipboard 
Print this post

  zeitfest said  [ question from non-Basic universe here    ]

In Basic, if a GOTO jumps to a code point inside a loop(s), is the loop ignored ?

That doesn't work

but tested with DOS_MM-Basic  


For x%=1 To 500
 Label:
 sqr%=x%*x%
Next x%
Print x%
GoTo Label

as expected
-----------------

[4] Next x%
Error : Cannot find a matching FOR

Edited 2022-10-06 20:09 by Martin H.
'no comment
 
stanleyella

Guru

Joined: 25/06/2022
Location: United Kingdom
Posts: 1647
Posted: 05:05pm 06 Oct 2022
Copy link to clipboard 
Print this post

I tried

option explicit
dim n,m,v1,v2
cls
text 100,100,"test"
for n=1 to 9
 for m=1 to 9
   v1=m:v2=n
   text 0,0,str$(n)
   text 30,0,str$(m)
   if m=5 then m=9:n=9
 next m
next n
text 0,16,str$(v1)
text 30,16,str$(v2)

results
1  5
5  1
it exits if var=val then set next values max to max.
Edited 2022-10-07 04:25 by stanleyella
 
stanleyella

Guru

Joined: 25/06/2022
Location: United Kingdom
Posts: 1647
Posted: 07:16pm 06 Oct 2022
Copy link to clipboard 
Print this post

I tried

option explicit
dim n,m,p,v1
cls
for n=1 to 10
 for m=1 to 10
   for p=1 to 100
     v1=v1+1
     text 0,0,str$(v1)
     if v1=512 then
       text 0,16,str$(m)
       text 30,16,str$(n)
       text 60,16,str$(p)
       m=10:n=10:p=100
     end if
   next p
 next m
next n
text 40,0,str$(v1)
text 0,32,str$(m)
text 30,32,str$(n)
text 60,32,str$(p)

I got
512
m=6, n=1, p=12
end was
m=11, n=11 p=101
it jumps out of a nested for next loop
at the end of the code v1 is 512 so must have exited or it would be around 10000
Edited 2022-10-07 05:42 by stanleyella
 
stanleyella

Guru

Joined: 25/06/2022
Location: United Kingdom
Posts: 1647
Posted: 08:09pm 06 Oct 2022
Copy link to clipboard 
Print this post

This is simpler and final number is 5432 so works but do not know about the stack. I thought for next was vars and used ram.

option explicit
dim n,m,p,v1,v2
v1=5432
for n=1 to 10
 for m=1 to 10
   for p=1 to 100
     v2=p+m+n
     if v2=v1 then m=9:n=9:p=99 'maybe 10, 10, 100
   next p
 next m
next n

I meant v2 is 5432 at the end, not n+m+p at the end.
goto could go any where though. this would just end the nested loop
Edited 2022-10-07 06:32 by stanleyella
 
stanleyella

Guru

Joined: 25/06/2022
Location: United Kingdom
Posts: 1647
Posted: 11:02pm 06 Oct 2022
Copy link to clipboard 
Print this post

This gives
v2=5432
a=6  b=5  c=32
comment/rem if v2=5432 then m=10:n=10:p=100 and I got
v2=10000
a=10  b=10  c=100

option explicit
dim n,m,p,v2,a,b,c as integer
cls
for n=1 to 10
 for m=1 to 10
   for p=1 to 100
   a=n:b=m:c=p
     v2=v2+1
     if v2=5432 then m=10:n=10:p=100
   next p
 next m
next n
cls
text 0,0,"v2="+str$(v2)
text 0,30,"a="+str$(a)+"  b="+str$(b)+"  c="+str$(c)

Edited 2022-10-07 09:26 by stanleyella
 
CaptainBoing

Guru

Joined: 07/09/2016
Location: United Kingdom
Posts: 1985
Posted: 08:50am 07 Oct 2022
Copy link to clipboard 
Print this post

see? in this case I genuinely think

for n=1 to 10
for m=1 to 10
  for p=1 to 100
  a=n:b=m:c=p
    v2=v2+1
    if v2=5432 then GoTo NiceExit
  next p
next m
next n
NiceExit:
cls


is tidier and easier to follow

jus' sayin'... I never had a problem with a *well placed* GoTo
 
zeitfest
Guru

Joined: 31/07/2019
Location: Australia
Posts: 385
Posted: 09:18am 07 Oct 2022
Copy link to clipboard 
Print this post

  Quote  
  Quote  [ question from non-Basic universe here    ]

In Basic, if a GOTO jumps to a code point inside a loop(s), is the loop ignored ?


... you would expect an error equivalent to "NEXT without FOR" or "LOOP without DO" at the point you reach a loop closing statement but the appropriate stack of open loops is empty.



  Quote  That doesn't work


What happens ?

I am wondering, if the stack of loops isn't empty - if the loop closing statement will then act on a different pre-existing active loop.
Edited 2022-10-07 19:23 by zeitfest
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8592
Posted: 09:46am 07 Oct 2022
Copy link to clipboard 
Print this post

  Quote  is tidier and easier to follow


Personally I much prefer Stanley's solution. All the loops terminate tidily and you KNOW there is no garbage left behind in the interpreter however good the implementation.
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 3660
Posted: 10:54am 07 Oct 2022
Copy link to clipboard 
Print this post

  matherp said  
  Quote  is tidier and easier to follow


Personally I much prefer Stanley's solution. All the loops terminate tidily and you KNOW there is no garbage left behind in the interpreter however good the implementation.

It does need the BASIC variant to allow loop variables to be modified the way the code does.

Also, if the terminating value is changed, there's now more than one place to change - somewhat error-prone.

Not much code seems to need these things, though. Most can use EXIT ...
or the DO...LOOP UNTIL 1=1 (maybe some prettier variant?).

John
Edited 2022-10-07 20:54 by JohnS
 
Tinine
Guru

Joined: 30/03/2016
Location: United Kingdom
Posts: 1646
Posted: 04:41pm 07 Oct 2022
Copy link to clipboard 
Print this post

(just having fun guys)

Wouldn't it be cool if you could throw the entire thing into another processor with shared memory and when you need to get out, have the processor shut itself down.

Now that would be a PROPer solution    


Craig
 
stanleyella

Guru

Joined: 25/06/2022
Location: United Kingdom
Posts: 1647
Posted: 05:04pm 07 Oct 2022
Copy link to clipboard 
Print this post

There is end next somewhere in the manual.
I think do loop alternatives would be a better way of ending a loop when the condition is true.
Why keep testing when the condition is met seems to be the point.
Goto label is cool but I prefer modern style of do loop and the conditions.
It is 2022.
code should have been

for n=1 to 10
 for m=1 to 10
   for p=1 to 100
     v2=v2+1
     if v2=5432 then a=n:b=m:c=p:m=10:n=10:p=100
   next p
 next m
next n

but only a test so does efficient code matter with mmb?
Edited 2022-10-08 07:22 by stanleyella
 
Nimue

Guru

Joined: 06/08/2020
Location: United Kingdom
Posts: 367
Posted: 02:53pm 08 Oct 2022
Copy link to clipboard 
Print this post

Hi all

Followed this thread with interest - and then as it happens I needed to do so (in Python) for a lesson on passwords / cracking

Forgive the Python code:

import itertools
import time
from tqdm import tqdm

start_time = time.time()



def foo(l,d):
 
 yield from itertools.product(*([l] * d))

def check_pwd():
 
 for d in tqdm(range (1,10)):
   for x in tqdm(foo('abcdefghijklmnopqrstuvwxyz',d)):
     if (''.join(x)) == "password":
       print (x,"password = ","password")
       return

check_pwd()

print("--- %s seconds ---" % (time.time() - start_time))


The point here being that to exit the nested for loops, I am "returning" from a function "check_pwd". The for..next are wrapped in a function.

In MMBASIC I can't get a function to exit in the same manner, but it works for a SUB -- this exits early...

sub check_pwd()
for x = 1 to 1000
 for y = 1 to 1000
   for z = 1 to 1000
     if x*y*z = 1500 then
       print x,y,z
       exit sub
     end if
   next z
 next y
next x
end sub


check_pwd



No idea how this "stacks" up (couldn't resist the pun ;-) )

Cheers
N
Entropy is not what it used to be
 
     Page 2 of 3    
Print this page
© JAQ Software 2024