September 25, 2018
By the time I got ZBasic I had been writing code in BASIC on my TRS-80 Model III for a few years. I don't know where the ZBasic cassette came from. I don't remember reading about it in 80 Micro magazine or begging my father for it. But I do remember loading the cassette, which I knew was a BASIC compiler, typing a simple BASIC program to draw some dots, and seeing the screen fill up faster than I thought was possible.
It didn't occur to me at the time that the ROM could have had a compiler instead of an interpreter. After all, they could fit a compiler in RAM and still leave room for your program, so perhaps a compiler would have fit in the 14K ROM. Did they try and fail, or did it not occur to them to try? It'd be tragic if thousands of programmers had to deal with a 10× slower computer simply because the architects of these home computers implemented interpreters out of inertia.
After my friend Brad Grantham wrote an Apple IIe emulator, the thought trickled into my head that I could implement an alternative history where BASIC programmers could actually write decent video games. I figured I'd try to see if a compiler might have fit into the 12K ROM of an Apple IIe.
The original ROM was written in assembly, but I wrote mine in C, using the cc65 compiler. The compiler generates fairly bloated code. This is partly because the Apple IIe's CPU, the MOS 6502, has a weak instruction set that isn't high-level language friendly, and partly because cc65 tries to be a proper C-compliant compiler, which means lots of promotion to 16-bit values when 8 bits might have been enough.
I ran out of room after implementing most of BASIC, having to leave out floating point and string support. Of course a real ROM would need these, and I don't know whether re-implementing the compiler in assembly would free up enough room for them. I'm okay leaving floating point out of my implementation because any program that used it would see a much smaller speed-up from compilation. Also, the original ROM BASIC didn't have floating point and people were able to write video games just fine. Strings, however, are a serious omission.
I tokenized exactly as AppleSoft BASIC did, so that LIST would give the same output. Their BASIC, unlike most others of the day, stripped all whitespace and inserted it back when listing. This saved some memory and execution time at the cost of generating ugly listings and confusing users with syntax errors when variables like RAT were defined. One odd detail is that < and = were different tokens, and since LIST inserted a space before and after every token, the expression X <= Y listed as X < = Y.
The most unexpected realization was that FOR loops, when compiled, are significantly slower than the equivalent loops written using IF and GOTO statements. That's because a GOTO always jumps to the same location, so it can be implemented in assembly with a JMP call. A NEXT, however, must check each time the stack of FOR statements to find the variable to increment and the line to jump to.
Here's a GIF of Brad's emulator with the original ROM interpreted AppleSoft BASIC computing a Mandelbrot set using integer math:
And here is that same program running on my ROM:
To run this yourself, drag the mandelbrot.bas file from the examples folder into the emulator, then type RUN.
The name (Apple IIa) comes from the Alice project that Brad and I have made so many projects for.
The source code is available on GitHub.