Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
for-next repeats forever because of data type limit
#1
Hi all,

I'm working on my first port from Sinclair Basic to ZX Basic. I'm excited about it. I'd love to program compiled versions of some old programs of mine, but first I need to acquaint with this wonderful and impressive tool.

I'm using ZX Basic 1.2.0 under Debian GNU/Linux.

Well, I think I found a kind of bug. Here you are the test:

Code:
' The following loop works as expected:

dim b0 as ubyte

for b0=0 TO 254
    print at 0,0;"b0=";b0;"    "
next b0

' The following loop works as expected too:

dim b1 as uinteger

for b1=0 TO 255
    print at 1,0;"b1=";b1;"    "
next b1

' But the following loop starts again forever:

dim b2 as ubyte

for b2=0 TO 255
    print at 2,0;"b2=";b2;"    "
next b2

border 4
print "This message never will be printed"
pause 0

I found the problem because I needed a loop from 0 to 255, so I used the ubyte data type for the index variable. Then I realized the loop repeated forever!

I guess the reason is NEXT increases the loop index before cheking it, so 256 becomes 0 after storing it back into the ubyte variable and the check gets wrong: the loop starts again because the index is zero! I guess the same happens with other data types, as long as their limits are reached, but I didn't try.

Do you think this is a language feature or a compiler bug? Smile

I'm programming a project in FreeBASIC too, but I didn't try this. I'll try a similar code and I'll see what happens.
Reply
#2
programandala.net Wrote:Hi all,

I'm working on my first port from Sinclair Basic to ZX Basic. I'm excited about it. I'd love to program compiled versions of some old programs of mine, but first I need to acquaint with this wonderful and impressive tool.

I'm using ZX Basic 1.2.0 under Debian GNU/Linux.
First of all, 1.2.0 is *VERY* old and might have lot of bugs. Please, download 1.2.5 or 1.2.6-beta here: <!-- m --><a class="postlink" href="http://www.boriel.com/files/zxb/">http://www.boriel.com/files/zxb/</a><!-- m -->

Quote:
Code:
dim b2 as ubyte

for b2=0 TO 255
    print at 2,0;"b2=";b2;"    "
next b2

border 4
print "This message never will be printed"
pause 0

I found the problem because I needed a loop from 0 to 255, so I used the ubyte data type for the index variable. Then I realized the loop repeated forever!
[...]
Do you think this is a language feature or a compiler bug? Smile
Unfortunately, it's a feature. :| This is something already discused: you're iterating a loop 256 times using a byte counter. It's really hard to do this, even in assembler, because you loop over the entire counter range (256), so the count will always overflow. The FOR sentence in basic is very powerful, it's equivalent to the following C code (if you don't know C, it does not matter):
Code:
unsigned char b2;
for (b2 = 0; b2 <= 255; b2++) {
  ...
}
This code will behave the same way: it will never exit. If you want to use a byte, try another loop sentence like DO LOOP UNTIL:
Code:
DIM b2 As Ubyte = 0;

DO
    LET b2 = b2 + 1
    ...
LOOP UNTIL b2 = 0
This should do the Loop using a an Ubyte value (have not tested it yet, btw.)
Reply
#3
boriel Wrote:First of all, 1.2.0 is *VERY* old and might have lot of bugs. Please, download 1.2.5 or 1.2.6-beta here: <!-- m --><a class="postlink" href="http://www.boriel.com/files/zxb/">http://www.boriel.com/files/zxb/</a><!-- m -->

Done. I installed 1.2.0 some months ago, and I forgot to upgrade.

boriel Wrote:Unfortunately, it's a feature. :| This is something already discused: you're iterating a loop 256 times using a byte counter. It's really hard to do this, even in assembler, because you loop over the entire counter range (256), so the count will always overflow. The FOR sentence in basic is very powerful, it's equivalent to the following C code (if you don't know C, it does not matter):

Thank you for the explanation. I understand. But at first sight I supposed it would work, because the index values were in range (0-255) for ubyte. You're right, that means 256 iterations, but that's the range a ubyte can hold: from 0 to 255. I supposed the compile time action of NEXT would be to check if the limit (255) had been reached, and don't loop again if so. But it seems it first increases the index. I think the current behaviour is less logical.

Anyway, it's not an important! I just wanted to confirm the issue.

I'll check what FreeBASIC does in such cases.
Reply
#4
programandala.net Wrote:
boriel Wrote:Thank you for the explanation. I understand. But at first sight I supposed it would work, because the index values were in range (0-255) for ubyte. You're right, that means 256 iterations, but that's the range a ubyte can hold: from 0 to 255. I supposed the compile time action of NEXT would be to check if the limit (255) had been reached, and don't loop again if so. But it seems it first increases the index. I think the current behaviour is less logical.
In fact, the semantic of FOR is not that. For example:
Code:
FOR i = 0 TO 254 STEP 2:
   PRINT "HELLO"
NEXT i
Will also fail, since 254u + 2u = 0u :!: (Note: 2u => 2 (Ubyte). So here FOR with UByte operates MOD 256!
The meaning for FOR sentence is: "Repeat this loop until (i + step) be GREATER THAN upper limit". Since (i + STEP) is truncated to the current type of variable i (Ubyte in this case), this condition is never satisfied. Keep in mind that FOR can be used with any STEP size (not just STEP 1). In the following version (1.2.6) the compiler might issue a Warning under these circumstances.

I suggest you to try the LOOP workaround code I put above.
Quote:I'll check what FreeBASIC does in such cases.
Please, do, since I'm trying to get close to FreeBasic as much as possible (preserving most of ZX BASIC on the other side ;-))
Reply
#5
boriel Wrote:
Quote:I'll check what FreeBASIC does in such cases.
Please, do, since I'm trying to get close to FreeBasic as much as possible (preserving most of ZX BASIC on the other side ;-))

I modified the code to check it with FreeBASIC, and it works exactly the same way: the 0-255 loop repeats forever when the index variable is ubyte:

Code:
' FreeBASIC

' The following loop works as expected:

cls
print "Press q to quit"

dim b0 as ubyte

for b0=0 TO 254
    locate 2
    print "b0=";b0;"    "
next b0

' The following loop works as expected too:

dim b1 as uinteger

for b1=0 TO 255
    locate 3
    print "b1=";b1;"    "
next b1

' But the following loop starts again forever:

dim b2 as ubyte

for b2=0 TO 255
    locate 4
    print "b2=";b2;"    "
    if inkey="q" then end endif
next b2

print "This message never will be printed"
sleep

By the way, the compatibility with FreeBASIC would be great: for certain programs, one source code could be compiled both for the ZX Spectrum and for other platforms --to some extent, with some conditional compilation. I'm starting working on some projects with FreeBASIC and ZX Basic, so I'll have the chance to explore the issue.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)