SectorLISP is an tiniest garbage
collected programming environment in the world. It's written as an i8086
BIOS program that's compatible with the original IBM PC. You can run
SectorLISP in Blink, by passing the -r
(REAL MODE) flag.
If you build Blink, then you can use the binaries provided for your convenience in this folder.
make -j8 o//blink
# easy mode
o//blink/blinkenlights -r third_party/sectorlisp/sectorlisp-friendly.bin
# professional mode
o//blink/blinkenlights -r third_party/sectorlisp/sectorlisp.bin
Then press c
to continue. The teletypewriter should become
highlighted, which means it's waiting for keystrokes.
You can then type in code like the following, which interns an atom:
(QUOTE HI)
The above code followed by the ENTER
key will display:
HI
For the purposes of readability in this tutorial, the above workflow will be described as follows:
>> (QUOTE HI)
HI
Once you've pressed c
(CONTINUE) the program TTY takes over control.
You can drop back into the debugger by pressing CTRL-C
. For example,
if you want to exit Blink entirely while using SectorLISP, you'd press
CTRL-C
(INTERRUPT) followed by q
(QUIT).
One thing you may have noticed, is that SectorLISP's interning algorithm
is slow. You can speed up or slow down execution at any time, by
pressing CTRL-C
(INTERRUPT) and, once in debugger mode, use CTRL-T
(TURBO) or ALT-T
(SLOWMO) as many times as desired. Then, execution
may be resumed by c
(CONTINUE) which hands control back over to the
SectorLISP program.
An alternative to pressing c
(CONTINUE) is to press s
(STEP). This
will allow you to go instruction by instruction. Be careful if you run
into an INT
instruction, since INT $0x16
for example, is your BIOS
keyboard service. In stepping mode, Blink will read one keystroke, and
then drop back into debugger control mode.
Here's an example of how you can build data structures:
> (CONS (QUOTE A) (QUOTE B))
(A∙B)
SectorLISP is purely expressional. It also doesn't have macros, which are what make the modern LISP syntax most people are used to possible. You instead need to write LISP the old fashioned way, as it is written in John McCarthy's original paper.
Here's an example of a recursive function which finds the first atom in
the tree ((A) B C)
, which is A
.
>> ((LAMBDA (FF X) (FF X))
(QUOTE (LAMBDA (X)
(COND ((ATOM X) X)
((QUOTE T) (FF (CAR X))))))
(QUOTE ((A) B C)))
A
The friendly version of SectorLISP makes it possible to break giant expressions like the above into smaller pieces. For example, the actual function from the S-expression above could be defined as follows:
(DEFINE FF .
(LAMBDA (X)
(COND ((ATOM X) X)
((QUOTE T) (FF (CAR X))))))
The friendly version also has the advantage of not exhibiting undefined behavior upon mistyped keystrokes!
We call real mode "real" because it puts your virtual machine in a mode that simulates non-virtualized memory ops. This adds a certain level of fun when programming, because it makes things so much simpler than long mode, which mandates that all memory operations be indirected through a 4-level radix trie.
The i8086 is still able to virtualize memory using segment registers:
%cs
(CODE SEGMENT)%ds
(DATA SEGMENT)%ss
(STACK SEGMENT)%es
(EXTRA SEGMENT)
BIOS programs are loaded to the address 0x7c00. What SectorLISP does is
it sets all the segments to the load address, which effectively
redefines NULL
to be equal to the base of the program image.