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: NetherlandsPosts: 3550 |
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: GermanyPosts: 903 |
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: AustraliaPosts: 3165 |
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 KingdomPosts: 3848 |
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: AustraliaPosts: 3165 |
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 StatesPosts: 326 |
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: AustraliaPosts: 385 |
[ 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 KingdomPosts: 3848 |
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: GermanyPosts: 903 |
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 KingdomPosts: 1647 |
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 KingdomPosts: 1647 |
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 KingdomPosts: 1647 |
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 KingdomPosts: 1647 |
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 KingdomPosts: 1985 |
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: AustraliaPosts: 385 |
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 KingdomPosts: 8592 |
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 KingdomPosts: 3660 |
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 KingdomPosts: 1646 |
(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 KingdomPosts: 1647 |
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 KingdomPosts: 367 |
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 |