Roll A Lisp In C – Reading (2020)
swatson555.github.io
swatson555.github.io
Now I have been searching for an overview of the CL commands that make up that core which would be needed to implement CL (run the rest), but I cannot find any. Anyone here knows?
IIRC, none of the actual ANSI CL code is implemented in C - in fact, it would break one of the core design ideas of SBCL, which is "Sanely Bootstrappable" - SBCL can compile itself on any "complete enough" ANSI CL system - it doesn't even have to implement everything - then uses itself and its own standard library to compile itself again but into actual native code.
Out of memory, the C based runtime in SBCL has the garbage collector, low-level memory interfaces to OS (how to acquire memory, how to release memory, setting memory protection flags), some core FFI to OS which are called pretty deep from standard library (i/o, threads, processes), basic FFI supports (manipulating linkage tables, for example) setting CPU contexts, etc.
On the non-OS-specific side, there's core loading, which is a distant ancestor of Mach dynamic linker.
Some of it is C-side implementation of basic SBCL datatypes which allows both GC and runtime to interact with them safely, but usually the CL code does not call into those.
Some of the low-level manipulation is actually assembler.
For learning more specifically on SBCL, you can look at following
https://pvk.ca/Blog/2013/04/13/starting-to-hack-on-sbcl/
https://simonsafar.com/2020/sbcl/
And of course SBCL code and comments.
There are also some papers related to CMUCL (and before that, Spice Lisp) that talk about Python Compiler (the compiler used by CMU CL, SBCL, Scieneer CL)
I'm looking to write a really basic one in javascript except using plain arrays. No parsing or tokenizing for me.
A little later I used Norvig's Scheme implementation from chapters 22 and 23 of PAIP (https://norvig.github.io/paip-lisp/#/?id=paradigms-of-artifi...).
I liked Norvig's a little better. It starts with a simple interpreter and adds improvements step-by-step, winding up with an optimizing compiler that targets a bytecode VM.
That approach makes a lot of implementation details manifest in a way that is easy to grasp. For example, I think I understood continuations much better after seeing Norvig's account of how to implement them.
This inlines the diffs between the original SICP and the new one that is implemented in Javascript too.
[0] https://github.com/kanaka/mal
[1] https://github.com/kanaka/mal/blob/master/process/guide.md
[Edit] Just wanted to reiterate that lexing/parsing Lisp is easy as per the MAL instructions. IIRC the things that I found hardest (in C#, as a C# newby) were understanding how to implement the closures required to support function definition, and then implementing Lisp's macro expansion.
https://okmij.org/ftp/tagless-final/
This embeds the target language as combinators in a host language, so you can construct and evaluate programs.
https://higherlogics.blogspot.com/search/label/tagless%20int...
The style of the construction is what matters most. If you're using JS then you're already giving up types, but the higher order abstract syntax is what lets you embed and play with language semantics.
evalExpression:
switch peekChar
( evalFunctionCall
0-9 parseNumber
" parseString
a-zA-Z parseAndGetVariable
evalFunctionCall
fn = evalExpression
arguments = evalExpression until )
fn(arguments)There are also the Lis.py articles which are incredibly good:
https://norvig.com/lispy2.html
You mentioned you want to write your lisp in javascript so you'll be getting quite a lot of functionality for free: memory allocation and garbage collection. That alone solves an enormous amount of problems. Just in case anyone reading is going to write in C, here's an excellent introduction to the topic:
https://journal.stuffwithstuff.com/2013/12/08/babys-first-ga...
Don't forget to spill the registers.