![]() |
Forum Index : Microcontroller and PC projects : CMM2: MMBasic Transpiler
Page 1 of 2 ![]() ![]() |
|||||
Author | Message | ||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Hello folks, Release 1, beta 1 of my MMBasic Transpiler is now released. What is it? A transcompiler and code-formatter for MMBasic 5.05 running on the Colour Maximite 2. Features: * Flattens #Include hierarchies * useful for moving code from the CMM2 to other MMBasic flavours that currently do not support #Include. * supports multiple levels of #Include and does not require the files to have ".inc" file-extension * MMBasic 5.05 on the CMM2 only supports a single level of #Include, i.e. a ".bas" file can #Include one or more ".inc" files and that's it. * Configurable code reformatting * automatic indentation. * automatic update of spacing between tokens. * remove comments. * remove empty-lines. * Conditional commenting/uncommenting of code sections * useful for supporting multiple MMBasic flavours from a single source-tree. * Configurable token replacement * useful for improving performance by inlining constants and shortening identifiers. * currently only supports a 1 -> 1 mapping. For more information see https://github.com/thwill1000/mmbasic-transpiler/blob/master/README.md Where can I download a zip file? https://github.com/thwill1000/mmbasic-transpiler/releases/download/r1b1/mbt-r1b1.zip What does it contain that might be worth repurposing for my own creations? * Lexer/tokenizer for the MMBasic language. * Implementations of 'Set' and 'Map' datastructures. * Command-line option parsing built upon the lexer. * The beginnings of an MMBasic unit-testing framework. Hope that it's of some use, Tom Edited 2020-07-22 22:43 by thwill MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Ugh, sorry about the mess, my original post included a right-arrow character (Alt-26) that the forum software didn't like. I'll see if I can get Glenn to remove the empty posts. Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
abraxas Regular Member ![]() Joined: 16/06/2020 Location: CanadaPosts: 99 |
Great initial feature set, thwill! Thanks for this work. I think I will have a play with it on my sources. That said, the killer feature for me would be the ability to inline CONST variables. In tight loops I resort to using hardcoded magic numbers to avoid the cost of indirection that the interpreter adds to dereference a variable. Is that feature in line with the things you envision for this project? |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Hi "abraxas", it could be prettier and more automated, but I'm already using the transpiler for constant inlining, at least if the constant value is a single token. If you transpile this: '!set INLINE_CONSTANTS '!replace A 1 '!replace B 2 '!comment_if INLINE_CONSTANTS Const A = 1 Const B = 2 '!endif Print A + B Then you get this: Print 1 + 2 EDIT: Note there is nothing magic about the choice of INLINE_CONSTANTS as the name for the controlling flag. Regards, Tom Edited 2020-07-23 00:40 by thwill MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
abraxas Regular Member ![]() Joined: 16/06/2020 Location: CanadaPosts: 99 |
Thanks, Tom. Is there a reason to repeat yourself in the source though? Looks like you have to declare each replacement explicitly with the '!replace statements? Is there a possibility in the future for a '!replace ALL as a catch all for inlining every CONST variable? Edited 2020-07-23 01:29 by abraxas |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Is there a possibility in the future for a '!replace ALL as a catch all for inlining every CONST variable? Actually I'm not sure that is possible in the general case. Consider the following which I believe to be valid MMBasic: If foo Then Const A = 1 Else Const A = 2 EndIf There is no way for the transpiler to know what value to use for 'A' unless 'foo' is also a Const .. and even then you start having to build a lot of "smarts" into the transpiler. The behaviour of an interpreted language like MMBasic a lot more "interesting" than something compiled like "C". That leaves you with 2 options: - Either the transpiler imposes restrictions on what subset of BASIC it allows, e.g. if it finds there are two declarations of A then it simply refuses to transpile, or better yet it won't create an automatic replacement for A. - Or you are forced to use the transpiler as a preprocessor, i.e. you write code that won't RUN unless it is first transpiled, which you can already do, e.g. Option Explicit On '!replace A 1 '!replace B 2 Print A + B Regards, Tom Edited 2020-07-23 02:01 by thwill MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
abraxas Regular Member ![]() Joined: 16/06/2020 Location: CanadaPosts: 99 |
Is there a possibility in the future for a '!replace ALL as a catch all for inlining every CONST variable? Actually I'm not sure that is possible in the general case. Consider the following which I believe to be valid MMBasic: If foo Then Const A = 1 Else Const A = 2 EndIf There is no way for the transpiler to know what value to use for 'A' unless 'foo' is also a Const .. and even then you start having to build a lot of "smarts" into the transpiler. The behaviour of an interpreted language like MMBasic a lot more "interesting" than something compiled like "C". That leaves you with 2 options: - Either the transpiler imposes restrictions on what subset of BASIC it allows, e.g. if it finds there are two declarations of A then it simply refuses to transpile, or better yet it won't create an automatic replacement for A. - Or you are forced to use the transpiler as a preprocessor, i.e. you write code that won't RUN unless it is first transpiled, which you can already do, e.g. Option Explicit On '!replace A 1 '!replace B 2 Print A + B Regards, Tom Yeah, that's a very astute point, Tom. Now I understand the limits. I'm still biased to read code as if it's compiled when it's not. What you said makes sense and the way you handle this is probably the best compromise (or at least I can't think of any improvement at this point). |
||||
Atomizer_Zero Senior Member ![]() Joined: 04/07/2020 Location: United KingdomPosts: 134 |
Decided to give this a try, as a break from grilling over lines and lines of code for hours on end recently... It starts out fine, but it gets some part through my second .inc file, and gives me an error [169] error: index out of bounds is it something in my code causing this? I didn't add any extra options to the cmdline. cheers |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
That suggests it thinks there is a line with more than 50 BASIC tokens on it, sounds unlikely so probably a bug on my side. Can you point me at the code in question and I'll see what I can do. Regards, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
"Worked" for me on the last version posted here: https://www.thebackshed.com/forum/ViewTopic.php?FID=16&TID=12399&LastEntry=Y#151086 I quote "Worked" because I'm not connected to a VGA monitor so I can't execute the result. Regards, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Looking at this code I would say there is at least a 10% speed improvement waiting in reducing identifier lengths. Maybe 5% or more in inlining the constants. Maybe 5% in inlining the 1-2 line functions - my transpiler can't help with that yet I'm afraid. Regards, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Sorry ... wrong program, I thought this was the Boulderdash port. Let's go back to the beginning, can you point me at the code ? ![]() Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
Atomizer_Zero Senior Member ![]() Joined: 04/07/2020 Location: United KingdomPosts: 134 |
lol. No worries. I haven't actually released my code yet, as it's far from complete and probably needs a complete rewrite to be honest. When you said " a line with more than 50 basic tokens in ", what exactly is a basic token? |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
For the transpiler a token is a keyword (e.g. DIM), identifier (i.e. variable/sub/function name), operator or other symbol (e.g. >= or :), number literal (e.g. 42, 3.6e-17, &hFF), string literal (e.g. "foo bar"), directive or comment. So it is unlikely you have 50 on one line unless you are doing something very peculiar. Note that Peter will occasionally talk about the limited number of tokens restricting the ability to extend MMBasic, this is different. Each of the MMBasic's top-level 128 operators/functions and 128 commands has a unique *byte* value that is used when the firmware tokenises a file to execute. Because the language has now reached the 256 token limit that can fit in a byte there are restrictions on how it can be extended without a significant rewrite. I'm not sure what command line you are using, but if you execute: RUN "/mbt/mbt.bas", "input.bas" Then you should see the output on the console up until the failing line in your code. You can also add the -C flag to syntax highlight the output if you are using a VT100 terminal. I'm really curious to find out what is going on so I'd appreciate it if you would persevere with mbt, I can add some additional diagnostics if necessary. Regards, Tom Edited 2020-07-28 08:38 by thwill MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Deleted strange double post. Edited 2020-07-28 09:14 by thwill MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
Atomizer_Zero Senior Member ![]() Joined: 04/07/2020 Location: United KingdomPosts: 134 |
1871: If (SPRSCLN(i, 2)) And &H80 = 0 Then 1872: If (((SLINE - SPRSCLN(i, 0))And &HFF)< 8) Then 1873: LOSPRADDR = (((SPRSCLN(i, 1) And &H01) << 12) Or ((SPRSCLN(i, 1) And &HFE) << 4) Or ((SLINE - SPRSCLN(i, 0)) And &H07)) And &HFFFF 1874: Else [169] Error: Index out of bounds This is where it fails. It's a complicated nested if else set of statements that call functions and do bit manipulation and such. So i'm not surprised it's causing issues lol. I'm going to have to rewrite this at some point anyway, as it's very unoptimized and probably doesn't even work properly in it's current state haha. |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Right, that line does contain more than 50 tokens I guess that means I need to up the limit. You can fix it for yourself by editing line 55 of "mbt.bas": Const LX_MAX_TOKENS = 50 Thanks for reporting the problem, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
lizby Guru ![]() Joined: 17/05/2016 Location: United StatesPosts: 3378 |
Tom--I know your transpiler has a different purpose, but since it seems it must do most of the parsing work needed, would it be difficult to modify it to produce a hierarchical tree of a program's structure? For instance: A B C D C E F C G H B C I ~ Edited 2020-07-31 22:17 by lizby PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Hi Lizby, I'm sorry, I don't understand. What are the elements A, B, C ... ? Perhaps a more specific example would help. Regards, Tom Edited 2020-07-31 22:26 by thwill MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 4044 |
I guess they're each the names of SUBs and FUNCTIONs. So, A calls each of B, D, E, G and I. Often called a call tree. Beware recursion... John Edited 2020-07-31 23:00 by JohnS |
||||
Page 1 of 2 ![]() ![]() |
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |