dmsc / fastbasic

FastBasic - Fast BASIC interpreter for the Atari 8-bit computers
GNU General Public License v2.0
139 stars 20 forks source link

ADR() on string array doesn't seem to work #64

Closed bsturk closed 1 year ago

bsturk commented 1 year ago

I'm porting (via the cross compiler) a program from Atari BASIC which does some USR calls, and it does an ADR() on a string array. Both ADR() and the & syntax give a compilation error:

adr_test.fb:2:11: parse error, expected: '(', left parenthesis MADDR = &M$<--- HERE -->

The small program that demonstrates this is:

DIM M$(5)
MADDR = &M$

I'm new to BASIC so it's possible I'm missing something, or is there maybe a more FB way of doing it? :)

dmsc commented 1 year ago

Hi @bsturk

DIM M$(5)
MADDR = &M$

Strings are different in FastBasic than Atari BASIC - the above in Atari BASIC will declare one string of 5 characters at most, but in FastBasic is an array of 5 strings of up to 256 characters.

So, in your translated example, yo need to drop the "DIM". Also, you should assign the string before taking the address, as it will change on the first assignment (to allocate the memory needed for the string data).

But... if you are using a string to store a machine-code subroutine, then I advice to not do it, as it will not work the same as in Atari BASIC, as there are two diferences:

If you post a more complete example I can help you convert it to FastBasic.

Have Fun!

bsturk commented 1 year ago

thank you! I have been switching over some things to using the DATA statement rather than DIM which is much better than the DIM, RESTORE, READ steps it was doing, is there a way to do something similar w/ the DATA statement, and allocate space for a certain size, but not have initial values, but instead initialize in a loop?

Something like this:

data foo(512) byte

for i=0 to 511
    foo[ i ] = 0
next i

I'm not suggesting this as something I would actual do (zero out something this way), but the program I'm porting does similar things but with a string, it initializes characters in a loop.

DIM SQUARE_TYPE$(1536)

SQUARE_TYPE$    = "B"
SQUARE_TYPE$(1536) = "B"        ' this "sets" the size of the string
SQUARE_TYPE$(2) = SQUARE_TYPE$   ' this fills in the other uninitialized characters to "B"

FOR JB = 0 TO 1280 STEP 256     ' for each of the 6 character sets, 1 page each (256 bytes)

        SQUARE_TYPE$(JB + 1)   = "2"
        SQUARE_TYPE$(JB + 5)   = "S"
        SQUARE_TYPE$(JB + 13)  = "O"
        SQUARE_TYPE$(JB + 32)  = "O"
        SQUARE_TYPE$(JB + 36)  = "D"
        SQUARE_TYPE$(JB + 45)  = "O"
        SQUARE_TYPE$(JB + 131) = "J"
        SQUARE_TYPE$(JB + 141) = "O"
        SQUARE_TYPE$(JB + 173) = "O"
        SQUARE_TYPE$(JB + 154) = "1"
NEXT JB

The original code used the (start,end) syntax, but I couldn't get that to work w/ FastBasic

e.g. SQUARE_TYPE$(JB + 141, JB + 141) = "O"

Is there a way to do something like this using DATA statements, or should I use the bracket syntax w/ DIM strings?

I can't use the array of strings from what I can tell since each string uses up 256 bytes. This is also pretty wasteful since it is just 1 char per string in the array. I can't use a straight up string since it seems to be limited to 256 characters.

Not sure what I can use to handle this particular block of code.

thanks for your help!

dmsc commented 1 year ago

HI!

thank you! I have been switching over some things to using the DATA statement rather than DIM which is much better than the DIM, RESTORE, READ steps it was doing, is there a way to do something similar w/ the DATA statement, and allocate space for a certain size, but not have initial values, but instead initialize in a loop?

This is what DIM does, it reserves a space of memory and initializes it to 0.

Something like this:

data foo(512) byte

for i=0 to 511
    foo[ i ] = 0
next i

Just use a byte array, like above, it is the simpler way.

DIM SQUARE_TYPE$(1536)

SQUARE_TYPE$    = "B"
SQUARE_TYPE$(1536) = "B"        ' this "sets" the size of the string
SQUARE_TYPE$(2) = SQUARE_TYPE$

FOR JB = 0 TO 1280 STEP 256     ' for each of the 6 character sets, 1 page each (256 bytes)

        SQUARE_TYPE$(JB + 1)   = "2"
        SQUARE_TYPE$(JB + 5)   = "S"
        SQUARE_TYPE$(JB + 13)  = "O"
        SQUARE_TYPE$(JB + 32)  = "O"
        SQUARE_TYPE$(JB + 36)  = "D"
        SQUARE_TYPE$(JB + 45)  = "O"
        SQUARE_TYPE$(JB + 131) = "J"
        SQUARE_TYPE$(JB + 141) = "O"
        SQUARE_TYPE$(JB + 173) = "O"
        SQUARE_TYPE$(JB + 154) = "1"
NEXT JB

The original code used the (start,end) syntax, but I couldn't get that to work w/ FastBasic

e.g. SQUARE_TYPE$(JB + 141, JB + 141) = "O"

This is better with a byte array instead of a string, as you can do SQUARE_TYPE(JB + 141) = ASC("O") or simply SQUARE_TYPE(JB + 141) = $4F . The hole loop above should be:

DIM SQUARE_TYPE(1536) BYTE

MSET &SQUARE_TYPE, 1536, ASC("B")

FOR JB = 0 TO 1280 STEP 256     ' for each of the 6 character sets, 1 page each (256 bytes)

        SQUARE_TYPE(JB + 1)   = ASC("2")
        SQUARE_TYPE(JB + 5)   = ASC("S")
        SQUARE_TYPE(JB + 13)  = ASC("O")
        SQUARE_TYPE(JB + 32)  = ASC("O")
        SQUARE_TYPE(JB + 36)  = ASC("D")
        SQUARE_TYPE(JB + 45)  = ASC("O")
        SQUARE_TYPE(JB + 131) = ASC("J")
        SQUARE_TYPE(JB + 141) = ASC("O")
        SQUARE_TYPE(JB + 173) = ASC("O")
        SQUARE_TYPE(JB + 154) = ASC("1")
NEXT JB

And you can replace the ASC() with the hex codes:

DIM SQUARE_TYPE(1536) BYTE

MSET &SQUARE_TYPE, 1536, $42

FOR JB = 0 TO 1280 STEP 256     ' for each of the 6 character sets, 1 page each (256 bytes)
        SQUARE_TYPE(JB + 1)   = $32
        SQUARE_TYPE(JB + 5)   = $53
        SQUARE_TYPE(JB + 13)  = $4F
        SQUARE_TYPE(JB + 32)  = $4F
        SQUARE_TYPE(JB + 36)  = $44
        SQUARE_TYPE(JB + 45)  = $4F
        SQUARE_TYPE(JB + 131) = $4A
        SQUARE_TYPE(JB + 141) = $4F
        SQUARE_TYPE(JB + 173) = $4F
        SQUARE_TYPE(JB + 154) = $31
NEXT JB

Have Fun!

bsturk commented 1 year ago

Awesome thanks!!

I will switch to using the byte array.

So, it seems like when I am not initializing an array, etc I should use DIM, not DATA. I've been switching over all of the DIMs to DATA foo() byte, but a couple have been too long, and the one I mentioned above is programmatically populated.

dmsc commented 1 year ago

Hi!

The idea is: use DATA for constant data, that is available on program start; use DIM for data that will be changed in the program.

Have Fun!

bsturk commented 1 year ago

Makes total sense!

One other thing I was wrestling with was using -1 as a value in a byte data array, I get compiler errors. Also, I wasn't sure if these are signed or unsigned by default. I got it to compiling by using hex, but I haven't gotten to the point if I know if it is being treated as a negative value.

dmsc commented 1 year ago

The byte values are signed, from 0 to 255. If you need negative values, you must use a word array.

Have Fun!