= SD-8516 Stellar Basic V1.0 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. == Core features * Line-numbered programs * ''LET'' (often optional) * ''PRINT'' * ''INPUT'' * ''IF-THEN'' * ''GOTO'' * ''GOSUB'' and ''RETURN'' * ''FOR-NEXT'' * Usually only access to integer variables and integer based math * Single letter variables (ex. ''A'', ''B'', ''Z'') * No floating-point math * Very limited strings * No arrays * No file I/O * Minimal error messages * Very limited editing commands Some versions stored programs as text, some as tokenized program code to save space. == Notable Tiny BASIC implementations * **Palo Alto Tiny BASIC** (Dennis Allison) * **Li-Chen Wang’s Tiny BASIC** * **6800 Tiny BASIC** * **NASCOM Tiny BASIC** * **Apple I BASIC** (inspired by Tiny BASIC ideas) * **Micro-Soft 8080 BASIC** (larger, but influenced by Tiny BASIC work) Stellar Basic is based on the intermediate language specs for Pao Alto Tiny Basic, written by Dennis Allison in 1975. == Tutorial For a complete tutorial on BASIC, please see the [[SD-8516 User's Guide]]. === Example BASIC program 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''.) == Implementation Diary === Stack-based design Everything in PATB is stack-based. This is a core design principle. There are three stacks: # **Expression Stack** - Arithmetic evaluation ** "5 + 3 * 2" is "push 5", "push 3", "push 2", "multiply" (pop 2 values, push result), "add" (pop 2 values, push result). # **GOSUB Stack** - Subroutine calls ** "GOSUB 1000" -- push current line number, jump to 1000 ** "RETURN" -- pop line number, jump back # **FOR Stack** - Loop context ** "FOR I=1 TO 10" -- push (I, 10, 1) ** "NEXT I" -- peek stack, increment I, check if done, pop if finished === The Plan The plan was to implement the IL as a service library so it could be used by other languages later on too. * Phase 1: Variable management (3 functions: get, set, clear_all) * Expression stack (4 functions: push, pop, peek, clear) * I/O & String Helpers (ex. IO_GETNUM) * String comparison, number parsing (ex. STR_SKIP_SPACE) * Phase 2: Stack Operations * GOSUB/RETURN stack (3 functions) * FOR/NEXT stack (4 functions) * Phase 3: Program Line Management * Find line by number * Insert/delete lines * Navigate through program (first line, next line) * Program storage with line markers (opcode 251) * Phase 4: IL Interpreter Core; * Design IL bytecode table (~30-40 IL opcodes) * Command tokenizer (major hurdles to pass -- this was hard) * IL fetch/decode/execute loop * Expression evaluation using the stack * Control flow (GOTO, GOSUB, IF/THEN, FOR/NEXT) * Phase 5: BASIC Commands * PRINT, INPUT, LET * RUN, LIST, NEW, CLEAR * Integrate with term.ts to highlight a "Boot-to-basic" experience. * Phase 6: Testing & Polish * End-to-end BASIC program tests * Error handling and status messages * Bug fixes * Performance tuning 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. === Implementing GOTO 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. === Implementing BREAK 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 === Implementing INPUT 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. ==== One, add the keyword to the system. * in basic1.sda: ** Add keyword_input to the keyword list in basic1.sda ** Add the "Check INPUT" code, in this case after "check REM". I.E. before exec_line_error. ** Add the function call in the jump table (matching the new JZ @exec_line_input from above) * in basic2.sda: ** Add the basic_exec_input function (called from basic1.sda above). ** The purpose of this function is to read and process the INPUT command from basic. ** This function eventually calls the actual read-string function in INT 05h. * in INT 05h ** Add in an IO_INPUT which reads in the string and returns a pointer to it (BLX). Next cross your fingers and hope it works! === Implementing RAND() 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. === Implementing IF 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. == How PATB spec became Stellar BASIC 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! == Example TinyBASIC Program 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 == Stellar BASIC Roadmap 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. * March 2026 - GOSUB/RETURN - the stack handlers are ready I just need to add the keywords. * April 2026 - better formatting for PRINT such as TAB and PRINT without CR/LF * May 2026 - PEEK/POKE -- let BASIC programs read/write memory directly, classic retro feature * June 2026 - FOR/NEXT -- the FOR stack is ready, but the execution logic is broken. * July 2026 - String variables (A$) -- This is going to be somewhat harder. * August 2026 - Floating Point numbers (A#) -- or maybe deal with them as strings? * September 2026 - BEEP, SOUND, PLAY, etc. -- Still working on what sound system to settle on...