![]() |
Forum Index : Microcontroller and PC projects : Most elegant MMBasic way to ......
Page 1 of 2 ![]() ![]() |
|||||
Author | Message | ||||
hitsware2![]() Guru ![]() Joined: 03/08/2019 Location: United StatesPosts: 719 |
..... Do this ? my site |
||||
Geoffg![]() Guru ![]() Joined: 06/06/2011 Location: AustraliaPosts: 3292 |
Check "Obsolete Commands and Functions" in the user manual. Geoff Graham - http://geoffg.net |
||||
CaptainBoing![]() Guru ![]() Joined: 07/09/2016 Location: United KingdomPosts: 2170 |
ON x GOTO/SUB 100,200,300,400... = Select Case x Case 1 'equivalent code for ON x = 1 Case 2 'equivalent code for ON x = 2 Case 3 'equivalent code for ON x = 3 Case 4 'equivalent code for ON x = 4 ... End Select Select makes it really easy to trap values of x that you are not expecting or want to take a generic action for (Case Else). Consider comparing a value for the ascii value for printable charcters... you would have to have ON x {tons of cryptic line numbers} where as a single Case 32 To 126 does that, and a Case Else catches everything outside this range. Stupid example but you get the point. ![]() Select Case Asc(x$) Case 13 StrEdit$=a$:Exit Function Case 127,8 If Len(a$)>0 Then a$=Left$(a$,Len(a$)-1):SStr a$,h,v EndIf Case 32 To 126 If Len(a$)<q Then a$=a$+x$:SStr a$,h,v Case Else 'ignore End Select Select Case, like ON x, works just like a big list of IF statements but looks nicer. As a rule, GOSUB is deprecated (archaic) in just about every modern basic. You can only pass arguments by using global variables and it relies on line numbers/labels instead of extending the language with nicely named procedures. It is maintained as a legacy statement but to be avoided if possible... don't think I have used one (where options exist) for 40 years. You should use Sub or Function (if you want something back). GOTO is the same and should be avoided as it can result in an uncontrolled exit from a structure (FOR/SELECT/WHILE/SUB/FUNCTION etc. - even GOSUB) which can cause memory leaks and weird stuff with the stack. I don't know if this applies to MMBasic, but can't see how it doesn't... if you constantly call a GOSUB and then GOTO the line that calls it, the stack will fill with unused RETURN addresses. That said, There is a tendency to stab yourself trying to maintain structure when a simple GOTO would do. I try to avoid it but if it is within an "encapsulated" block of code and for a short distance, then I don't really have a problem with it. But as I said, I do *try* to avoid it. At the end of the day, write your code how you want but I always strive to improve. ![]() my 2p Edited 2020-08-16 20:32 by CaptainBoing |
||||
capsikin Guru ![]() Joined: 30/06/2020 Location: AustraliaPosts: 341 |
I imagine the ON x GOTO being faster since it's only one line, but I don't know if it's true. I've seen this bug using GOTO out of a SUB. But I think C lets you GOTO out of a loop or switch/case (SELECT CASE equivalent). Not so easy in an interpreted language though. Testing ... MMBASIC doesn't seem to mind jumping out of a FOR loop many times. |
||||
capsikin Guru ![]() Joined: 30/06/2020 Location: AustraliaPosts: 341 |
I expected one of these tests to fail - test 1 getting a stack overflow or test 2 being disallowed like in a compiled language. goto test2 'test one - works fine test1: for n=1 to 1000000 for i=1 to 200 if (n mod 500 = 0) THEN print n,i if i > 3 THEN GOTO loopend next i loopend: next n 'test 2 - also works fine test2: for n=1 to 1000000 for i=1 to 200 if (n mod 500 = 0) THEN print n,i if i > 3 THEN next n next i next n I bet conditional NEXT could be even more fun and confusion than GOTO. And I wonder about conditional FOR. |
||||
mkopack73 Senior Member ![]() Joined: 03/07/2020 Location: United StatesPosts: 261 |
There is NEVER EVER a good reason to use a goto. Have we learned NOTHING over the last 40+ years? Anything you think you need a goto to achieve I guarantee you I can find a way to do without it. |
||||
darthvader Regular Member ![]() Joined: 31/01/2020 Location: FrancePosts: 87 |
So true ![]() But it's not 40+ years , 30 years ago in university , it was not allowed to use GOTO. If you do , you got a note of 0 , it means , you loose a full year and can retake your chance next semester ... he he he ... It's sometime tricky but again , it's true ![]() Cheers. Theory is when we know everything but nothing work ... Practice is when everything work but no one know why ;) |
||||
hitsware2![]() Guru ![]() Joined: 03/08/2019 Location: United StatesPosts: 719 |
Thank You ! ![]() That's why I didn't find it ![]() my site |
||||
Poppy![]() Guru ![]() Joined: 25/07/2019 Location: GermanyPosts: 486 |
But there is! Good for debugging if you just want to break out intentionally, of course actually not for final coding. But I think "old" stuff must not get lost, it can and should simply be still available paralelly for all those who intentionally want to use it ... for what reason ever. GOTO is great! ![]() ... at least for 20 GOTO 10 ... and don´t forget to warn little Mira! ![]() ![]() ![]() | ||||
vegipete![]() Guru ![]() Joined: 29/01/2013 Location: CanadaPosts: 1132 |
All this hating on GOTO. Show me a processor that doesn't have a machine code equivalent to GOTO. The STM32 chips have a bunch of branch instructions that goto the targeted memory location. PIC32 chips have branches and jumps, as does the 6502 and 68000. The Z80 has jumps... they all do. It is our little minds that can't handle the resulting spaghetti formed from pages of ill-planned goto-filled code. If the code is correct, the processor will faithfully wend its way through all that spaghetti. That's a really big if though. When I am writing assembly code, I gleefully use branch and jump instructions, saving memory and sometimes execution speed. But with high level languages, there is no need for goto. MMBasic is such a high level language. If you think you are really stuck and need a goto, it is time to re-examine your program logic. And don't forget the EXIT and CONTINUE commands. These two commands can replace many tempting uses of goto. Edited 2020-08-17 04:23 by vegipete Visit Vegipete's *Mite Library for cool programs. |
||||
Tinine Guru ![]() Joined: 30/03/2016 Location: United KingdomPosts: 1646 |
Assembly programmers are well respected but they won't get very far without jmp, je, jne, etc. Change the spelling to GOTO and all of a sudden you're not a real programmer. I have yet to test this with MMBASIC but the ON x Goto/Gosub in some dialects, creates a jump table. This is WAY faster than evaluating every "case" or "if". I use On x GOSUB in MMBASIC all the time. I guess it's what we call state machine programming. I am not going to be using MMBASIC for a few days so it would be interesting to learn from Geoff or Pete whether ON x GOSUB does in fact create a jump table. Regards, Craig Edited 2020-08-18 02:36 by Tinine |
||||
CaptainBoing![]() Guru ![]() Joined: 07/09/2016 Location: United KingdomPosts: 2170 |
[VegiPete] agree and [Tinine] agree. see this snippet: 'Web API parsing LANRxLN$=GetIO$(LAN,1) IF LANRxLN$="" OR LANRxLN$="T/O" THEN GOTO Main CL LANRxLN$,0 IF MID$(LANRxLN$,2,8)=",CONNECT" THEN Chan=VAL(LANRxLN$) IF Chan>=0 AND Chan<=4 THEN FlagSet Conn+Chan CL "Inbound connect channel "+STR$(Chan),0 GOTO IPEXIT END IF END IF IF MID$(LANRxLN$,2,7)=",CLOSED" THEN Chan=VAL(LANRxLN$) IF Chan>=0 AND Chan<=4 THEN IF FlagTest(Conn+Chan)=0 THEN A$="Abnormally " ELSE A$="" CL "Closed channel "+STR$(Chan),0 FlagRes Conn+Chan GOTO IPEXIT END IF END IF IF LEFT$(LANRxLN$,5)="+IPD," THEN DO:a$=GetIO$(LAN,2):LOOP UNTIL a$="Connection: Keep-Alive" Chan=VAL(MID$(LANRxLN$,6,1)) IF Chan>4 THEN GOTO IPDerrEXIT IF FlagTest(Conn+Chan)=0 THEN GOTO IPDerrEXIT 'channel not open z=INSTR(LANRxLN$,":GET /") '+IPD,0,nnn:GET /smssend?tel=077?msg=XYZ HTTP/1.1 IF z=0 THEN GOTO IPDerrEXIT LANRxLN$=MID$(LANRxLN$,z+6) z=INSTR(LANRxLN$," HTTP") IF z=0 THEN GOTO IPDerrEXIT LANRxLN$=LEFT$(LANRxLN$,z-1) args=Split(Replace$(LANRxLN$,"+"," "),"?") SELECT CASE SP$(1) CASE "smssend" IF args <3 THEN GOTO IPDerrEXIT Tel$="":Msg$="" FOR n=2 TO args a$=Trim$(URLDecode$(MID$(sp$(n),5))) SELECT CASE LEFT$(ucase$(SP$(n)),4) CASE "TEL=" Tel$=a$ CASE "MSG=" Msg$=a$ END SELECT NEXT IF Tel$="" OR Msg$="" THEN GOTO IPDerrEXIT CL "O/B SMS "+Tel$+":"+Msg$,0 z=GSMSend(Tel$,Msg$) IF z=0 THEN B$="OK: Message Queued for sending":GOTO IPOKEXIT ELSE B$="ERROR: Gateway failed to send message {"+STR$(z)+"}" GOTO IPOKEXIT END IF CASE "stat" 'IF z=>8 AND Z<=11 THEN 'other API calls go here... 'z=INSTR(LANRxLN$,":GET /whatever?") 'IF z<>0 THEN 'etc... ' B$="OK: STAT="+LL1$+LL2$ ' GOTO IPOKEXIT END SELECT GOTO IPDerrEXIT 'default action IF we don't find an API call END IF GOTO IPEXIT IPDerrEXIT: B$="ERROR: Malformed request {"+LANRxLN$+"}" IPOKEXIT: PRINT #LAN,"AT+CIPSENDEX="+STR$(Chan)+",255" PAUSE 100 PRINT#LAN,B$+"\0" PAUSE 100 PRINT#LAN,"AT+CIPCLOSE="+STR$(Chan) FlagRes Conn+Chan IPEXIT: Trying to eliminate all those GOTOs with "structured methods" when you are knee-deep in multiple condition checks would be a royal PitA and not add anything to the code other than a "badge of honour". Worth mentioning that this code exists in the main thread of the code, not in a SUB so EXIT is not an option. As I said, when it makes lfe easy (and fast in this case) I'll do it... it's just not the first blade out of the swiss army knife. Edited 2020-08-18 03:54 by CaptainBoing |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 4044 |
See Goto Considered Harmful. Yes, they're adequate for getting things done and very cheap. Most code is written in high-level languages to avoid the GOTO etc issues. Not just our little minds. It's realistically impossible to prove program correctness when they're spaghetti-like. John |
||||
CaptainBoing![]() Guru ![]() Joined: 07/09/2016 Location: United KingdomPosts: 2170 |
a little code. Times in mS (natch) I tried to avoid timing anything but the switch and made the workload as identical as I could. Select is around twice as fast as a On x GoSub but it's all relative and tweakable Dim Integer n,t,tt for n=1 to 10 timer=0 Select case n case 1 t=timer tt=tt+t ?n,t case 2 t=timer tt=tt+t ?n,t case 3 t=timer tt=tt+t ?n,t case 4 t=timer tt=tt+t ?n,t case 5 t=timer tt=tt+t ?n,t case 6 t=timer tt=tt+t ?n,t case 7 t=timer tt=tt+t ?n,t case 8 t=timer tt=tt+t ?n,t case 9 t=timer tt=tt+t ?n,t case 10 t=timer tt=tt+t ?n,t End Select Next ?tt, ?"with Select":? tt=0 for n=1 to 10 timer=0 On n GoSub l1,l2,l3,l4,l5,l6,l7,l8,l9,l10 Next ?tt, ?"with Gosub":? End l1: t=timer tt=tt+t ?n,t return l2: t=timer tt=tt+t ?n,t return l3: t=timer tt=tt+t ?n,t return l4: t=timer tt=tt+t ?n,t return l5:t=timer tt=tt+t ?n,t return l6: t=timer tt=tt+t ?n,t return l7: t=timer tt=tt+t ?n,t return l8: t=timer tt=tt+t ?n,t return l9: t=timer tt=tt+t ?n,t return l10:t=timer tt=tt+t ?n,t return and the output... (prints are not part of the timing). Slowest and fastest CPU speeds on a '170. At 48Mhz, most of the switches are beyond the resolution of the timer. cpu 5 > RUN 1 1 2 1 3 1 4 1 5 2 6 1 7 2 8 2 9 3 10 2 16 with Select 1 2 2 2 3 3 4 3 5 3 6 3 7 3 8 3 9 4 10 3 29 with Gosub > cpu 48 > RUN 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 1 1 with Select 1 0 2 0 3 0 4 1 5 0 6 0 7 1 8 0 9 0 10 1 3 with Gosub Edited 2020-08-18 04:49 by CaptainBoing |
||||
hitsware2![]() Guru ![]() Joined: 03/08/2019 Location: United StatesPosts: 719 |
> Select is around twice as fast as a On x GoSub That sorta make sense looking @ ON int(rnd*3)+1 GOSUB a,b,c a: do choice #1 : RETURN b: do choice #2 : RETURN c: do choice #3 : RETURN versus SELECT CASE int(rnd*3) CASE 0 : do choice #1 CASE 1 : do choice #2 CASE 2 : do choice #3 END SELECT Because everything goes in one direction ... Instead of having the RETURN my site |
||||
Tinine Guru ![]() Joined: 30/03/2016 Location: United KingdomPosts: 1646 |
Many thanks for doing the leg work Cap'n. I guess I'm going back to Select Case. This is good news, actually because I'm switching from the MX470 to the MX170 and so nothing is lost. Makes no real difference, actually but it just makes me feel better to know that I have greater efficiency. ![]() Regards, Craig |
||||
vegipete![]() Guru ![]() Joined: 29/01/2013 Location: CanadaPosts: 1132 |
I count 14 GOTOs in that snippet. One is "GOTO Main" which I can't comment on. All the remaining ones involve exiting the snippet through one of 3 routes. I can see relatively easily replacing them with structure and likely one state variable. However, I don't disagree with their use. The usage is in my view logical and sensible. The purpose of the code is to test a bunch of conditions in a particular order and exit once a condition has been met. That to me is NOT spaghetti-like. It's stuff like this: 10 W=500:Dim F(W):P=1:A=3 that is spaghetti and should be expunged.20 F(P)=A:P=P+1:If P>W Then GoTo DONE 30 A=A+2:X=1 40 S=A/F(X):If S=Int(S) Then 30 50 X=X+1:If X<P And F(X)*F(X)<=A Then 40 60 GoTo 20 DONE: Visit Vegipete's *Mite Library for cool programs. |
||||
CaptainBoing![]() Guru ![]() Joined: 07/09/2016 Location: United KingdomPosts: 2170 |
The timing is so that only the switch logic is compared - the Return is not counted. I specifically didn't want to count the Return in the timings as that would be an obvious tilt in favour of Select Case (read; cheating-ish). I only wanted to see how long it took to make the decision - not do the resultant work. ![]() You are right Return would add more time, but then so would skipping the remaining Case statements - hence my interest in the switch only. My point precisely - it *could* be done (of course), but as I have a number of points where I might want to bail and each is nested a level further in than the preceding one, writing that as structured would increase code size and not really gain anything except a "I avoided GOTO today" badge ![]() I rarely use them, but when I do I don't see it as an excuse to just write 1970s unfathomable code. Yeah they still have a place. ![]() Edited 2020-08-18 07:58 by CaptainBoing |
||||
Tinine Guru ![]() Joined: 30/03/2016 Location: United KingdomPosts: 1646 |
Yes! The moral of the story is don't write spaghetti code! Don't blame GOTO. I work over in the Parallax Propeller world and I am one of the few users of PropBasic (very cool). It is best described as a translator rather than a compiler and GOTO translates directly to a jmp. Sure I have alternatives but they all generate extra instructions. Even their C compilers can't touch PropBasic ![]() |
||||
CaptainBoing![]() Guru ![]() Joined: 07/09/2016 Location: United KingdomPosts: 2170 |
interesting. So in the "translated" code, are GOTO lines actual memory addresses? I use Great Cow Basic (which is a compiler) for some PIC based projects and I often have a browse through the assembler output just for kicks (I am starting to think there may be some truth behind Mrs. Boing's claim that I am "sad"). Anyway, in the asm output, GOTO & GOSUB are pretty much precisely what you would write if you were doing the assembler yourself - jumps and calls (PIC assembler actually uses GOTO instead of the more usual m/c instructions of JMP, BRA etc...). This tickles my efficiency nerve as I know that executes as fast as possible. I am tempted to try the above bit of code on a stock 18Fxxx and have a look and see what the code is like. |
||||
Page 1 of 2 ![]() ![]() |
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |