Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 07:24 10 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 : EXIT from multi-line IF/THEN....

Author Message
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9072
Posted: 12:37am 13 Mar 2017
Copy link to clipboard 
Print this post

Hi there.


I am just trying to clean up my code that at the moment uses GOTO out of loops.

DO and FOR are taken care of with EXIT DO and EXIT FOR respectively, but there is no EXIT IF command, so I am "Making one" via a flag and ENDIF.

In other words, IF Y THEN ENDIF kind of idea.

Is this acceptable?
What I DON'T want to do in my attempt to clean up all my loops, is introduce ANOTHER bad practise in the process!

A code sample:(not wanting anyone to re-write this, it is only for context of the ENDIF idea)





The yellow highlighter bar in this GIF image, shows the line I have concern with.

Prior to this week, all my loops had 'Dirty' exits, by GOTO'ing out of the loop, which is a bit naughty, so I am cleaning up all the code now so that ALL loops have a clean exit, and one single ON x GOTO concept at the bottom, and I just use flags('Y' in this case) to signal that exits need to happen at a given point. This all seems to be working fine.

FOR/NEXT is easy to deal with via EXIT FOR.
DO/LOOP is easy to deal with via EXIT DO

Multi-line IF/THEN exits are a little different.

So, looking at how I have written my exit using a flag and an ENDIF - is this acceptable, or is there another(better!) way?

I have quite a few of these multi-line IF/THEN's to change, so I only want to do it once.
Smoke makes things work. When the smoke gets out, it stops!
 
Bizzie
Senior Member

Joined: 06/07/2014
Location: Australia
Posts: 185
Posted: 12:54am 13 Mar 2017
Copy link to clipboard 
Print this post

The select case statement with a break would do your job. I personally have not seen this in any flavors of Basic.
It is however available in many other languages. Look for the switch command in C, Java or PHP for examples to name a few.


Rob White
 
CaptainBoing

Guru

Joined: 07/09/2016
Location: United Kingdom
Posts: 1986
Posted: 01:13am 13 Mar 2017
Copy link to clipboard 
Print this post

FWIK there is no EXIT IF in MS basics (which MMBasic leans on heavily). Certainly wasn't when I stopped writing professionally (then at VB6) and I can't remember anything like it in QB, etc (Basica and GW Basic still used line numbers and so don't properly support structured code).

I know it is considered bad practice and I try to write IF sections that only include a positive test so i can nest them nicely, but even then on some nasty stuff I will still use a label right before a relevant END IF and GOTO it. Even bailing deep out of a nest of IFs will work just fine and it is faster than END IF, END IF, END IF, END IF, END IF etc... What's the point of jumping to another jump instruction? Remember: the END IF is just a local point to which a jump will be executed if the condition evaluates false (assuming no ELSE). A good example would be to look at compiled code and as most processors are fairly simple beasts, all they have is JUMP or BRANCH so that is what they use to zip round bits of code that are not required after a test. The use of a GOTO is a good analogue to this and it is fast.

Here is an example of an IF/END IF in compiled code - note the jump to a temporary label (I have removed sections of ASM that are not relevant


;if nn=fl then
movf FL,W
subwf NN,W
btfss STATUS, Z
goto ENDIF16
;print "."
[...]
;end if
ENDIF16
[...]


If you are not familiar with PIC assembler, the btfss skips the next command if the specified bit is set (in this case the zero bit).

The test of the condition results in a GOTO on false - exactly what you are doing (but feeling bad about )


The one flow control that is missing (if we are to adhere to the MS standard) that I have used is EXIT SELECT (at least it isn't in 5.3). This gets the same 'label-before-END' treatment from me if I can't make the code tight easily.

That said, I do find that most tests can be structured tightly by re-evaluating what I am trying to do and perhaps approaching from a different angle.

I have always said that GOTO has a place - just only use them if there is (apparently) no other way. Make the label meaningful and it maintains the look of the flow. So long as the code is nice to read and fast, why beat yourself up?

INCOMING!!!! Edited by CaptainBoing 2017-03-14
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 3675
Posted: 01:43am 13 Mar 2017
Copy link to clipboard 
Print this post

Grogster

I'm fairly sure it won't work, because ENDIF is lexically matched with its IF. You'd want the equivalent of EXIT IF (which I think doesn't exist).

I'm not sure in your code where you'd want it to go. If it's where I think then you could use EXIT DO instead, I think.

Or, it looks like you could change the line concerned and the ENDIF above into ELSE (and the ENDIF further down).

In C I'd probably follow the already mentioned way using a switch (select case or whatever in some languages).

JohnEdited by JohnS 2017-03-14
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3165
Posted: 03:11am 13 Mar 2017
Copy link to clipboard 
Print this post

In MMBasic ENDIF does not actually do anything when it is executed. It only exists as a marker so that the interpreter can scan forward to find the end of the IF statement. This is used when the IF test is false, in that case the interpreter will scan forward looking for the matching ENDIF and resume execution after it.

Putting the ENDIF at the end of an IF will just confuse the interpreter because it cannot evaluate the IF while scanning.

The bottom line is... DON'T DO IT

Geoff
Geoff Graham - http://geoffg.net
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 3675
Posted: 07:14am 13 Mar 2017
Copy link to clipboard 
Print this post

  JohnS said   I'm fairly sure it won't work, because ENDIF is lexically matched with its IF.
By which I mean that any time you find an ENDIF there should be one and only one IF matching it (inevitably earlier in the code), with any other similar lexical items (FOR/DO loops, further IF/ENDIFs etc) properly nested within them.

(And if there's an ELSE it'll be between them and so on.)

This sort of thing became known in some languages as "..." - meaning obvious or some such!

When there's a formal grammar for a language you can work through it and it should always work out this way. (In essence this is what a compiler has to do.)

JohnEdited by JohnS 2017-03-14
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9072
Posted: 03:23pm 13 Mar 2017
Copy link to clipboard 
Print this post

OK, so I won't mod anymore IF/THEN's like this.

Having said that then, how do you exit from a multi-line IF/THEN cleanly, WITHOUT an EXIT IF command?

It may well be do-able with MMBASIC as-is, but I will need a little prod as to how this is done if that is the case.

Using my example above, what I am trying to do with the highlighted line, is exit totally out of that IF/THEN, down to line 803(technically then to 805).

IE: At line 784, what I need is something that can do the same as IF Y THEN EXIT IF, resulting in the code dropping down to line 803 in this example and continuing from there(and then dropping out to line 805).

Based on what has been written above, and if ENDIF is simply a marker for the interpreter and does not "Do" anything in terms of code processing exactly, can I just use EXIT DO as JohnS suggests? This will drop me right out of the IF/THEN and it's hosting loop. If that works, that is fine with me - so long as that is still considered a clean exit, yes?

EDIT: In other words, can I use IF Y THEN EXIT DO at line 784, to effectively drop me back out to line 805?Edited by Grogster 2017-03-15
Smoke makes things work. When the smoke gets out, it stops!
 
erbp
Senior Member

Joined: 03/05/2016
Location: Australia
Posts: 186
Posted: 03:48pm 13 Mar 2017
Copy link to clipboard 
Print this post

  Grogster said  
Using my example above, what I am trying to do with the highlighted line, is exit totally out of that IF/THEN, down to line 803(technically then to 805).


You could try changing line 784 to "If Y = 0 Then" and add a new line after the current 801 containing "End If" - this would be the matching End to the If on 784.

I find thinking about If conditions in positive logic terms works best - i.e. what condition do I need the specify so that the following Then block of code gets executed rather than skipped.

 
disco4now

Guru

Joined: 18/12/2014
Location: Australia
Posts: 844
Posted: 04:31pm 13 Mar 2017
Copy link to clipboard 
Print this post



The construction below is useful if you want to test for multiple things

IF blah THEN
.
.
ELSE IF blah2 THEN
.
.
ELSE IF blah3 THEN
...

ELSE
... (none of above)

ENDIF


I think the ELSE statement to replace the two highlighted lines might get you close.




Regards
Gerry

Latest F4 Latest H7
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9072
Posted: 05:41pm 13 Mar 2017
Copy link to clipboard 
Print this post

Hey, I think you are on to something there, Gerry!





Made the change you suggested(replaced those lines with an ELSE), and the code works exactly as expected. This seems like the way forward, yes?
Smoke makes things work. When the smoke gets out, it stops!
 
disco4now

Guru

Joined: 18/12/2014
Location: Australia
Posts: 844
Posted: 07:56pm 13 Mar 2017
Copy link to clipboard 
Print this post

Yes,the way forward in my experience. You can make the IF statements easy to read if you selected the right method.

This sytle works well if you only want to do one of a number of things. The first one that is true is done, the rest are skipped.

IF blah THEN
.
.
ELSE IF blah2 THEN
.
.
ELSE IF blah3 THEN
...

ELSE
... (none of above)

ENDIF



Use this if you want to possibly run each one if it is true.

IF blah THEN
.
.
ENDIF

IF blah3 THEN
...

ENDIF


It all about making it easy to read 1 year down the track.

A suggestion to make it easier to read is create a subroutine for the DEBUG printing
like below.

SUB DPRINT (m$ as STRING)
IF DEBUG THEN PRINT m$
END SUB


In your main code just call it like this


DPRINT("Exit Button Touched. (database editor/new)")



The advantages are your code is easier to read. (A lot of IFs are gone and the ones left are easier to visualise.) Also if you want to tweak how you write errors etc then you do it all in one place, the DPRINT SUB. You just start to use DPRINT like its another command after a while.

You could do and SPRINT SUB for the SYSLOG stuff.

Regards
Gerry

Latest F4 Latest H7
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9072
Posted: 08:27pm 13 Mar 2017
Copy link to clipboard 
Print this post

Debug Sub is a nice idea - I will make that change also. As you say - less IF's to visualize.

The WRITE_SYSLOG sub is called if the SYSLOG flag is set.
This flag(among many others) is set via checkboxes in the settings menu.
I could have the WRITE_SYSLOG sub check the flag though, then it is not another IF in the mix of the main guff.....

Right, I will set about changing all these lumps of code so that all the exit paths for the code are neater and more in line with how it should be.

I do like the ON x GOTO.... command, as this allows me to use one flag to decide where to go, and when the code gets out the very bottom of the routines and loops, this one command then does any and all GOTO branching for me, with no nasty jumping out of loops.
Smoke makes things work. When the smoke gets out, it stops!
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3022
Posted: 05:01am 14 Mar 2017
Copy link to clipboard 
Print this post

I really like the SUB DPRINT idea. You can then test for different debug conditions.
[code]
SUB DPRINT(A as string)
IF Debug1 or Debug2 or Debug3 then PRINT A
END SUB
[/code]
... On further consideration, I don't know what I meant by the above multiple Debug#s. But I do like the SUB DPRINT idea.
Edited by lizby 2017-03-16
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9072
Posted: 02:38pm 14 Mar 2017
Copy link to clipboard 
Print this post


Smoke makes things work. When the smoke gets out, it stops!
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 10:37pm 14 Mar 2017
Copy link to clipboard 
Print this post

One problem with a debug subroutine is that it takes time.
Time that when using time sensitive tasks will influence the working of your program depended on if the debug flag is set or not.

It can (will) cause that a program works perfectly while debug is on and not work or not work sometimes when debug is off.

Ask me how i know. :) :(

Just something to be aware of, as it can be very difficult to find.

Microblocks. Build with logic.
 
isochronic
Guru

Joined: 21/01/2012
Location: Australia
Posts: 689
Posted: 07:33am 15 Mar 2017
Copy link to clipboard 
Print this post

  Quote  Just something to be aware of, as it can be very difficult to find.


Good advice there.
Once (in assembler, but the logic still holds) I was debugging a program that was
at the maximum number of subroutine return addresses in a hardware stack..adding another call (debug or print) gave apparently random execution or crashes, exasperating and at the worst time
 
isochronic
Guru

Joined: 21/01/2012
Location: Australia
Posts: 689
Posted: 07:53am 15 Mar 2017
Copy link to clipboard 
Print this post

BTW wrt the nested if/do etc, [there are no doubt several ways and opinions]
I think a WHILE construct with a compound test condition would be clean ?

 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9072
Posted: 04:15pm 15 Mar 2017
Copy link to clipboard 
Print this post

Yes, good advice from MB there - all knowledge is power.

I have not had a chance to work on this anymore just yet - other things in the way.
I hope to get back to this tonight.
Smoke makes things work. When the smoke gets out, it stops!
 
Print this page


To reply to this topic, you need to log in.

© JAQ Software 2024