Dennis Allison’s 1975 article in Dr. Dobb’s Journal was a key moment in the history of Computer Science. It contained a formal specification of Tiny BASIC, a BASIC that could be implemented in less than 4 KB.
Stellar BASIC is very much in the same vein as Tiny BASIC, and is intended to evolve over time. However, Tiny BASIC itself is only a specification. One way is to compile a list of IL (intermediate language) statements. Once you have the IL interpretation you compile it and interpret it from there. On a machine with limited ram this approach can require up to 50% of the memory of a standard BASIC program. This is problematic. So machines like the C64 tokenized the statements on entry and executed them that way. The other issue with IL is that you have this compiled version and you also have the text lying around. That's two copies of the program. Which one is the 'real' program? If you remove the original text you can't necessarily LIST your code. Therefore, tokenization was settled on as a standard.
Therefore, when it came time to compile the IL into a program we instead chose a C64 style tokenization, and added $99 as PRINT as a subtle homage to the adventure, the love, and the magic of the C64 era.
LET (often optional)PRINTINPUTIF-THENGOTOGOSUB and RETURNFOR-NEXTA, B, Z)Some versions stored programs as text, some as tokenized program code to save space.
Stellar Basic is based on the intermediate language specs for Pao Alto Tiny Basic, written by Dennis Allison in 1975.
For a complete tutorial on BASIC, please see the SD-8516 User's Guide.
10 LET A = 1 20 PRINT A 30 A = A + 1 40 IF A <= 10 THEN GOTO 20 50 END
Stellar BASIC will allow this even shorter form:
10 A=1 20 ?A 30 A=A+1 40 IF A<=10 GOTO 20
(? is shorthand for PRINT.)
Everything in PATB is stack-based. This is a core design principle. There are three stacks:
The plan was to implement the IL as a service library so it could be used by other languages later on too.
Up until around Phase 5 things were going fine. Oh, how naieve I was. After I finished and tested the IL, a work in itself, I began to have a lot of trouble getting the tokenizer and execution loop to work together. After weeks of tracing through the code I decided to remove the tokenizer. At that point I was able to pinpoint the last 3 or 4 core bugs and fix them. It finally worked! It's amazing, you know, to see these things being brought up from scratch.
The basic_execution_loop always loads the next line. However, if the U flag is set (by the GOTO executor) it loads the next line pointer from PATB_PROGRAM_POINTER instead. This was normally set by NEXT_LINE, but however it is set it then calls BASIC_EXEC_LINE. This was a rather simple addition.
A rather simple thing, I just checked for a keypress every run loop.
; Check for ESC key LDAH $00 ; Read char (non-blocking) INT $10 JZ @continue ; ZF=1 = no key CMP AL, #27 ; ESC? JNZ @continue ;; print break message and RET
I thought INPUT was going to be complex, but it turned out very easy. I had written input routines before. The strategy was to do a simple input routine. I used a loop with blocking input (from INT 10h) and put keys in a buffer as they were typed, ending on ENTER. I just used the TTY function (from INT 10h again) and various others to handle backspace, etc. and it just worked.
I realize this may not satisfy the curiosity of some, and, things are getting a bit complex so I'm just going to write out what needed to be done here as a sort of recipe. Later commands will follow the same general idea.
Next cross your fingers and hope it works!
We are going to make a RAND() which is for integers since I did not add floating point support yet. The idea is RAND(num) will return a random number between 0 and NUM-1. So RAND(100) will give 0-99. Or should I do it another way?
The big issue here is going to be how do we expand parse_expression? That's the RIGHT way to do it so that it can work in immediate mode, in a PRINT, or as a variable expression.
I left this for last and not because its the best but because it was hard. I had to subordinate evaluate_expression to evaluate_factor (of an expression) and then evaluate expression would evaluate the factors of the expression. I'll write up what I did later. But it was a bit painful and I would like to take a break from it.
Well first off, PATB is a specification. I tried to follow it, but there were so many little things I chose to do differently that it diverged pretty early on. For example, I added LINE_FIND_REVERSE and LINE_PREV as well as LINE_MAKE_SPACE and LINE_REMOVE_SPACE for line management. For my own comfort. I also write a string handling library (INT 12h) that could be used.
Although I tried to work from example code and specs (such as that published in Dr. Dobb's journal) I did not completely understand what I was doing because I was unfamiliar with the assembly code used in the article. However the basic ideas were easy to draw out and after some study I had a decent IL. I also added string helpers, most of which were moved into INT 12h now.
I had so much trouble with the tokenizer I decided to ditch it. That allowed me to get the execution loop working (after a lot of trouble!) Then I was able to start adding more commands – first GOTO then INPUT. By this time I had significantly diverged from the ideas of PATB and I couldn't really point to anything in the system that was related to PATB except some of the IL function names. I decided to call it “Stellar basic”, since after all, it is from the fantasy scientific laboratory “Stellar Dynamics”.
After I finally got the execution loop working, GOTO and INPUT I started focusing on how to get strings working. Once that was all hooked up I added a RND function. After quite some debugging and fish poking I was able to create a random number guessing game in BASIC. This was a huge milestone for me, so I set BASIC aside at this point to work on other aspects of the system.
Later, I plan to try and write a text adventure game in BASIC, or add graphics commands. The main driver at this point will be whatever I need to add to BASIC to write some interesting games for the sytsem!
Just like the old days!
This is NUMGUESS, the first program written for Stellar BASIC. It demonstrates TinyBASIC as a MVP; consisting of PRINT, LET, GOTO, INPUT, RAND and IF-THEN.
This program is also listed in the Stellar BASIC Programs list.
10 PRINT ""
20 PRINT "NUMBER GUESSING GAME V1.0"
30 PRINT "BY APPLEDOG (C) 2026"
40 PRINT "INSTRUCTIONS:"
50 PRINT " GUESS THE NUMBER, AND"
60 PRINT " TYPE YOUR ANSWER BELOW!"
70 PRINT "============================"
100 LET A = 1
110 LET B = 100
120 LET C = B - A
130 LET D = RAND(C)
140 LET F = 0
200 LET F = F + 1
300 PRINT ""
310 PRINT "ROUND "F
320 PRINT "LOW: "A
330 PRINT "HIGH: "B
340 INPUT "ENTER A NUMBER: ", E
350 IF E > B THEN GOTO 1000
360 IF E < A THEN GOTO 2000
370 IF E < D THEN GOTO 3000
380 IF E > D THEN GOTO 4000
400 GOTO 5000
1000 PRINT "THAT NUMBER IS TOO LARGE."
1010 PRINT ""
1020 GOTO 300
2000 PRINT "THAT NUMBER IS TOO SMALL."
2010 PRINT ""
2020 GOTO 300
3000 PRINT "YOUR GUESS IS TOO SMALL!"
3010 LET A = E
3020 PRINT ""
3030 GOTO 200
4000 PRINT "YOUR GUESS IS TOO LARGE!"
4010 LET B = E
4020 PRINT ""
4030 GOTO 200
5000 PRINT "YOU WIN!"
5010 LET F = 101 - F
5020 PRINT "SCORE: "F
I might do this faster but I'll just write out a long-term guide to make sure I have time. After all, Reing of the Warlock is out, first new DLC for Diablo 2 in 25 years, gotta grind up on the hc ladder frfr this time IYKYK.