> python mbx.py "IaIbca+bPc" ?? 22 ?? 20 42
Minimal BASIC is a minimalist version of BASIC inspired by Brainf**k and Dennis Allison's Tiny BASIC (see examples here).
The language consists of just four commands: printing ('P'), input ('I'), assignment, and conditional jumps ('J'). Variable names are single lowercase letters. Labels used by jumps are single uppercase letters. Only integer arithmetic is supported, and expression operators only cover basic arithmetic and comparison, and are all single character symbols. Strings are only utilized for printing, and are included mainly as a debugging aid.
These restrictions mean that white space is irrelevant in the code, so a program can be represented by a single (long) string. As an example, here's fact.bas for calculating the factorial of a number entered by the user:
# fact.bas P "Enter a number" I n # input n r 1 # r = 1 i 1 # i = 1 A c i > n J c E # if i > n goto E r r * i # r = r*i i i + 1 J 1 A # back to A unconditionally E P "factorial:" P r # print the result P! # print a newlineIt's executed by mbx.py:
> python mbx.py fact.bas Enter a number ?? 5 factorial: 120
fact.bas is reformatted as a string by mbStr.py:
> python mbStr.py fact.bas "P-Inr1i1Aci>nJcErr*iii+1J1AEP-PrP!"
mbStr.py strips away the .bas file's comments and white spaces, and calls to 'P' involving strings (e.g. P "Enter a number") are rewritten to print nothing (by calling P-). Such a string can be passed to mbx.py to be executed:
> python mbx.py "P-Inr1i1Aci>nJcErr*iii+1J1AEP-PrP!" ?? 5 120
mbFormat.py does the reverse of mbStr.py, adding white space to make the string a little easier to understand:
> python mbFormat.py "P-Inr1i1Aci>nJcErr*iii+1J1AEP-PrP!" P - I n r 1 i 1 A c i>n J c E r r*i i i+1 J 1 A E P - P r P !
The BNF for Minimal BASIC is (unsurprisingly) quite short:
program ::= { [label] statement }
statement ::= 'P' (var | string | '!' | '-') # newline, ""
| 'I' var
| var expr
| 'J' atom label # jump to label if atom != 0
expr ::= atom [ op atom ]
atom ::= var | int
op ::= '+' | '-' | '*' | '/' | '&' | '|'
| '=' | '!' | '<' | '>'
# '/' is floor division: -7 / 2 = -4
# '=' is == and '!' is !=
# '&' is logical and '|' is logical or
# All logical operations return 1 (true) or 0 (false)
var ::= a-z
label ::= A-Z (excluding P, J, I)
int ::= (0-9)+
string ::= '"' [^"]* '"' # ! at end means \n
We can treat Minimal BASIC as a target language for a compiler of a higher-level imperative language. For example, a language with if-then-else, for, and while loops, is supported by tbc.py, translating a tb program using those features into a Minimal BASIC .bas file. As an example, consider primesHigh.tb, which tests whether an integer entered by the user is prime:
# primesHigh.tb
PRINT "Prime Tester"
INPUT "Enter number" n
IF n < 2 THEN
PRINT n, "is not prime"
ELSE
p = 1
m = n - 1
FOR i = 2 TO m
q = n / i
m = q * i
r = n - m
IF r == 0 THEN
p = 0
ENDIF
NEXT i
IF p == 1 THEN
PRINT n, "is prime"
ELSE
PRINT n, "is not prime"
ENDIF
PRINT p
ENDIF
Its translation to Minimal BASIC:
> python tbc.py primesHigh.tb P "Prime Tester" P ! P "Enter number" I n y n > 2 x n = 2 z y | x J z A P n P "is not prime" P ! J 1 B A P "-" p 1 m n - 1 i 2 C P "-" w i > m J w D q n / i m q * i r n - m v r ! 0 J v E p 0 J 1 F E P "-" F P "-" i i+1 J 1 C D P "-" u p ! 1 J u G P n P "is prime" P ! J 1 H G P "-" P n P "is not prime" P ! H P "-" P p P ! B P "-" --------------------- Written to primesHigh.bas
The generated .bas file can be run by mbx.py:
> python mbx.py primesHigh.bas Prime Tester Enter number ?? 97 97 is prime 1 > python mbx.py primesHigh.bas Prime Tester Enter number ?? 36 36 is not prime 0
The DOS batch file tbx.bat calls tbc.py followed by mbx.py:
> tbx.bat primesHigh.tb
Compiling primesHigh.tb ...
P "Prime Tester"
P !
P "Enter number"
I n
y n > 2
: more lines, not shown...
P !
H P "-"
P p
P !
B P "-"
---------------------
Written to primesHigh.bas
Running PRIMES~1.bas ...
Prime Tester
Enter number ?? 79
79 is prime
1
The .bas version of the primes tester can be converted to a string, and executed:
> python mbStr.py primesHigh.bas > temp.txt > python mbx.py "P-P!P-Inyn>2xn=2zy|xJzAPnP-P!J1BAP-p1mn-1i2CP-wi>mJwDqn/i -mvr!0JvEp0J1FEP-FP-ii+1J1CDP-up!1JuGPnP-P!J1HGP-PnP-P!HP-PpP!BP-" ?? 97 97 1 > python mbx.py "P-P!P-Inyn>2xn=2zy|xJzAPnP-P!J1BAP-p1mn-1i2CP-wi>mJwDqn/i -mvr!0JvEp0J1FEP-FP-ii+1J1CDP-up!1JuGPnP-P!J1HGP-PnP-P!HP-PpP!BP-" ?? 36 36 0
I copied the string argument of mbx.py from temp.txt. Note that there are no printed strings in this version of the primes tester, but the integer result (1 or 0) is still reported.
program ::= statement*
statement ::= assignment
| print | input
| while | for | if
| BREAK | CONTINUE
assignment ::= var '=' expr
print ::= PRINT print_item (',' print_item)*
print_item ::= atom | string
input ::= INPUT [string] var
while ::= WHILE expr statement* WEND
for ::= FOR var '=' atom TO atom [STEP atom]
statement* NEXT var
if ::= IF expr THEN statement* [ELSE statement*] ENDIF
expr ::= atom [ op atom ]
op ::= '+' | '-' | '*' | '/' | '&' | '|'
| '==' | '!=' | '<' | '<=' | '>' | '>='
Aside from higher-level control flow, tb also slightly extends the input, printing, assignment, and expression functionality.
One avenue to investigate further are other extensions to Minimal Basic. Two possibilities are support for more complex expressions, including precedence and brackets, and some simple form of GOSUB/RETURN.
I've made a start on the first one -- a standalone expression compiler is in exprCompiler.py, with a test input file called test1.txt, and the generated output in out.txt.
Screen.py contains a Screen class that manages a window consisting of a 2D grid of square cells, each of which can store a color. The class offers three main functions:
Color IDs are integers with the following meanings: 0 = white, 1 = black, 2 = red, 3 = green, 4 = blue, 5 = yellow, and 6 = gray.
The rendered grid looks like the following:

although it's possible to adjust the size of the cells and the grid.
The Screen class is utilized in a variant of mbx.py called mbxS.py which adds an 'S' command. Its BNF is:
statement ::= existing mbx statements and ...
| 'S' int '-' int [ '-' int ]
| 'S' '-'
For example, 'S 30-40-6' sets the cell at (30,40) to gray, while 'S -' clears the grid.
A complete program could be executed like so:
python mbxS.py "IaIbca+bPcS40-40Ia"
This prompts for two numbers and prints their addition, and displays the 2D grid with the cell at (40,40) colored black (by default). Note the inclusion of the final Ia which causes the program to wait until the user enters a value; this means that the Screen window will remain open for a while before the program ends.
One way of extending Screen would be to allow a cell to also contain a single character, allowing us to emulate the character mode displays of yesteryear.