Jump to content
Sign in to follow this  
majestyx

Weird IF-THEN-ELSE issue

Recommended Posts

Perhaps I'm simply misunderstanding how this is interpreted by Extended BASIC & its derivatives, but here is some sample code that isn't giving me the expected result:

 

10 A=INT(RND*10)+1
20 IF A>5 THEN A$="GREATER THAN" :: GOSUB 100 ELSE A$="LESS THAN OR EQUAL TO" :: GOSUB 110
30 PRINT A;"IS ";A$;5
40 GOTO 10
100 PRINT "> TEST" :: RETURN
110 PRINT "<= TEST" :: RETURN

Here is what I would have expected to be the result:

 

<= TEST

 1 IS LESS THAN OR EQUAL TO 5

<= TEST

 3 IS LESS THAN OR EQUAL TO 5

> TEST

 8 IS GREATER THAN 5

<= TEST

 4 IS LESS THAN OR EQUAL TO 5

> TEST

 6 IS GREATER THAN 5

> TEST

 9 IS GREATER THAN 5

 

Instead, this is what I get:

 

image.thumb.png.83a2f4f8990ac26d2c5218cf73596c34.png

 

You can see that it is executing both GOSUBs in line 20 when A is greater than 5.

 

Is this truly the way it's supposed to work? The way I'm getting around it is to insert a GOTO 30 after GOSUB 100.

 

Share this post


Link to post
Share on other sites
1 hour ago, majestyx said:

Is this truly the way it's supposed to work? The way I'm getting around it is to insert a GOTO 30 after GOSUB 100.

 

My guess is that the second GOSUB is waiting to be executed when the first GOSUB returns.

 

...lee

  • Like 1

Share this post


Link to post
Share on other sites
1 hour ago, majestyx said:

20 IF A>5 THEN A$="GREATER THAN" :: GOSUB 100 ELSE A$="LESS THAN OR EQUAL TO" :: GOSUB 110

10 INPUT X

20 IF X>5 THEN A$="GT" ELSE A$="LT"::PRINT A$

30 GOTO 10

This behaves as you would expect and only prints A$ if it is 5 or less.

Changing line 20 to:

20 IF X>5 THEN A$="GT"::GOSUB 100 ELSE A$="LT"::GOSUB 100::PRINT A$        and add 100 RETURN

This has the anomaly you describe - when returning from the first GOSUB it does not move on to line 30 but resumes after the first :: after the ELSE.

Changing line 20 to:

20 IF X>5 THEN A$="GT"::GOSUB 100 ::X=X ELSE A$="LT"::GOSUB 100::PRINT A$  

And now it behaves as expected. So it looks like you will be OK if the program does some operation after the return from first GOSUB and before the program comes to the ELSE.

 

I'll bet the compiler does not do this - which is too bad because it should exactly mimic the program flow in XB, even if it is wrong.

Edited by senior_falcon

Share this post


Link to post
Share on other sites

I think there was a documented issue with GOSUB and IF/THEN/ELSE that (re)surfaced a few years ago, either in this forum or the Yahoo Group. I did a quick search but could not find the related topic. 

Share this post


Link to post
Share on other sites
2 hours ago, senior_falcon said:

I'll bet the compiler does not do this - which is too bad because it should exactly mimic the program flow in XB, even if it is wrong.

As expected, the compiler does not have this bug.

  • Like 1

Share this post


Link to post
Share on other sites

I changed the first Gosub to Goto, and of course changed the Return on line 100 to Goto 10 and it worked that way too.

 

Take out the Else and have two If/Then/Gosub. Hmmm, that may not work either.

 

10 A=INT(RND*10)+1
20 IF A>5 THEN A$="GREATER THAN" :: GOSUB 100 :: If A<=5 THEN A$="LESS THAN OR EQUAL TO" :: GOSUB 110
30 PRINT A;"IS ";A$;5
40 GOTO 10
100 PRINT "> TEST" :: RETURN
110 PRINT "<= TEST" :: RETURN

 

Or you could break line 20 into two separate lines with an If/Then/Gosub statement for each result.

 

-Ed

Edited by Ed in SoDak
  • Like 1

Share this post


Link to post
Share on other sites

 

7 hours ago, majestyx said:

20 IF A>5 THEN A$="GREATER THAN" :: GOSUB 100 ELSE A$="LESS THAN OR EQUAL TO" :: GOSUB 110

Rearranging the order of operations should make this work. You just don't want the GOSUB to RETURN to an ELSE

20 IF A>5 THEN GOSUB 100::A$="GREATER THAN" ELSE GOSUB 110::A$="LESS THAN OR EQUAL TO"

  • Thanks 1

Share this post


Link to post
Share on other sites

Thanks for the link to the bug report & for the suggestion on the order of operations. I believe this will work.

Share this post


Link to post
Share on other sites

Interesting. Did not know that. This might just possibly save me a lot of hair pulling in a future project :)

Share this post


Link to post
Share on other sites
19 hours ago, majestyx said:

Perhaps I'm simply misunderstanding how this is interpreted by Extended BASIC & its derivatives, but here is some sample code that isn't giving me the expected result:

 

10 A=INT(RND*10)+1
20 IF A>5 THEN A$="GREATER THAN" :: GOSUB 100 ELSE A$="LESS THAN OR EQUAL TO" :: GOSUB 110
30 PRINT A;"IS ";A$;5
40 GOTO 10
100 PRINT "> TEST" :: RETURN
110 PRINT "<= TEST" :: RETURN

Here is what I would have expected to be the result:

 

<= TEST

 1 IS LESS THAN OR EQUAL TO 5

<= TEST

 3 IS LESS THAN OR EQUAL TO 5

> TEST

 8 IS GREATER THAN 5

<= TEST

 4 IS LESS THAN OR EQUAL TO 5

> TEST

 6 IS GREATER THAN 5

> TEST

 9 IS GREATER THAN 5

 

Instead, this is what I get:

 

image.thumb.png.83a2f4f8990ac26d2c5218cf73596c34.png

 

You can see that it is executing both GOSUBs in line 20 when A is greater than 5.

 

Is this truly the way it's supposed to work? The way I'm getting around it is to insert a GOTO 30 after GOSUB 100.

 

You can not put a GOSUB in a IF THEN or IF THEN ELSE as there is no way to return to that address as it is in the middle of the XB code.

Now if you used a THEN line number or GOTO line number and that line number had a GOSUB line number it would work.

See as a programmer of RXB I know how XB works and it would be impossible to find where the GOSUB was in that line.

 

Edited by RXB
SPELLING
  • Thanks 1

Share this post


Link to post
Share on other sites
3 minutes ago, RXB said:

You can not put a GOSUB in a IF THEN or IF THEN ELSE as there is not way to return to that address as it is in the middle of the XB code.

Now if you used a THEN line number or GOTO line number and that line number had a GOSUB line number it would work.

See as a programmer of RXB I know how XB works and it would be impossible to find where the GOSUB was in that line.

 

Well—actually, you can put a GOSUB there and XB is perfectly happy to return to the statement after the ELSE without indicating an error. You clearly should not do that because it is a bug (feature?).

 

...lee

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
35 minutes ago, RXB said:

You can not put a GOSUB in a IF THEN or IF THEN ELSE as there is no way to return to that address as it is in the middle of the XB code.

Now if you used a THEN line number or GOTO line number and that line number had a GOSUB line number it would work.

See as a programmer of RXB I know how XB works and it would be impossible to find where the GOSUB was in that line.

 

This is not correct. GOSUB returns as it should as this program shows:

10 INPUT X

20 IF X>5 THEN GOSUB 100::A$="GT" ELSE GOSUB 110::A$="LT"

30 PRINT A$::GOTO 10

100 PRINT "SUB100"::RETURN

110 PRINT "SUB110"::RETURN

(As noted earlier, just be sure GOSUB is not followed by ELSE - unless you want to eploit this bug. But if you are using this bug and compile the program the results will not be the same.)

Edited by senior_falcon

Share this post


Link to post
Share on other sites
1 hour ago, Lee Stewart said:

 

Well—actually, you can put a GOSUB there and XB is perfectly happy to return to the statement after the ELSE without indicating an error. You clearly should not do that because it is a bug (feature?).

 

...lee

The subroutine Stack saves the location but when the GOSUB is returned it clears stack then continues on, this is exactly what caused the error we see.

This is why you should do this:

 

20 IF X>5 THEN A$="GREATER THAN" :: GOSUB 100 ::  GOTO 30 ! fixes first part of line

25 A$="LESS THAN OR EQUAL TO" :: GOSUB 110 ! fixes second part of line

30 PRINT A;"IS ";A$;5
40 GOTO 10

 

This would be the proper way to do the program.

 

 

Share this post


Link to post
Share on other sites
1 hour ago, senior_falcon said:

This is not correct. GOSUB returns as it should as this program shows:

10 INPUT X

20 IF X>5 THEN GOSUB 100::A$="GT" ELSE GOSUB 110::A$="LT"

30 PRINT A$::GOTO 10

100 PRINT "SUB100"::RETURN

110 PRINT "SUB110"::RETURN

(As noted earlier, just be sure GOSUB is not followed by ELSE - unless you want to eploit this bug. But if you are using this bug and compile the program the results will not be the same.)

Answered the issue above to Lee.

Subroutine stack pops off the values and clears stack but upon return to that line you see the results are not correct, thus the bug.

Share this post


Link to post
Share on other sites

Have you tried out the program that I posted in #13? Obviously not, because if you had done so you would have seen that it works as it should, despite your claim that it does not. 

Edited by senior_falcon

Share this post


Link to post
Share on other sites

I wasn't trying to start a war here and I do appreciate all the input. Hopefully I won't offend anyone with the below post that I was about to submit before senior_falcon did in post #13. I'm mainly posting it to provide as much info as I was able to put together & especially for my own reference in this one thread.

 

----

 

Lee is correct on this. Here is a program that WILL work because there is no additional code after the ELSE.

 

10 INPUT DR
20 IF DR>8 THEN GOSUB 100 :: PRINT DR;">8" :: GOSUB 110 ELSE GOSUB 120
30 PRINT :: GOTO 10
100 PRINT "LINE 100" :: RETURN
110 PRINT "LINE 110 (>)" :: RETURN
120 PRINT DR;"<=8" :: PRINT "LINE 120 (<=)" :: RETURN

It's when you place any additional code after the double colon of an ELSE statement that it will execute for both conditions (THEN and ELSE), something I wasn't aware of.

 

Here is an entry in the XB manual that explains what cannot be used in an IF-THEN-ELSE statement, as well as an example of using GOSUB, but without any additional code after the ELSE. The description indicates that it should continue on the line following when returning from the subroutine. In this case, this is correct. But not in the case of another statement after the ELSE X=X+5. Anything after the ELSE will run for both THEN and ELSE. This could be used as a feature, but it takes knowing that this is how it actually works in order to take advantage of it, as well as how to avoid that it DOESN'T work as I had expected in my original post.

 

image.thumb.png.8d3e4dfd6688accd7975a188fb964056.png

 

  • Thanks 1

Share this post


Link to post
Share on other sites
2 hours ago, majestyx said:

It's when you place any additional code after the double colon of an ELSE statement that it will execute for both conditions (THEN and ELSE), something I wasn't aware of.

 

Not quite right. The problem occurs when there is a GOSUB followed immediately by ELSE. If you give the GOSUB something other than ELSE to return to by inserting another statement between GOSUB and ELSE, it works as you would expect and you can insert as many statements as will fit after either GOSUB:

10 A=INT(RND*10)+1
20 IF A>5 THEN A$="GREATER THAN" :: GOSUB 100 :: X=1 ELSE A$="LESS THAN OR EQUAL TO" :: GOSUB 110 :: X=2
30 PRINT A;"IS ";A$;5;"X =";X
40 GOTO 10
100 PRINT "> TEST" :: RETURN
110 PRINT "<= TEST" :: RETURN

 

Clearly, this is a bug!

 

...lee

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

Yes, it looks like if the interpreter has "no code to go to" after the GOSUB, it will in error go to the code after the ELSE, instead of the code after the whole IF statement, which is where it should be heading.

Share this post


Link to post
Share on other sites
10 hours ago, apersson850 said:

Yes, it looks like if the interpreter has "no code to go to" after the GOSUB, it will in error go to the code after the ELSE, instead of the code after the whole IF statement, which is where it should be heading.

Yes exactly as I explained happens. 

 

Share this post


Link to post
Share on other sites
17 hours ago, Lee Stewart said:

 

Not quite right. The problem occurs when there is a GOSUB followed immediately by ELSE. If you give the GOSUB something other than ELSE to return to by inserting another statement between GOSUB and ELSE, it works as you would expect and you can insert as many statements as will fit after either GOSUB:

10 A=INT(RND*10)+1
20 IF A>5 THEN A$="GREATER THAN" :: GOSUB 100 :: X=1 ELSE A$="LESS THAN OR EQUAL TO" :: GOSUB 110 :: X=2
30 PRINT A;"IS ";A$;5;"X =";X
40 GOTO 10
100 PRINT "> TEST" :: RETURN
110 PRINT "<= TEST" :: RETURN

 

Clearly, this is a bug!

 

...lee

Yes again as I have explained and why it happens.

Share this post


Link to post
Share on other sites

Once again, Lee states what I should have. Here's a sample of my actual code that now works correctly because I moved the GOSUB to be before the string assignment:

 

300 GOSUB 5150::IF DR+COM<6 THEN GOSUB 6180::FN$="E286" ELSE GOSUB 6190::FN$="E663"

 

However, as Rich has mentioned, the GOTO is needed for this line of code, as the GOSUB would be immediately before the ELSE without it, resulting in the FN$="E642" & GOSUB 5000 executing, which is NOT what I wanted:

 

310 GOSUB 5000::FN$="E654"::GOSUB 5000::GOSUB 5150::IF DR+NTU<8 THEN GOSUB 6100::GOTO 320 ELSE GOSUB 6110::FN$="E642"::GOSUB 5000

Thanks again to all for their input, as it has been quite helpful!

 

  • Thanks 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...