Honeywell B was a true compiler. There were lots of ways to implement B.
It’s also important to understand that on many early machines a subroutine call was a single machine word instruction so occupied just as much space as the address itself as data would.
Some machines also had instructions that were the equivalent of something akin to jump to the address in the machine word pointed to be register r and increment register r, so each “subroutine” actually was simply a piece of code jumped to which ended with another of those jumps.
You can actually do this on 8080/Z80 too if you are not using interrupts and you build your threadcode engine right. The instruction you need is “ret” which is basically JMP (SP+) and you simply make your operation list an array of addresses of the functions to call and point SP at the start.
Any actual virtual machine level subroutine consists of saving the old SP on a software stack, loading the new SP and going from there. As you mostly do rets and rarely do a software SP save/load its quicker.
My ROMBAT monitor actually uses this in small doses in order to run in 256 bytes and without RAM.
Incidentally he was correct. The Honeywell L66 and friends did indeed get a C compiler although some things were very strange. Having a 36bit word and a choice of char sizes at compile time was fun. In addition you either have 9 bit chars or you have a problem with sizeof(). Whilst 7 bit chars were supported it needed a bit of care. As I understand it all the Waterloo related system software remained in B however.
Pointers were also fun as it was a K&R compiler but char * and int * representations differed so missing a cast was weird.
One fascinating thing I’ve learned from this thread is that there was more than one B compiler!
I’d previously been under the impression that it was sort of a one-off stepping stone on the way to C, but here I’m reading about compilers for B on different systems.
(And each being slightly different again, I suspect).
I believe, historically there were three B compilers.
There was also an intermediary step in between B and C called NB, for new B. Maybe the development from B to C was more of a gradual thing, but at some point the updated language was different enough from the old B to be called new, and after still more hacking, C.
The Honeywell compiler was very well developed and acquired a lot of C bits by the time I met it (like a stdio), extended (better than C) switch statements and many other things.
It was part of the systems programming infrastructure for TSS and the like and as a 36bit word oriented machine the C compiler seems to have mostly been an afterthought as C programs became common.