6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu Apr 25, 2024 4:09 pm

All times are UTC




Post new topic Reply to topic  [ 41 posts ]  Go to page 1, 2, 3  Next
Author Message
PostPosted: Mon Jun 22, 2020 9:58 pm 
Offline

Joined: Thu Mar 12, 2020 10:04 pm
Posts: 690
Location: North Tejas
What should happen when this code is run?

Code:
100 goto 1500
900 next i
910 print 910
920 goto 2000
1500 for i = 1 to 10
1510 print i
1520 goto 900
1530 next i
1540 print 1540
2000 rem


Now what would you expect to see when this is run?

Code:
100 goto 1500
900 next i
910 print 910
920 goto 2000
1500 for i = 1 to 0
1510 print i
1520 goto 900
1530 next i
1540 print 1540
2000 rem


The final question is how would you handle this if you were writing a BASIC compiler?

It takes a twisted mind to try to write a compiler; it requires a really twisted mind to thoroughly test one.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jun 22, 2020 10:16 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1926
Location: Sacramento, CA, USA
I would expect
Code:
1
2
3
4
5
6
7
8
9
10
910
for the first and
Code:
1
910
for the second. Did I win?

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
PostPosted: Mon Jun 22, 2020 10:48 pm 
Offline

Joined: Thu Mar 12, 2020 10:04 pm
Posts: 690
Location: North Tejas
barrym95838 wrote:
Did I win?


I do not think there is one right answer.

Your answer for the first is the intuitive answer for a BASIC interpreter. It just blindly executes code until it encounters the "NEXT" statement, so that becomes the "bottom" of the loop.

So far, I have only tried it at https://yohan.es/swbasic/ and it gives the same result as you.

For the second one, it gave just

1540

What to do when the loop is not executed is subjective. Possibilities include:

* look forward only, expecting "properly" structured code
* look both forward and backward for the nearest one
* scan the code without executing it except for following any "GOTO" statements. That is ill advised at best as the bowl of spaghetti may include conditional code with many possible branches


Top
 Profile  
Reply with quote  
PostPosted: Mon Jun 22, 2020 11:05 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
I would expect a compiler to be more strict in several ways than an interpreter, and generally to accept fewer code constructs. It is natural for a compiler to prefer properly structured code and strong typing, whereas it's relatively easy to write an interpreter to be more flexible in both of those respects (at the expense of speed).

However, it is also entirely possible to write a "threaded code" compiler which works very much like an interpreter, but without the overhead of parsing each source line as it is encountered. Such a compiler would emit code that runs more slowly than well optimised code, but can be more flexible in handling strange code constructs. I remember seeing a tutorial for writing a BASIC compiler that worked essentially that way.

In this case, the threaded code would maintain a FOR stack just like an interpreter. Executing FOR would initialise the loop variable, and place a frame on the FOR stack pointing to that variable, and listing the limit, the step, and the address of the code immediately following the FOR. Executing NEXT would pop FOR frames until the correct loop variable (if specified) was found, then increment the loop variable by the step, compare it against the limit, and conditionally GOTO the linked block. Threaded code is characterised by having most of the actual code in subroutines of a runtime library, and the program consisting mostly of parameter setup and JSRs.

Finally, the result of FOR X = 1 TO 0 tends to vary between dialects of BASIC. Some will iterate over 1 and 0 in that order, some will behave like C for(x=1; x <= 0; x++) and thus not execute at all, and some will behave like a do-while loop and execute only the 1 iteration.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 23, 2020 12:27 am 
Offline

Joined: Thu Mar 12, 2020 10:04 pm
Posts: 690
Location: North Tejas
The plot thickens...

First this code:

Code:
100 goto 1500
900 next i
910 print 910
920 goto 2000
1500 for i = 1 to 2
1510 print i
1520 goto 900
1530 next i
1540 print 1540
2000 rem


with these interpreters:

https://yohan.es/swbasic/

1
2
910

6800 FLEX BASIC

1
2
910

GWBASIC

1
NEXT without FOR in 900


Then this code:

Code:
100 goto 1500
900 next i
910 print 910
920 goto 2000
1500 for i = 1 to 0
1510 print i
1520 goto 900
1530 next i
1540 print 1540
2000 rem


with these interpreters:

https://yohan.es/swbasic/

1540

6800 FLEX BASIC

1
910

GWBASIC

1540


And then this code:

Code:
100 goto 1500
900 next i
910 print 910
920 goto 2000
1500 for i = 1 to 0
1510 print i
1520 goto 1700
1530 next i
1540 print 1540
1550 goto 2000
1700 next i
1710 print 1710
2000 rem


with these interpreters:

https://yohan.es/swbasic/

1540

6800 FLEX BASIC

1
1710

GWBASIC

1540


And finally this code:

Code:
100 goto 1500
900 next i
910 print 910
920 goto 2000
1500 for i = 1 to 2
1510 print i
1520 goto 1700
1530 next i
1540 print 1540
1550 goto 2000
1700 next i
1710 print 1710
2000 rem


with these interpreters:

https://yohan.es/swbasic/

1
2
1710

6800 FLEX BASIC

1
2
1710

GWBASIC

1
NEXT without FOR in 1700


Two different interpretations of "FOR I = 1 TO 0":

* find the next "NEXT"; that is the bottom of the loop
* the loop always executes at least once

It is interesting that GWBASIC only considers the first NEXT following the FOR to be valid.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 23, 2020 1:27 am 
Offline
User avatar

Joined: Fri Dec 12, 2008 10:40 pm
Posts: 1000
Location: Canada
I like the response of GW-BASIC best. It seems to get things closer to the way I'd expect. I come from a structured compiled basic background (VAX BASIC). I don't think your code would even compile under VAX BASIC, but the GW-BASIC is doing a fine job from a interpreter perspective. Have you tried it with MS PDS 7.1 or QuickBasic?

_________________
Bill


Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 23, 2020 3:58 am 
Offline

Joined: Mon Sep 17, 2018 2:39 am
Posts: 132
Hi!

BillG wrote:
The final question is how would you handle this if you were writing a BASIC compiler?

It takes a twisted mind to try to write a compiler; it requires a really twisted mind to thoroughly test one.


Now you know why FastBasic does not have "GOTO" ;)

There are many subtle results on typical BASIC interpreters. One is the "multiple NEXT", this runs in Atari BASIC:
Code:
10 FOR I=0 TO 10
20 IF I = 6 THEN NEXT I
30 PRINT I,
40 IF I < 5 THEN NEXT I
50 PRINT "OK"
60 IF I > 7 THEN NEXT I : GOTO 90
70 NEXT I
80 PRINT "LAST?"
90 PRINT "END"


The result is:
Code:
0         1         2         3         4         5         OK
7         OK
8         OK
9         OK
10        OK
END


You can also abuse "POP" to call NEXT inside a GOSUB:
Code:
10 FOR I=1 TO 10
20 GOSUB 50
30 PRINT "OK"
40 NEXT I
50 PRINT I,
60 IF I=3 THEN POP :NEXT I
70 PRINT "SUB",
80 IF I>10 THEN END
90 RETURN

RUN
1         SUB       OK
2         SUB       OK
3         4         SUB       OK
5         SUB       OK
6         SUB       OK
7         SUB       OK
8         SUB       OK
9         SUB       OK
10        SUB       OK
11        SUB       


In the Atari computers, TurboBasic XL introduced "IF/ELSE/ENDIF" (without THEN), so this code is also valid:
Code:
10 FOR A=0 TO 2
20 PRINT "A=";A;" - ";
30 IF A<>0
40 PRINT "1";
50 IF A=1 THEN ELSE
60 PRINT "2";
70 ENDIF
80 PRINT " X"
90 NEXT A

RUN
A=0 - 2 X
A=1 - 1 X
A=2 - 12 X


There is a lot of BASIC code for the Atari computers full of those weird constructs and others like:
- Computed GOTO,
- Nested FOR with same variable, using POP to skip from one to the other,
- POP inside a GOSUB to return to grandparent instead of parent.

In FastBasic there is no line numbers and there is no "GOTO" nor "POP", but there is "EXIT" that terminates current FOR/WHILE/DO/REPEAT or exits a PROC, and you can't place the NEXT (or other loop ending) inside an IF or another loop. This makes the compiler a lot simpler and allows more optimizations on the generated code.

Have Fun!


Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 23, 2020 4:11 am 
Offline

Joined: Mon Sep 17, 2018 2:39 am
Posts: 132
Hi!

BillG wrote:
The plot thickens...


Your three examples in Atari BASIC:

Code:
READY

100 GOTO 1500
900 NEXT I
910 PRINT 910
920 GOTO 2000
1500 FOR I = 1 TO 2
1510 PRINT I
1520 GOTO 900
1530 NEXT I
1540 PRINT 1540
2000 REM

RUN
1
2
910

READY
NEW

READY

100 GOTO 1500
900 NEXT I
910 PRINT 910
920 GOTO 2000
1500 FOR I = 1 TO 0
1510 PRINT I
1520 GOTO 900
1530 NEXT I
1540 PRINT 1540
2000 REM

RUN
1
910

READY
NEW

READY

100 GOTO 1500
900 NEXT I
910 PRINT 910
920 GOTO 2000
1500 FOR I = 1 TO 2
1510 PRINT I
1520 GOTO 1700
1530 NEXT I
1540 PRINT 1540
1550 GOTO 2000
1700 NEXT I
1710 PRINT 1710
2000 REM

RUN
1
2
1710

READY


TurboBasic XL, is compatible with Atari BASIC by default, but you can activate "enhanced FOR", this skips FOR with no iterations:
Code:
90 *F +
100 GOTO 1500
900 NEXT I
910 PRINT 910
920 GOTO 2000
1500 FOR I=1 TO 0
1510 PRINT I
1520 GOTO 900
1530 NEXT I
1540 PRINT 1540
2000 REM

RUN
1540

READY


Have Fun!


Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 23, 2020 10:26 am 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
I'll just leave this here:


Attachments:
Screenshot 2020-06-23 13.26.02.png
Screenshot 2020-06-23 13.26.02.png [ 64.1 KiB | Viewed 1569 times ]
Top
 Profile  
Reply with quote  
PostPosted: Tue Jun 23, 2020 10:34 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10793
Location: England
It feels to me that a compiled Basic can either stay quite close to the semantics of the interpreted language, or aim to impose some degree of structure. In the absence of any block structure in the text of the language, there's no way to have a zero-iterations FOR loop without some form of compromise. And if you make that compromise, the behaviour of the compiled version will inevitably diverge from that of the interpreted version.

Like many things, it feels like a design choice, which is going to satisfy some people but not everyone.

The key, I think, is not to surprise the users too much. Document the behaviour!

(BBC Basic lacks a DO-WHILE for this very reason, I think: it has REPEAT-UNTIL which necessarily runs at least once through the loop, just as a FOR-NEXT must. And in both cases, the head of the loop sets up a return mechanism, so when a corresponding tail statement is met, it can go back to the top. And so there can be several such tails, and it doesn't matter where they are or how they are reached. This feels to me like a reasonable compromise, but then I am biased!)


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 28, 2020 7:32 pm 
Offline

Joined: Thu Mar 12, 2020 10:04 pm
Posts: 690
Location: North Tejas
The latest version of my BASIC torture code is:

Code:
100 a = 0
200 gosub 1500
300 a = 1
400 gosub 1500
500 end
900 next i
910 print 910
920 goto 2000
1500 for i = 1 to 2
1510 print i
1520 if a = 0 then goto 900
1530 goto 1700
1540 next i
1550 print 1550
1560 goto 2000
1700 next i
1710 print 1710
2000 return


Running it with https://yohan.es/swbasic/ yields:

1
2
910
1
2
1710

It appears that the NEXT statement "tells" the FOR statement the location of the bottom of the loop.


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 28, 2020 8:41 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1926
Location: Sacramento, CA, USA
BillG wrote:
It appears that the NEXT statement "tells" the FOR statement the location of the bottom of the loop.

I don't get that impression at all. I believe that it's all in the spirit of what Chromatix stated above: NEXT doesn't modify anything inside the FOR activation frame, it simply accesses it to update the loop variable and perform a conditional branch back to the beginning of the loop (or discard the frame and fall-through from its current location). The location of whichever NEXT eventually terminates the loop determines the post-loop flow of execution via the fall-through mechanism, nothing more.

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 28, 2020 8:52 pm 
Offline

Joined: Thu Mar 12, 2020 10:04 pm
Posts: 690
Location: North Tejas
This code would indicate otherwise:

Code:
100 gosub 1000
200 gosub 2000
300 end
1000 for i = 1 to 2
1100 goto 3000
2000 for i = 7 to 8
2100 goto 3000
3000 print i
3100 next i
3200 return


1
2
7
8

Edit: On further thought, that is inconclusive. Let me think about it some more...


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 28, 2020 9:03 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1926
Location: Sacramento, CA, USA
That result is totally expected in my scenario. In the BASICs I'm describing, FOR doesn't perform any increments or comparisons or branches, it just does an initial assignment, creates an activation frame and (always) proceeds with the following statement. That frame is never modified during the loop, but is discarded by whichever NEXT becomes the loop-terminator. NEXT is where all the "real" work is done, and the fall-through mechanism is its final task.

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 28, 2020 10:10 pm 
Offline

Joined: Thu Mar 12, 2020 10:04 pm
Posts: 690
Location: North Tejas
Technically, I guess we are both right. I am thinking like a compiler implementer.

Looking at this code:

Code:
100 gosub 1000
200 gosub 2000
300 end
1000 for i = 1 to 2
1100 goto 3000
2000 for i = 7 to 6 step -1
2100 goto 3000
3000 print i
3100 next i
3200 return


---

My way:

Activation record contains:
Code:
  identity of loop variable
  address of top of loop
  address of loop exit


init part of FOR statement does:
Code:
  assign starting value to loop variable
  create activation record
  store loop variable identity in activation record
  store address of top of loop


The iterate part is different depending on whether the loop counts up or down.

iterate part of an up counting FOR statement does:
Code:
  add step to loop variable
  if loop variable > terminating value:
    discard activation record
    goto loop exit


iterate part of a down counting FOR statement does:
Code:
  add step to loop variable
  if loop variable < terminating value:
    discard activation record
    goto loop exit


NEXT statement does:
Code:
  verify loop variable identity
  raise error if not matching
  store loop exit address in activation record
  goto top of loop


---

Your way:

Activation record contains:
Code:
  identity of loop variable
  address of top of loop
  termination value
  step value


init part of FOR statement does:
Code:
  assign starting value to loop variable
  create activation record
  store loop variable identity in activation record
  store address of top of loop
  store termination value in activation record
  store step value in activation record


iterate part of FOR statement does:
Code:
  nothing


NEXT statement does:
Code:
  verify loop variable identity
  raise error if not matching
  add step to loop variable
  if step is positive:
    if loop variable <= termination value:
      goto top of loop
  else:
    if loop variable >= termination value:
      goto top of loop
  discard activation record


---

Added complication: some BASIC interpreters allow leaving off the loop variable from the NEXT statement. For your way, NEXT would have to use indirection to get to the loop variable.

Further consideration, my way allows for easy optimization when the loop variable deals with integer instead of floating point values.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 41 posts ]  Go to page 1, 2, 3  Next

All times are UTC


Who is online

Users browsing this forum: drogon, Google [Bot], W3C [Validator] and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: