I'm writing a Kernel interpreter
Kernel is the Scheme variant by John Shutt that I've been blogging about.
The two and a half days, I've been adapting the Tinyscheme interpreter to run Kernel. Right now it doesn't compile. Some of the choices I'm making:
New eval functionality
The first thing I did was to write a new eval loop and support functions to make and evaluate vaus, which are basically Kernel's version of lambdas. Like in Tinyscheme, it's separated into parts, and in between the parts the interpreter does other stuff such as nested evals.
C functions instead of new opcodes
Rather than grossly extend the OP_ list, I've opted to add the capability for the interpreter to call a C function instead.
This is distinct from the old foreign function type. All these functions have the signature:
typedef pointer (*kernel_func)(scheme * sc, pointer args, pointer env);
They are suitable for use as operatives, so a lot of the base Kernel functionality can directly be C functions.
Initially I coded some of the stuff as new opcodes, because that's the way TS has always done things. But I was never too thrilled about that way of doing things.
To support this, I:
- changed the interpreter to include a field for the next function to call.
- changed the stack frame code to save and restore that field
- Added one opcode: OPKERNELCALL, which calls that function (or complains if it's NULL)
So right now both opcodes and C functions are supported and opcodes are primary.
New code for registering foreign functions
Since I have the new supported function type, I created a way of registering those functions. That is, knowing their C name and Kernel name (as a string), add them to a Kernel environment.
I wrote that facility for Tinyscheme in the first place, so it was pretty easily adapted. I corrected one thing I wish I'd done earlier and allowed this registering to apply to an arbitrary environment. Before, it always applied to the global environment (what Kernel calls the ground environment)
Added pseudo-object fields to interpreter
Tinyscheme creates some gotta-be-present objects as fields in the interpreter, such as #t, #f, and nil. Kernel has some new objects that I made similarly: #ignore and #inert
One thing I did differently: For some obscure historical reason, TS has both objects and pointers for those fields. It seems pointless; the pointer must always point at the same object, so one could just take the object's address. So for the new ones, I left out the pointer field.
Tinyscheme code really hasn't had a consistent indentation style etc. On request, I had added a style marking to the file local variables, which as "k&r" which seemed to nearly match the original style. But I like GNU style better, so I switched the file local variable to that.