That's why having no default may be the best solution.
Not quite, as then you have a lottery, smarter to follow the existing standard of freebasic’s default.
Then, pasted code gives no surprises.
Lottery?
What???
Needing an "option base" before the 1st "dim array(..)" is the exact opposite of lottery.
You have to think about what you need instead of starting to code, forgetting "option base" and maybe getting something that does not match the default.
And executing pasted code without thinking is what made "christma.exec" possible.
I don't want sloppy or forgiving defaults. I want correct programs.
I disagree, the idea to be able to copy from Freebasic and get the same results is a great idea.
QuickBasic and VB also start at zero by default.
I really don't see it as any kind of deviation from the norm when defaulting for Option Base 0, but being able to set to 1.
Not being able to dimension arrays without prior explicitely setting "option base something" still looks better to me:
$ cat option-base.bas
option base 1
dim a(2)
dim b(3)
''
'' set
''
for i=1 to 2
a(i) = 1000+i
next i
for i=0 to 2
b(i) = 2000+i
next i
''
'' get
''
for i=1 to 2
print "a(";i;") = ";a(i)
next i
for i=0 to 2
print "b(";i;") = ";b(i)
next i
$ fastspin option-base.bas
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2018 Total Spectrum Software Inc.
Version 3.9.13-beta-96efba6 Compiled on: Dec 15 2018
option-base.bas
option-base.pasm
Done.
Program size is 4932 bytes
$ spinsim -b option-base.binary
a(1) = 1001
a(2) = 2000
b(0) = 2000
b(1) = 2001
b(2) = 2002
It will not prevent such errors but when looking for the reason you do not need to know the default then and every reader of that code will see what the coder wanted to be correct.
@yeti: you're correct that making it a "required base" instead of "option base" would be safer. But honestly I don't think people choose BASIC for safety, but rather for convenience. So I think there should be a default, and it seems the consensus here is for a base of 0.
@yeti: you're correct that making it a "required base" instead of "option base" would be safer. But honestly I don't think people choose BASIC for safety, but rather for convenience. So I think there should be a default, and it seems the consensus here is for a base of 0.
So the default will allocate 11 elements for an array that is declared with "DIM foo(10)" with indices of 0-10? I guess that's the safest approach.
Some useful BASIC commands that are not yet implemented in FlexBasic:
ON x GOTO/GOSUB label1, label2, ...
I think this can be replaced by a function table, and a call per function pointer.
But speaking of tables, I miss data handling in FlexBasic.
DATA 1,2,3.14,"string",0
x = READ
RESTORE label
You can already have initialized global arrays for tables, but DATA is more flexible in that you can mix numbers, labels and strings.
It's a bit like the DAT section in Spin.
@yeti: you're correct that making it a "required base" instead of "option base" would be safer. But honestly I don't think people choose BASIC for safety, but rather for convenience. So I think there should be a default, and it seems the consensus here is for a base of 0.
So the default will allocate 11 elements for an array that is declared with "DIM foo(10)" with indices of 0-10? I guess that's the safest approach.
Yes, in the default case "DIM foo(10)" becomes "DIM foo(0 TO 10)" which will allocate 11 elements. And if you set "option base 9" then "DIM foo(10)" becomes "DIM foo(9 TO 10)" and allocates 2 elements. In all cases DIM is given an upper bound rather than a size. I think this is the way most BASICs work.
DATA is a really tricky case. You're right that it's like the DAT section, but it has to store a mixture of data types (floats, integers, strings) and I'm not sure how we can check that the values being read have the right types.
One way to implement it is to store the contents verbatim (as a string) in memory and then parse that string at runtime. Or, I guess we could store a long for each item (assuming everything fits in a long), with strings converted to pointers to their contents, but then there's no type checking on the READ. Maybe a long + a type flag?
DATA is a really tricky case. You're right that it's like the DAT section, but it has to store a mixture of data types (floats, integers, strings) and I'm not sure how we can check that the values being read have the right types.
One way to implement it is to store the contents verbatim (as a string) in memory and then parse that string at runtime. Or, I guess we could store a long for each item (assuming everything fits in a long), with strings converted to pointers to their contents, but then there's no type checking on the READ. Maybe a long + a type flag?
Maybe it should be done compatible to Spin.
DATAB for bytes, DATAW for words and DATAL or just DATA for longs and floats. With the same rules as in Spin ("..." for appended ASCII).
They generate initialzed arrays, but you can set labels in between for partial array access.
Not sure if READ and RESTORE makes then much sense. READ would need to know the size, or you need READB, READW.
Let's look at the typical INPUT command in the 8-bit home computers.
If you'd implement the INPUT {"prompt"} {,or;} {var} statement, then it flows naturally from there.
INPUT knows the type of the {var} it is seeking, or in this case read from SERIAL.
INPUT also has no qualms about refusing entry and starting over, saying something like *BAD VALUE, REDO FROM START*.
The inputted byte string usually goes into the "crunch buffer" that a BASIC interpreter typically has, if it is running in immediate mode.
So it gets a series of characters, and usually ENTER is pressed... some kind of EOL marker anyways. Let's be forgiving of (CR, CR+LF, or LF)!
Processing begins:
Ignore any leading spaces then I think it goes through and sees if it has a number (+ - . 0~9), or if it encounters an alpha character then it knows it's a string.
Paths diverge then, ultimately copying to {var}, which it knows the type and min/max range constraints of.
READ would be the same as an INPUT {var}, but redirected to a byte pointer.
At program start, the byte pointer is initialized to the very first DATA statement (an implicit RESTORE command).
The byte pointer has to know some things like what range it's allowed to work within, and awareness of the RESTORE command if used with a line number or label.
I think DATA statements would end up compiling to one or more constant strings (whose length can be very long).
So the byte pointer is read and incremented until it encounters the end of the string, or a comma. The data being fed into the crunch buffer. The crunch buffer then is interpreted to be either a number or string and put into the READ variable.
To make it easier, maybe require only one variable per READ?
@yeti: you're correct that making it a "required base" instead of "option base" would be safer. But honestly I don't think people choose BASIC for safety, but rather for convenience. So I think there should be a default, and it seems the consensus here is for a base of 0.
So the default will allocate 11 elements for an array that is declared with "DIM foo(10)" with indices of 0-10? I guess that's the safest approach.
Yes, in the default case "DIM foo(10)" becomes "DIM foo(0 TO 10)" which will allocate 11 elements. And if you set "option base 9" then "DIM foo(10)" becomes "DIM foo(9 TO 10)" and allocates 2 elements. In all cases DIM is given an upper bound rather than a size. I think this is the way most BASICs work.
Hmmm... Now I'm remembering why I'm not a BASIC programmer anymore.
@yeti: you're correct that making it a "required base" instead of "option base" would be safer. But honestly I don't think people choose BASIC for safety, but rather for convenience. So I think there should be a default, and it seems the consensus here is for a base of 0.
So the default will allocate 11 elements for an array that is declared with "DIM foo(10)" with indices of 0-10? I guess that's the safest approach.
Yes, in the default case "DIM foo(10)" becomes "DIM foo(0 TO 10)" which will allocate 11 elements. And if you set "option base 9" then "DIM foo(10)" becomes "DIM foo(9 TO 10)" and allocates 2 elements. In all cases DIM is given an upper bound rather than a size. I think this is the way most BASICs work.
Hmmm... Now I'm remembering why I'm not a BASIC programmer anymore.
The option base is an option, however why not cut to the quick and eliminate the problem at the source?
Dim a(0,10)
Dim b(1,10)
Dim c(2,10)
I'm sure someone won't like it, however there are so many known semantic issues with programming, it seems like we are decades past when simple solutions should have been applied.
I always love the complaining about how this or that will cause extra typing. Lets have more rules and regulations requiring memorization vs something that is actually more Human readable.
For my next trick, I'll show you one easy trick the experts don't want you to know which solves the white space tab vs spaces issue.
The option base is an option, however why not cut to the quick and eliminate the problem at the source?
Dim a(0,10)
Dim b(1,10)
Dim c(2,10)
I'm going to support that, but with FreeBasic syntax:
Dim a(0 to 10)
Dim b(1 to 10)
Dim c(2 to 10)
Careful programmers can use this version so there is no confusion about the base. But for compatibility with other BASICs I think we still need "option base".
You're too advanced. Basic programmers don't worry about such things.
I have had fun implementing BASIC interpreters though. I wrote a couple for the P1. Seems Eric has BASIC under control for the P2 though.
Well, a BASIC interpreter for P2 would still be nice to have, since it could run on the machine. Being able to type commands interactively would be great. We do have Tachyon for P2, but not everyone will be comfortable with FORTH syntax.
Yes. The FORTH is difficult. I must say Peter has done very well with Tachyon though. I used it a time or two on the P1, and it was the first FORTH I was able to find useful. Having it as the resident system tool in the P2 is going to be spiffy. With a well chosen dictionary, lots of one liner useful things will end up being passed around. All good, IMHO.
Thanks for this work ersmith. It's great, and I am super eager to make use of it.
There are BASICS we can compile. Eventually, the best BASIC will probably be a mostly PASM thing, using skip and friends for some real speed.
You're too advanced. Basic programmers don't worry about such things.
I have had fun implementing BASIC interpreters though. I wrote a couple for the P1. Seems Eric has BASIC under control for the P2 though.
Well, a BASIC interpreter for P2 would still be nice to have, since it could run on the machine. Being able to type commands interactively would be great. We do have Tachyon for P2, but not everyone will be comfortable with FORTH syntax.
Actually, I was thinking about that after I posted my previous message. However, I think with the relatively large amount of memory on the P2 that Eric might be able to get his BASIC compiler working on the P2 itself. In any case, I fully intend to play with the XBYTE feature to create fast byte code interpreters for some of the languages I wrote for the P1 even if they never really get used by anyone.
Well, a BASIC interpreter for P2 would still be nice to have, since it could run on the machine. Being able to type commands interactively would be great. We do have Tachyon for P2, but not everyone will be comfortable with FORTH syntax.
Actually, I was thinking about that after I posted my previous message. However, I think with the relatively large amount of memory on the P2 that Eric might be able to get his BASIC compiler working on the P2 itself. In any case, I fully intend to play with the XBYTE feature to create fast byte code interpreters for some of the languages I wrote for the P1 even if they never really get used by anyone.
I'm looking forward to seeing what you come up with. XBYTE certainly seems like a good way to implement interpreters.
I don't think fastspin will ever fit on the P2, it's got more than 512K bytes of code alone, and it does a lot of dynamic memory allocation.
Some useful BASIC commands that are not yet implemented in FlexBasic:
ON x GOTO/GOSUB label1, label2, ...
I think this can be replaced by a function table, and a call per function pointer.
Andy
+1000
This is great for state-machine sequencing....to switch a sequence off, make x=0. Just been playing with this in Android BASIC! and no matter the value of x, the execution time doesn't change so it feels like there is some pointer/jump-table thing happening.
I tried it with "print" instead of using "ser.*" and added a "then" to the "if" line:
$ cat rsut20181218-1221.bas
dim list(127) as ubyte
dim lptr as ubyte
let mes1$ = "Error-list"
if list(lptr) = &h20 then
print mes1$
end if
$ fastspin-3.9.12 rsut20181218-1221.bas
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2018 Total Spectrum Software Inc.
Version 3.9.12 Compiled on: Dec 10 2018
rsut20181218-1221.bas
rsut20181218-1221.pasm
Done.
Program size is 1620 bytes
$ █
Comments
What???
Needing an "option base" before the 1st "dim array(..)" is the exact opposite of lottery.
You have to think about what you need instead of starting to code, forgetting "option base" and maybe getting something that does not match the default.
And executing pasted code without thinking is what made "christma.exec" possible.
I don't want sloppy or forgiving defaults. I want correct programs.
For what it's worth tracking Freebasic too closely makes no sense at all.
Freebasic is a monster.
P1 is a micro controller, Flexibasic works because it takes advantage of the unique architecture of the Propeller and the embedded spin language.
Ron
QuickBasic and VB also start at zero by default.
I really don't see it as any kind of deviation from the norm when defaulting for Option Base 0, but being able to set to 1.
Not being able to dimension arrays without prior explicitely setting "option base something" still looks better to me: It will not prevent such errors but when looking for the reason you do not need to know the default then and every reader of that code will see what the coder wanted to be correct.
A bit of self documentation in the code.
Does that one line more really hurt sooooo much?
Defaults are faults!
It's called "option base" and not "required base"
ON x GOTO/GOSUB label1, label2, ...
I think this can be replaced by a function table, and a call per function pointer.
But speaking of tables, I miss data handling in FlexBasic.
DATA 1,2,3.14,"string",0
x = READ
RESTORE label
You can already have initialized global arrays for tables, but DATA is more flexible in that you can mix numbers, labels and strings.
It's a bit like the DAT section in Spin.
Andy
Yes, in the default case "DIM foo(10)" becomes "DIM foo(0 TO 10)" which will allocate 11 elements. And if you set "option base 9" then "DIM foo(10)" becomes "DIM foo(9 TO 10)" and allocates 2 elements. In all cases DIM is given an upper bound rather than a size. I think this is the way most BASICs work.
DATA is a really tricky case. You're right that it's like the DAT section, but it has to store a mixture of data types (floats, integers, strings) and I'm not sure how we can check that the values being read have the right types.
One way to implement it is to store the contents verbatim (as a string) in memory and then parse that string at runtime. Or, I guess we could store a long for each item (assuming everything fits in a long), with strings converted to pointers to their contents, but then there's no type checking on the READ. Maybe a long + a type flag?
This can be emulated by an array of strings.
Maybe it should be done compatible to Spin.
DATAB for bytes, DATAW for words and DATAL or just DATA for longs and floats. With the same rules as in Spin ("..." for appended ASCII).
They generate initialzed arrays, but you can set labels in between for partial array access.
Not sure if READ and RESTORE makes then much sense. READ would need to know the size, or you need READB, READW.
Andy
Let's look at the typical INPUT command in the 8-bit home computers.
If you'd implement the INPUT {"prompt"} {,or;} {var} statement, then it flows naturally from there.
INPUT knows the type of the {var} it is seeking, or in this case read from SERIAL.
INPUT also has no qualms about refusing entry and starting over, saying something like *BAD VALUE, REDO FROM START*.
The inputted byte string usually goes into the "crunch buffer" that a BASIC interpreter typically has, if it is running in immediate mode.
So it gets a series of characters, and usually ENTER is pressed... some kind of EOL marker anyways. Let's be forgiving of (CR, CR+LF, or LF)!
Processing begins:
Ignore any leading spaces then I think it goes through and sees if it has a number (+ - . 0~9), or if it encounters an alpha character then it knows it's a string.
Paths diverge then, ultimately copying to {var}, which it knows the type and min/max range constraints of.
READ would be the same as an INPUT {var}, but redirected to a byte pointer.
At program start, the byte pointer is initialized to the very first DATA statement (an implicit RESTORE command).
The byte pointer has to know some things like what range it's allowed to work within, and awareness of the RESTORE command if used with a line number or label.
I think DATA statements would end up compiling to one or more constant strings (whose length can be very long).
So the byte pointer is read and incremented until it encounters the end of the string, or a comma. The data being fed into the crunch buffer. The crunch buffer then is interpreted to be either a number or string and put into the READ variable.
To make it easier, maybe require only one variable per READ?
Teacher:
Let's count to 5.
Student:
0, 1, 2, 3, 4
Teacher:
You're far too advanced for my class.
Dim a(0,10)
Dim b(1,10)
Dim c(2,10)
I'm sure someone won't like it, however there are so many known semantic issues with programming, it seems like we are decades past when simple solutions should have been applied.
I always love the complaining about how this or that will cause extra typing. Lets have more rules and regulations requiring memorization vs something that is actually more Human readable.
For my next trick, I'll show you one easy trick the experts don't want you to know which solves the white space tab vs spaces issue.
Well, a BASIC interpreter for P2 would still be nice to have, since it could run on the machine. Being able to type commands interactively would be great. We do have Tachyon for P2, but not everyone will be comfortable with FORTH syntax.
Thanks for this work ersmith. It's great, and I am super eager to make use of it.
There are BASICS we can compile. Eventually, the best BASIC will probably be a mostly PASM thing, using skip and friends for some real speed.
I'm looking forward to seeing what you come up with. XBYTE certainly seems like a good way to implement interpreters.
I don't think fastspin will ever fit on the P2, it's got more than 512K bytes of code alone, and it does a lot of dynamic memory allocation.
Eric
+1000
This is great for state-machine sequencing....to switch a sequence off, make x=0. Just been playing with this in Android BASIC! and no matter the value of x, the execution time doesn't change so it feels like there is some pointer/jump-table thing happening.
Ron
My bad, IF needs a Then.
Ron
My 1st try on multi line "if"s was without "then" too.
Maybe the grammar can be tuned to make that "then" optional?