dmsc Posted June 29, 2017 Share Posted June 29, 2017 Hi! Over the last months I have been writing a new Basic interpreter for the Atari 8-bit computers. My goals are: - Integer variables - Small size (currently less than 6k) - Fast execution (currently, about 15% faster than compiled TurboBasicXL in the "sieve.bas" benchmark) - Modern (no line numbers, many control structures) - "alike" TruboBasicXL. Attached is my current "beta" release. What is missing is an editor, currently it only runs text programs from disk, and possibly more commands. Also, parsing speed is slow, main reason is that the file is read a line at a time, if the file were read from memory the parser would be a lot faster. I ported one of my ten-liners to the interpreter, and included some demonstration programs. Well, bug reports and new ideas are welcomed ----- cheat sheet ----- All statements and variable names can be lower or uppercase, the parser is case insensitive. No line numbers are allowed. Supported integer operators, in order of precedence: + - : addition, subtraction * / MOD : multiplication, division, modulus & ! EXOR : binary AND, OR and EXOR + - : unary "+" and "-" Supported functions: TIME : time in jiffies ABS(N) SGN(N) PEEK(N) PADDLE(N) PTRIG(N) STICK(N) STRIG(N) RAND(N) : random from 0 to N DPEEK(N) FRE() : free memory ERR() : last I/O error ADR(array) : address of array in memory ADR(string) LEN(string) VAL(string) ASC(string) Supported boolean operators, in order of precedence: OR : Logical OR AND : Logical AND NOT : Logical NOT <= >= <> < > = : Integer comparison Strings: String variables don't need DIM, are of max 255 bytes length. String constants can have embedded " by duplicating (" my string ""hello"" ") Arrays: Arrays must be DIM before use. After array name, you can specify "WORD" or "BYTE" to give a type. DIM Array1(10) Word, SmallArray(32) Byte Variables: Variables are always INT (from -32768 to 32767), must be assigned before use. Statements: ' : Comment (REM) . : Comment (REM) ? : PRINT BGET # BPUT # CLOSE # COLOR DIM DO / LOOP DPOKE DRAWTO END : Terminates parsing, go to command mode EXEC EXIT : Exits from DO, REPEAT, WHILE or FOR FILLTO FOR / TO / NEXT FOR / TO / STEP / NEXT GET : Get from Keyboard GET # GRAPHICS IF / ELSE / ENDIF IF / THEN INC INPUT MOVE / -MOVE OPEN # PAUSE PLOT POKE POSITION PRINT PROC / ENDPROC PUT : Put to E: PUT # REPEAT / UNTIL SETCOLOR SOUND : With no parameters silences all sounds. WHILE / WEND XIO # fastbas.atr 23 Quote Link to comment Share on other sites More sharing options...
pirx Posted June 29, 2017 Share Posted June 29, 2017 WOW!!! Quote Link to comment Share on other sites More sharing options...
pirx Posted June 29, 2017 Share Posted June 29, 2017 gtia = $d000 ... dpoke gtia + $02,48 + trackPos / 32 Does it mean unsigned INT is also OK but for calculations? Quote Link to comment Share on other sites More sharing options...
Island2Live Posted June 29, 2017 Share Posted June 29, 2017 This is MOST interesting. :-) By looking over the defined instruction set I don't see anything important missing. What's missing would be a deeper documentation but that's definitely nitpicking at this point. Oh, one thing: You should set up a little website ... with a donation-button! I would be willing to pay for that! Quote Link to comment Share on other sites More sharing options...
mono Posted June 29, 2017 Share Posted June 29, 2017 Nice alternative to AtariBASIC What about USR() function? Quote Link to comment Share on other sites More sharing options...
dmsc Posted June 29, 2017 Author Share Posted June 29, 2017 Hi! gtia = $d000 ... dpoke gtia + $02,48 + trackPos / 32 Does it mean unsigned INT is also OK but for calculations? Yes, you can input any number from -65535 to 65535 (or -$FFFF to $FFFF), but the representation is as signed two complement integers. The only places where this is important is in comparisons (<, >, <= and >=), division and printing. You need to be specially careful with FOR loops, as a simple looking "FOR I=0 TO 40000" won't iterate. This is MOST interesting. :-) By looking over the defined instruction set I don't see anything important missing. What's missing would be a deeper documentation but that's definitely nitpicking at this point. Oh, one thing: You should set up a little website ... with a donation-button! I would be willing to pay for that! About the documentation, that is always a weak spot for me , perhaps the community could help with that. I plan to release the source code after I a little cleanup, probably under a GPL license. Nice alternative to AtariBASIC What about USR() function? I plan to implement USR() and DATA, but I don't really like "USR" as a function, I probably would implement a "SYSTEM" statement instead. Quote Link to comment Share on other sites More sharing options...
luckybuck Posted June 29, 2017 Share Posted June 29, 2017 Did you all took a look at OSS Integer Basic including source code and benchmarks: https://atariwiki.org/wiki/Wiki.jsp?page=OSS%20Integer%20Basic ? Quote Link to comment Share on other sites More sharing options...
dmsc Posted June 29, 2017 Author Share Posted June 29, 2017 Hi! Did you all took a look at OSS Integer Basic including source code and benchmarks: https://atariwiki.org/wiki/Wiki.jsp?page=OSS%20Integer%20Basic ? No, this interpreter is not based on any existing BASIC, it is written from scratch. But I expect my interpreter to be about 5 times faster than the OSS one. 1 Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted June 29, 2017 Share Posted June 29, 2017 24-bit and 32-bit ints would be very nice (and would make one completely forget about FP). It's an interesting project, for sure. Quote Link to comment Share on other sites More sharing options...
luckybuck Posted June 29, 2017 Share Posted June 29, 2017 @dmsc: No, it is not. It is from OSS. It's the fastest Basic for the Atari, when real numbers are not required. Please see the bechmarks and compare. Further, I highly recommend to take a look at the source code. Further, a cart has been made of it. Quote Link to comment Share on other sites More sharing options...
mono Posted June 29, 2017 Share Posted June 29, 2017 (edited) I plan to implement USR() and DATA, but I don't really like "USR" as a function, I probably would implement a "SYSTEM" statement instead. USR as a function can return a result - I think it is very flexible, because you can use it in expressions. If you decide to implement USR I suggest you to add error support. This is very simple and can acts similar to I/O operation error support. If USR user function has changed error variable with error code (AtariBASIC has it at $B9 ERRCOD and initialize it to 0) it is catched by TRAP (if set, otherwise breaks program with error message). Of course you could return it by ERR() function. This is simplest way to extend language function set. Edited June 29, 2017 by mono Quote Link to comment Share on other sites More sharing options...
Bryan Posted June 29, 2017 Share Posted June 29, 2017 Yes, you can input any number from -65535 to 65535 (or -$FFFF to $FFFF), but the representation is as signed two complement integers. The only places where this is important is in comparisons (<, >, <= and >=), division and printing. You need to be specially careful with FOR loops, as a simple looking "FOR I=0 TO 40000" won't iterate. I'm confused. Do you mean you support 17 bit signed or did you mean -32768 to +32767 because 40000<65535. Quote Link to comment Share on other sites More sharing options...
mono Posted June 29, 2017 Share Posted June 29, 2017 Do you use RPN for expression parsing and executing? Quote Link to comment Share on other sites More sharing options...
dmsc Posted June 29, 2017 Author Share Posted June 29, 2017 Hi! @dmsc: No, it is not. It is from OSS. It's the fastest Basic for the Atari, when real numbers are not required. Please see the bechmarks and compare. Further, I highly recommend to take a look at the source code. Further, a cart has been made of it. Sorry, I tried to say that *my* interpreter is written from scratch. I tested the "sieve" benchmark, in an NTSC Atari800XL, graphics 0, result is: - OSS Integer Basic: 7107 jiffies ( 3.64x slower) - TurboBasicXL: 7939 jiffies (4.07x slower) - Atari Basic: 24556 jiffjes (12.6x slower) - FastBasic: 1950 jiffies Note that TurboBasicXL and AtariBasic versions use "POKE/PEEK" instead of an array to store result, because you can't define arrays as big. Attached are the benchmark programs. sieve-bench.zip 1 Quote Link to comment Share on other sites More sharing options...
luckybuck Posted June 29, 2017 Share Posted June 29, 2017 Sorry, did misunderstand, maybe I am too old. Wow! That sounds fantastic. Will take a closer look at. Thank you very much! :-))) Quote Link to comment Share on other sites More sharing options...
dmsc Posted June 29, 2017 Author Share Posted June 29, 2017 USR as a function can return a result - I think it is very flexible, because you can use it in expressions. If you decide to implement USR I suggest you to add error support. This is very simple and can acts similar to I/O operation error support. If USR user function has changed error variable with error code (AtariBASIC has it at $B9 ERRCOD and initialize it to 0) it is catched by TRAP (if set, otherwise breaks program with error message). Of course you could return it by ERR() function. This is simplest way to extend language function set. What I dislike about "USR" is that side-effects become visible, you need to specify the order of execution in cases like "POSITION USR(A), USR(B)" or worse "USR(A,USR(B))". All this is not possible with a statement. About errors, currently my interpreter don't have a "TRAP" instructions, you need to manually check "ERR()" after each I/O operation, so certainly you could write a ML routine that writes to the error variable. I tough of adding TRAP, but currently I don't have "GOTO", so it does not feel natural. Also, to properly TRAP you should roll-back the execution stack, and my interpreter does not keeps track of the stack (the parser makes sure that all the exits from control-blocks clear the stack properly). I'm confused. Do you mean you support 17 bit signed or did you mean -32768 to +32767 because 40000<65535. No, all integers are 16bit, but the parser allows numbers up to 65535. This means that if you write 40000, the parser stores the same number as -25536, so this means that 0 is bigger than 40000 (=-25536). Then, a "FOR I=0 to 40000" does no iterations. Do you use RPN for expression parsing and executing? The interpreter is a stack-machine, so it is like RPN. The parser is a recursive descent parser with no token recognition (parses directly from input), interpreted using a state-machine. This state-machine is generated from a description file similar to a PEG grammar. 2 Quote Link to comment Share on other sites More sharing options...
Bryan Posted June 29, 2017 Share Posted June 29, 2017 No, all integers are 16bit, but the parser allows numbers up to 65535. This means that if you write 40000, the parser stores the same number as -25536, so this means that 0 is bigger than 40000 (=-25536). Then, a "FOR I=0 to 40000" does no iterations. Ah, okay. It's up to the user to handle when something is treated as negative. Quote Link to comment Share on other sites More sharing options...
mono Posted June 29, 2017 Share Posted June 29, 2017 (edited) The interpreter is a stack-machine, so it is like RPN. The parser is a recursive descent parser with no token recognition (parses directly from input), interpreted using a state-machine. This state-machine is generated from a description file similar to a PEG grammar. Great! I think RPN speeds-up execution a little bit What I dislike about "USR" is that side-effects become visible, you need to specify the order of execution in cases like "POSITION USR(A), USR(B)" or worse "USR(A,USR(B))". All this is not possible with a statement. Of course, but because USR is a function, the order is specified exactly as for each other built in functions of language. If you can stack it correctly, then it will be work in correct order (as built in functions). About errors, currently my interpreter don't have a "TRAP" instructions, you need to manually check "ERR()" after each I/O operation, so certainly you could write a ML routine that writes to the error variable. I tough of adding TRAP, but currently I don't have "GOTO", so it does not feel natural. Also, to properly TRAP you should roll-back the execution stack, and my interpreter does not keeps track of the stack (the parser makes sure that all the exits from control-blocks clear the stack properly). There is no problem there is no TRAP in FB - ERR() function is enough. My suggestion is to publish address of error code variable for USR programmers to enable support of errors returned from user ML code . AtariBASIC hasn't this functionality. Maybe you would extend your BASIC about TRY/CATCH instead of TRAP ? Edited June 29, 2017 by mono Quote Link to comment Share on other sites More sharing options...
+Philsan Posted June 29, 2017 Share Posted June 29, 2017 Very nice! Are sprites commands out of question? A command to move all sprites at the same time would be useful for multicolor sprites... 1 Quote Link to comment Share on other sites More sharing options...
dmsc Posted June 30, 2017 Author Share Posted June 30, 2017 Hi! There is no problem there is no TRAP in FB - ERR() function is enough. My suggestion is to publish address of error code variable for USR programmers to enable support of errors returned from user ML code . AtariBASIC hasn't this functionality. Maybe you would extend your BASIC about TRY/CATCH instead of TRAP ? Well, try/catch is actually easier than a simple "TRAP", you simply *save* the stack position on "TRY" and restore it in the "CATCH". It get's tricky if you allow nested try/catch, but I can simply ignore that. Very nice! Are sprites commands out of question? A command to move all sprites at the same time would be useful for multicolor sprites... As you know, there is no way to move P/M "simultaneously", because you can only write *one* Antic register at a time. The recommended way to do that (even on ML programs) is to wait for VCONT > some line and then write all registers. There are two ways to do that in FastBasic: - Simply wait for the correct VCOUNT: - Use "PAUSE 0" to wait for the VBI (remember that VBI is at VCOUNT = 124) I don't really like the PMMOVE statement in BasicXE, because it always moves all the PM data, so it's slower than posible. Using "MOVE" and "-MOVE" it's easy to do sprites. This is a P/M testing program that shows that with a simple PROC to move P/M you can have PM support, as you see in the picture there is many frame time still available (purple lines): This is the program source: ' P/M test program RAMTOP = $6A : SDMCTL = $22F : PCOLR0 = $2C0 HPOSP0 = $D000 : GRACTL = $D01D : PMBASE = $D407 ' Reserve memory at TOP MemTop = Peek(RAMTOP) - 4 P0Mem = $100 * MemTop + $200 oldPos = P0Mem poke RAMTOP, MemTop ' Activate and configure P/M data graphics 0 poke P0Mem, 0 : move P0Mem, P0Mem+1, 127 : ' Clears Memory poke PCOLR0, $1F poke SDMCTL, Peek(SDMCTL) ! 8 poke PMBASE, MemTop poke GRACTL, 2 ' P/M data and blank as strings PMdata = 1 + Adr("8DTD8") : PMclear= 1 + Adr("\00\00\00\00\00") ' Initial Conditions xPos = 6400 : yPos = 2560 xSpd = 64 : ySpd = 0 do xPos = xPos + xSpd : yPos = yPos + ySpd ySpd = ySpd + 2 if (ySpd > 0) and (yPos > 12800) ySpd = -ySpd xSpd = Rand(512) - 256 endif if xSpd > 0 if xPos > 25600 Then xSpd = -xSpd else if xPos < 6400 Then xSpd = -xSpd endif exec MovePm : ' Move P/M Graphics loop proc MovePm x = xPos / 128 : y = P0Mem + yPos / 128 poke $D01A,$74 : ' Change background color pause 0 poke HPOSP0, x move PMclear, oldPos, 5 move PMdata, y, 5 oldPos = y endproc 1 Quote Link to comment Share on other sites More sharing options...
Rybags Posted June 30, 2017 Share Posted June 30, 2017 I had a quick look yesterday - looks good. I'm thinking I might try and port one of my games over though the one I most had in mind is very heavy on the FP and would be a big job. Quote Link to comment Share on other sites More sharing options...
dmsc Posted June 30, 2017 Author Share Posted June 30, 2017 Hi! I finally uploaded the full sources at https://github.com/dmsc/fastbasic 7 Quote Link to comment Share on other sites More sharing options...
+CharlieChaplin Posted June 30, 2017 Share Posted June 30, 2017 But errmmm, Fast Basic is not a good name, since there already exists a Basic with that name for approx. 20 or more years - Fast Basic by Tom Hunt (has no extra commands, it is just about 10%-30% faster than Atari Basic)... Quote Link to comment Share on other sites More sharing options...
pirx Posted June 30, 2017 Share Posted June 30, 2017 (edited) I guess the confusion will be absolutely negligible thanks to TBXL that completely overshadowed Tom Hunt's FB that shall be known from now on as the Tom Hunt's Fast Basic :]]]]] Edited June 30, 2017 by pirx 1 Quote Link to comment Share on other sites More sharing options...
baktra Posted June 30, 2017 Share Posted June 30, 2017 I believe that this project deserves a unique name. Flying Basic, FlyBasic, DMSC Basic, FI Basic, Jet Basic, Citus Basic... Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.