I think you need to use a stack for the FOR statements. Then when you call NEXT you'll go from the top of the stack to the bottom and search for a match to the argument of the NEXT statement.
When you find a match you'll just discard any more recent entries in the stack.
For example if you do:
10 FORI=1TO5
20 FORJ=1TO10
30 PRINTJ;
40 IFJ=2THENNEXTIELSENEXT
50 NEXTJ
This program will (I think) print:
1212121212
and get a NEXT without FOR error on line 50 because the FORJ is removed from the FOR stack by the NEXTI call
OK. I've already tought to use a stack. to improve the speed i do not create a highlevel-sw implemented stack, but instead i try to use at max the processor support (its stack).
The same applies to gosub return (what kind of orrible thing... )
THIS MEANS: if the programmer is a beast that do things like jumping into gosub blocks without gosub, or use a for next loop like the above, if the program works correctly in msxbasic, also (i hope) run in it's compiled form. However, with those orrible things (like the above), if this doesn't work 100% correctly or crash, i think would be a great thing to learn programming and rewrite some parts in a much more cleaner way
So, do not expect things like array index checks, gosub without return checks, and so on... If you want those , stay in msxbasic, please. My goal is to achieve efficiency.
About errors though: remember that some programs rely on errors to be handled. ON ERROR GOSUB....
Using the processor stack may be slightly tricky (I haven't thought about it much) because you may need to discard entries in cases like the ones mentioned above or this:
10 FOR I=1 TO 5
20 FOR J=1 TO 5
30 PRINT J;
40 NEXT I
which will discard the top of the stack on the NEXT I statement and jump straight to line 10.
Another thing to keep in mind is that you can't directly translate
FOR I=1 to 5
to
for (i = 1; i <=5; i++)
because there isn't a direct mapping between c-types and Basic types. In Basic you need to have the types runtime changable, for example:
10 DEFSTRA-Z
20 A="Value: "
30 PRINT A
40 DEFINTA-Z
50 PRINT A
will output:
Value: 0
Here is a more weird consequence of the runtime types:
10 FOR I=1 TO 10
20 DEFSTR I
30 PRINT I
40 NEXT
This will output ten empty lines... (Not sure how this works actually, maybe NYYRIKKI can explain it)
EDIT: Actually what happens is that I% and I$ are different variables. To start with I will be mapping to I% but the DEFSTR I will map I to I$.
So this is basically what happens:
10 FOR I%=1 TO 10
20 DEFSTR I
30 PRINT I$
40 NEXT
if the NEXT line in the example would have been changed to
40 NEXT I
You'd get a NEXT without FOR error because I would refer to I$ which is not the same as I%
Would be easier to implement "newer" BASIC statements?
Like the While , Case , Do While ...
In the MSX-BASIC specific case, is this one of the implementations that is possible to re-adjust the value of the variable that control the loop? Some old BASIC program will use this feature for controlling the loop simulating a "Do While" statement. Not every interpreter will handle this as a correct manner ...
Here is a more weird consequence of the runtime types:
10 FOR I=1 TO 10
20 DEFSTR I
30 PRINT I
40 NEXT
This will output ten empty lines... (Not sure how this works actually, maybe NYYRIKKI can explain it)
EDIT: Actually what happens is that I% and I$ are different variables. To start with I will be mapping to I% but the DEFSTR I will map I to I$.
So this is basically what happens:
10 FOR I%=1 TO 10
20 DEFSTR I
30 PRINT I$
40 NEXT
if the NEXT line in the example would have been changed to
40 NEXT I
You'd get a NEXT without FOR error because I would refer to I$ which is not the same as I%
Implementing full support for all those things result finally in a crappy copy of the msx basic interpreter.
Some stuffs like also clear or DEFXXX are obviusly not supported for performance reasons.
The trick of FOR NEXT loop will also not work as expected in msxbasic. Basically i will do a alike of XBASIC KUN compiler with the ability to make independent binaries. Also i probably change the string management routines, that probably break some machine code programs that rely on msxbasic string structure.
As said before, my goal is speed.
take two examples:
1) X-TURBO BASIC (MSX): some commands are not the same. This is inerently due to the differences between the interpretative vs compiled approach.
2) Microsoft QBASIC 3-QBASIC 4 translation. This program is perfectly legal in qbasic 3 code:
10 for t%=0to10
20 if SOMEVAR%=0 THEN NEXT t%
30 E%=SQR(T%)
40 NEXT T%
... ma do not compile in QuckBASIC 4 and above. The reason? you cannot have multiple next T% and ONE FOR T% . you will be forced to change those orrible thing in a little less orrible:
10 for t%=0to10
20 if SOMEVAR%=0 THEN GOTO 40
30 E%=SQR(T%)
40 NEXT T%
About ON something GOSUB this is constly. Try to compile with or without support for those things (almost all old basic compilers have the option to support or not on....gosub). I will try to get support to those, using the same msxbasic mechanics.
In my first implementation I used a processor based stack pointer, however it soon became rather unmanagable due to ints, floats and strings all being differing sizes. So in the redesign I opted for basic software stack with each stack entry using 6 bytes, and had intended to speed this up (if I hadn't canned the whole project) using alignment at a later stage.
TBH I'm rather interested to see how you convert expressions etc to z80, as I admittedly no idea how a modern compiler would do it. I opted for the
LD Whatever
Call FetchInt
LD Somethingelse
Call FetchFloat
Call Add
LD ResultVar
Call StoreFloat.
Which is seemingly dozens times faster than MSX basic but still nowhere near what a hand written piece of code would be.
I wonder how useful it would be if a basic compiler only supported a subset of the language. I think its better to do a 100% compatible Basic compiler although it may be slightly slower.
In my first implementation I used a processor based stack pointer, however it soon became rather unmanagable due to ints, floats and strings all being differing sizes. So in the redesign I opted for basic software stack with each stack entry using 6 bytes, and had intended to speed this up (if I hadn't canned the whole project) using alignment at a later stage.
TBH I'm rather interested to see how you convert expressions etc to z80, as I admittedly no idea how a modern compiler would do it. I opted for the
LD Whatever
Call FetchInt
LD Somethingelse
Call FetchFloat
Call Add
LD ResultVar
Call StoreFloat.
Which is seemingly dozens times faster than MSX basic but still nowhere near what a hand written piece of code would be.
hey!, this is similar of what does virtual machine do. a stack based schema for compute expressions. Like java and M$ CLR do.
(Really when the jitter emit the code those stack based architecure turn into register based one....)
There is one big difference and that is the compiled version doesn't need to do any parsing so your code will be significantly faster than what the interpretor can do. There are also optimizations that can be done on the compiled code.