mirror of
https://github.com/samsonjs/sectorlisp.git
synced 2026-03-25 09:05:48 +00:00
Remove old code and update documentation
This commit is contained in:
parent
cbb4ecc4d5
commit
4233210a86
14 changed files with 3755 additions and 702 deletions
1
LICENSE
1
LICENSE
|
|
@ -1,4 +1,5 @@
|
||||||
Copyright 2020 Justine Alexandra Roberts Tunney
|
Copyright 2020 Justine Alexandra Roberts Tunney
|
||||||
|
Copyright 2021 Alain Greppin
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for
|
Permission to use, copy, modify, and/or distribute this software for
|
||||||
any purpose with or without fee is hereby granted, provided that the
|
any purpose with or without fee is hereby granted, provided that the
|
||||||
|
|
|
||||||
60
Makefile
60
Makefile
|
|
@ -1,70 +1,28 @@
|
||||||
CFLAGS ?= -g
|
|
||||||
CFLAGS += -fno-pie
|
|
||||||
LDFLAGS += -no-pie # -s -static -N
|
|
||||||
|
|
||||||
REALFLAGS = \
|
|
||||||
-Os \
|
|
||||||
-D__REAL_MODE__ \
|
|
||||||
-wrapper ./realify.sh \
|
|
||||||
-ffixed-r8 \
|
|
||||||
-ffixed-r9 \
|
|
||||||
-ffixed-r10 \
|
|
||||||
-ffixed-r11 \
|
|
||||||
-ffixed-r12 \
|
|
||||||
-ffixed-r13 \
|
|
||||||
-ffixed-r14 \
|
|
||||||
-ffixed-r15 \
|
|
||||||
-mno-red-zone \
|
|
||||||
-fcall-used-rbx \
|
|
||||||
-fno-jump-tables \
|
|
||||||
-fno-shrink-wrap \
|
|
||||||
-fno-schedule-insns2 \
|
|
||||||
-flive-range-shrinkage \
|
|
||||||
-fno-omit-frame-pointer \
|
|
||||||
-momit-leaf-frame-pointer \
|
|
||||||
-mpreferred-stack-boundary=3 \
|
|
||||||
-fno-delete-null-pointer-checks
|
|
||||||
|
|
||||||
CLEANFILES = \
|
CLEANFILES = \
|
||||||
lisp \
|
lisp \
|
||||||
lisp.o \
|
lisp.o \
|
||||||
lisp.real.o \
|
bestline.o \
|
||||||
sectorlisp.o \
|
sectorlisp.o \
|
||||||
start.o \
|
|
||||||
lisp.bin \
|
|
||||||
sectorlisp.bin \
|
sectorlisp.bin \
|
||||||
lisp.bin.dbg \
|
|
||||||
sectorlisp.bin.dbg
|
sectorlisp.bin.dbg
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: lisp \
|
all: lisp \
|
||||||
lisp.bin \
|
|
||||||
lisp.bin.dbg \
|
|
||||||
sectorlisp.bin \
|
sectorlisp.bin \
|
||||||
sectorlisp.bin.dbg
|
sectorlisp.bin.dbg
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:; $(RM) $(CLEANFILES)
|
clean:; $(RM) lisp lisp.o bestline.o sectorlisp.o sectorlisp.bin sectorlisp.bin.dbg
|
||||||
|
|
||||||
lisp.bin.dbg: start.o lisp.real.o lisp.lds
|
lisp: lisp.o bestline.o
|
||||||
lisp: lisp.o
|
lisp.o: lisp.c bestline.h
|
||||||
|
bestline.o: bestline.c bestline.h
|
||||||
start.o: start.S Makefile
|
|
||||||
lisp.o: lisp.c lisp.h Makefile
|
|
||||||
lisp.real.o: lisp.c lisp.h Makefile
|
|
||||||
|
|
||||||
sectorlisp.o: sectorlisp.S
|
sectorlisp.o: sectorlisp.S
|
||||||
$(AS) -g -mtune=i386 -o $@ $<
|
$(AS) -g -mtune=i386 -o $@ $<
|
||||||
|
|
||||||
sectorlisp.bin.dbg: sectorlisp.o
|
sectorlisp.bin.dbg: sectorlisp.o
|
||||||
$(LD) -oformat:binary -Ttext=0x7600 -o $@ $<
|
$(LD) -oformat:binary -Ttext=0x7600 -o $@ $<
|
||||||
|
|
||||||
sectorlisp.bin: sectorlisp.bin.dbg
|
sectorlisp.bin: sectorlisp.bin.dbg
|
||||||
objcopy -SO binary sectorlisp.bin.dbg sectorlisp.bin
|
objcopy -S -O binary sectorlisp.bin.dbg sectorlisp.bin
|
||||||
|
|
||||||
%.real.o: %.c
|
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(REALFLAGS) -c -o $@ $<
|
|
||||||
|
|
||||||
%.bin.dbg:
|
|
||||||
$(LD) $(LDFLAGS) -static -o $@ $(patsubst %.lds,-T %.lds,$^)
|
|
||||||
|
|
||||||
%.bin: %.bin.dbg
|
|
||||||
objcopy -SO binary $< $@
|
|
||||||
|
|
|
||||||
80
README.md
80
README.md
|
|
@ -1,37 +1,71 @@
|
||||||
# sectorlisp
|
# sectorlisp
|
||||||
|
|
||||||
sectorlisp is an effort to bootstrap John McCarthy's meta-circular
|
sectorlisp is a 512-byte implementation of LISP that's able to bootstrap
|
||||||
evaluator on bare metal from a 512-byte boot sector.
|
John McCarthy's meta-circular evaluator on bare metal.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Motivations
|
## Overview
|
||||||
|
|
||||||
Much of the information about LISP online tends to focus on
|
LISP has been described as the [Maxwell's equations of
|
||||||
[wild macros](http://www.paulgraham.com/onlisp.html),
|
software](https://michaelnielsen.org/ddi/lisp-as-the-maxwells-equations-of-software/).
|
||||||
[JIT compilation](http://pixielang.org/), or its merits as
|
Yet there's been very little focus to date on reducing these equations
|
||||||
[a better XML](http://www.defmacro.org/ramblings/lisp.html)
|
to their simplest possible form. Even the [original LISP
|
||||||
as well as [a better JSON](https://stopa.io/post/265). However
|
paper](https://people.cs.umass.edu/~emery/classes/cmpsci691st/readings/PL/LISP.pdf)
|
||||||
there's been comparatively little focus on the
|
from the 1960's defines LISP with nonessential elements, e.g. `LABEL`.
|
||||||
[primary materials](https://people.cs.umass.edu/~emery/classes/cmpsci691st/readings/PL/LISP.pdf)
|
|
||||||
from the 1950's which emphasize the radically simple nature of
|
This project aims to solve that by doing three things:
|
||||||
LISP, as best evidenced by the meta-circular evaluator above.
|
|
||||||
|
1. We provide a LISP implementation that's written in LISP, as a single
|
||||||
|
pure expression, using only the essential functions of the language.
|
||||||
|
See [lisp.lisp](lisp.lisp). It's the same meta-circular evaluator in
|
||||||
|
John McCarthy's paper from the 1960's, except with its bugs fixed,
|
||||||
|
dependencies included, and syntactic sugar removed.
|
||||||
|
|
||||||
|
2. We provide a readable portable C reference implementation to show how
|
||||||
|
the meta-circular evaluator can be natively bootstrapped on POSIX
|
||||||
|
conforming platforms, with a pleasant readline-like interface. See
|
||||||
|
[lisp.c](lisp.c).
|
||||||
|
|
||||||
|
2. We provide a 512-byte i8086 implementation of LISP that boots from
|
||||||
|
BIOS on personal computers. See [sectorlisp.S](sectorlisp.S). To the
|
||||||
|
best of our knowledge, this is the tiniest true LISP implementation
|
||||||
|
to date.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img alt="Binary Footprint Comparison"
|
<img alt="Binary Footprint Comparison" src="bin/footprint.png">
|
||||||
width="750" height="348" src="bin/footprint.png">
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
This project aims to promote the radical simplicity of the essential
|
## Getting Started
|
||||||
elements of LISP's original design, by building the tiniest LISP machine
|
|
||||||
possible. With a binary footprint less than one kilobyte, that's capable
|
|
||||||
of running natively without dependencies on modern PCs, sectorlisp might
|
|
||||||
be the tiniest self-hosting LISP interpreter to date.
|
|
||||||
|
|
||||||
We're still far off however from reaching our goal, which is to have
|
See [lisp.lisp](lisp.lisp) for code examples that you can copy and paste
|
||||||
sectorlisp be small enough to fit in the master boot record of a floppy
|
into your LISP REPL.
|
||||||
disk, like [sectorforth](https://github.com/cesarblum/sectorforth). If
|
|
||||||
you can help this project reach its goal, please send us a pull request!
|
You can run the C implementation as follows:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ make
|
||||||
|
$ ./lisp
|
||||||
|
```
|
||||||
|
|
||||||
|
After running `make` you should see a `sectorlisp.bin` file, which is a
|
||||||
|
master boot record you can put on a flopy disk and boot from BIOS. If
|
||||||
|
you would prefer to run it in an emulator, we recommend using
|
||||||
|
[Das Blinkenlights](https://justine.lol/blinkenlights/).
|
||||||
|
|
||||||
|
```sh
|
||||||
|
curl --compressed https://justine.lol/blinkenlights/blinkenlights-latest.com >blinkenlights.com
|
||||||
|
chmod +x blinkenlights.com
|
||||||
|
./blinkenlights.com -rt sectorlisp.bin
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively you may use QEMU as follows:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
qemu-system-i386 -nographic -fda sectorlisp.bin
|
||||||
|
```
|
||||||
|
|
||||||
|
Further information may be found on [our wiki](https://github.com/jart/sectorlisp/wiki).
|
||||||
|
|
||||||
## Demo
|
## Demo
|
||||||
|
|
||||||
|
|
|
||||||
3481
bestline.c
Normal file
3481
bestline.c
Normal file
File diff suppressed because it is too large
Load diff
33
bestline.h
Normal file
33
bestline.h
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef struct bestlineCompletions {
|
||||||
|
unsigned long len;
|
||||||
|
char **cvec;
|
||||||
|
} bestlineCompletions;
|
||||||
|
|
||||||
|
typedef void(bestlineCompletionCallback)(const char *, bestlineCompletions *);
|
||||||
|
typedef char *(bestlineHintsCallback)(const char *, const char **,
|
||||||
|
const char **);
|
||||||
|
typedef void(bestlineFreeHintsCallback)(void *);
|
||||||
|
|
||||||
|
void bestlineSetCompletionCallback(bestlineCompletionCallback *);
|
||||||
|
void bestlineSetHintsCallback(bestlineHintsCallback *);
|
||||||
|
void bestlineSetFreeHintsCallback(bestlineFreeHintsCallback *);
|
||||||
|
void bestlineAddCompletion(bestlineCompletions *, const char *);
|
||||||
|
|
||||||
|
char *bestline(const char *);
|
||||||
|
char *bestlineRaw(const char *, int, int);
|
||||||
|
char *bestlineWithHistory(const char *, const char *);
|
||||||
|
int bestlineHistoryAdd(const char *);
|
||||||
|
int bestlineHistorySave(const char *);
|
||||||
|
int bestlineHistoryLoad(const char *);
|
||||||
|
void bestlineFreeCompletions(bestlineCompletions *);
|
||||||
|
void bestlineHistoryFree(void);
|
||||||
|
void bestlineClearScreen(int);
|
||||||
|
void bestlineMaskModeEnable(void);
|
||||||
|
void bestlineMaskModeDisable(void);
|
||||||
|
void bestlineDisableRawMode(void);
|
||||||
|
void bestlineFree(void *);
|
||||||
|
unsigned bestlineLowercase(unsigned);
|
||||||
|
unsigned bestlineUppercase(unsigned);
|
||||||
|
void bestlineSetXlatCallback(unsigned(*)(unsigned));
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 12 KiB |
Binary file not shown.
335
lisp.c
335
lisp.c
|
|
@ -16,110 +16,109 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "lisp.h"
|
#include "bestline.h"
|
||||||
|
|
||||||
#define RETRO 1 // auto capitalize input
|
#ifndef __COSMOPOLITAN__
|
||||||
#define DELETE 1 // allow backspace to rub out symbol
|
#include <ctype.h>
|
||||||
#define QUOTES 1 // allow 'X shorthand (QUOTE X)
|
#include <stdlib.h>
|
||||||
#define PROMPT 1 // show repl prompt
|
#include <string.h>
|
||||||
#define WORD short
|
#include <unistd.h>
|
||||||
#define WORDS 8192
|
#endif
|
||||||
|
|
||||||
|
#define QUOTES 1 /* allow 'X shorthand for (QUOTE X) */
|
||||||
|
#define FUNDEF 1 /* be friendly w/undefined behavior */
|
||||||
|
#define TRACE 0 /* prints Eval() arguments / result */
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
│ The LISP Challenge § LISP Machine ─╬─│┼
|
│ The LISP Challenge § LISP Machine ─╬─│┼
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
|
|
||||||
#define ATOM 1
|
#define ATOM 0
|
||||||
#define CONS 0
|
#define CONS 1
|
||||||
|
|
||||||
#define NIL (ATOM | 0)
|
#define ISATOM(x) (~(x)&1)
|
||||||
#define UNDEFINED (ATOM | 8)
|
#define VALUE(x) ((x)>>1)
|
||||||
#define ATOM_T (ATOM | 30)
|
#define OBJECT(t,v) ((v)<<1|(t))
|
||||||
#define ATOM_QUOTE (ATOM | 34)
|
|
||||||
#define ATOM_COND (ATOM | 46)
|
|
||||||
#define ATOM_ATOM (ATOM | 56)
|
|
||||||
#define ATOM_CAR (ATOM | 66)
|
|
||||||
#define ATOM_CDR (ATOM | 74)
|
|
||||||
#define ATOM_CONS (ATOM | 82)
|
|
||||||
#define ATOM_EQ (ATOM | 92)
|
|
||||||
#define ATOM_LAMBDA (ATOM | 98)
|
|
||||||
|
|
||||||
#define VALUE(x) ((x) >> 1)
|
#define NIL OBJECT(ATOM,0)
|
||||||
|
#define ATOM_T OBJECT(ATOM,4)
|
||||||
|
#define ATOM_QUOTE OBJECT(ATOM,6)
|
||||||
|
#define ATOM_COND OBJECT(ATOM,12)
|
||||||
|
#define ATOM_ATOM OBJECT(ATOM,17)
|
||||||
|
#define ATOM_CAR OBJECT(ATOM,22)
|
||||||
|
#define ATOM_CDR OBJECT(ATOM,26)
|
||||||
|
#define ATOM_CONS OBJECT(ATOM,30)
|
||||||
|
#define ATOM_EQ OBJECT(ATOM,35)
|
||||||
|
#define ATOM_LAMBDA OBJECT(ATOM,38)
|
||||||
|
#define UNDEFINED OBJECT(ATOM,45)
|
||||||
|
|
||||||
struct Lisp {
|
struct Lisp {
|
||||||
WORD mem[WORDS];
|
int mem[8192];
|
||||||
unsigned char syntax[256];
|
unsigned char syntax[256];
|
||||||
WORD look;
|
int look;
|
||||||
WORD globals;
|
int globals;
|
||||||
WORD index;
|
int index;
|
||||||
char token[128];
|
char token[128];
|
||||||
char str[WORDS];
|
char str[8192];
|
||||||
};
|
};
|
||||||
|
|
||||||
_Static_assert(sizeof(struct Lisp) <= 0x7c00 - 0x600,
|
static const char kSymbols[] =
|
||||||
"LISP Machine too large for real mode");
|
"NIL\0"
|
||||||
|
"T\0"
|
||||||
_Alignas(char) const char kSymbols[] = "NIL\0"
|
"QUOTE\0"
|
||||||
"*UNDEFINED\0"
|
"COND\0"
|
||||||
"T\0"
|
"ATOM\0"
|
||||||
"QUOTE\0"
|
"CAR\0"
|
||||||
"COND\0"
|
"CDR\0"
|
||||||
"ATOM\0"
|
"CONS\0"
|
||||||
"CAR\0"
|
"EQ\0"
|
||||||
"CDR\0"
|
"LAMBDA\0"
|
||||||
"CONS\0"
|
#if FUNDEF
|
||||||
"EQ\0"
|
"*UNDEFINED"
|
||||||
"LAMBDA";
|
|
||||||
|
|
||||||
#ifdef __REAL_MODE__
|
|
||||||
static struct Lisp *const q;
|
|
||||||
#else
|
|
||||||
static struct Lisp q[1];
|
|
||||||
#endif
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
static void Print(long);
|
static struct Lisp q[1];
|
||||||
static WORD GetList(void);
|
|
||||||
static WORD GetObject(void);
|
static void Print(int);
|
||||||
static void PrintObject(long);
|
static int GetList(void);
|
||||||
static WORD Eval(WORD, WORD);
|
static int GetObject(void);
|
||||||
|
static void PrintObject(int);
|
||||||
|
static int Eval(int, int);
|
||||||
|
|
||||||
static void SetupSyntax(void) {
|
static void SetupSyntax(void) {
|
||||||
unsigned char *syntax = q->syntax;
|
q->syntax[' '] = ' ';
|
||||||
asm("" : "+bSD"(syntax));
|
q->syntax['\r'] = ' ';
|
||||||
syntax[' '] = ' ';
|
q->syntax['\n'] = ' ';
|
||||||
syntax['\r'] = ' ';
|
q->syntax['('] = '(';
|
||||||
syntax['\n'] = ' ';
|
q->syntax[')'] = ')';
|
||||||
syntax['('] = '(';
|
q->syntax['.'] = '.';
|
||||||
syntax[')'] = ')';
|
q->syntax['\''] = '\'';
|
||||||
syntax['.'] = '.';
|
|
||||||
#if QUOTES
|
|
||||||
syntax['\''] = '\'';
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetupBuiltins(void) {
|
static void SetupBuiltins(void) {
|
||||||
CopyMemory(q->str, kSymbols, sizeof(kSymbols));
|
memmove(q->str, kSymbols, sizeof(kSymbols));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline WORD Car(long x) {
|
static inline int Car(int x) {
|
||||||
return PEEK_ARRAY(q, mem, VALUE(x), 0);
|
return q->mem[VALUE(x) + 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline WORD Cdr(long x) {
|
static inline int Cdr(int x) {
|
||||||
return PEEK_ARRAY(q, mem, VALUE(x), 1);
|
return q->mem[VALUE(x) + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD Set(long i, long k, long v) {
|
static int Set(int i, int k, int v) {
|
||||||
POKE_ARRAY(q, mem, VALUE(i), 0, k);
|
q->mem[VALUE(i) + 0] = k;
|
||||||
POKE_ARRAY(q, mem, VALUE(i), 1, v);
|
q->mem[VALUE(i) + 1] = v;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD Cons(WORD car, WORD cdr) {
|
static int Cons(int car, int cdr) {
|
||||||
int i, cell;
|
int i, cell;
|
||||||
i = q->index;
|
i = q->index;
|
||||||
POKE_ARRAY(q, mem, i, 0, car);
|
q->mem[i + 0] = car;
|
||||||
POKE_ARRAY(q, mem, i, 1, cdr);
|
q->mem[i + 1] = cdr;
|
||||||
q->index = i + 2;
|
q->index = i + 2;
|
||||||
cell = OBJECT(CONS, i);
|
cell = OBJECT(CONS, i);
|
||||||
return cell;
|
return cell;
|
||||||
|
|
@ -128,120 +127,116 @@ static WORD Cons(WORD car, WORD cdr) {
|
||||||
static char *StpCpy(char *d, char *s) {
|
static char *StpCpy(char *d, char *s) {
|
||||||
char c;
|
char c;
|
||||||
do {
|
do {
|
||||||
c = LODS(s); // a.k.a. c = *s++
|
c = *s++;
|
||||||
STOS(d, c); // a.k.a. *d++ = c
|
*d++ = c;
|
||||||
} while (c);
|
} while (c);
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD Intern(char *s) {
|
static int Intern(char *s) {
|
||||||
int j, cx;
|
int j, cx;
|
||||||
char c, *z, *t;
|
char c, *z, *t;
|
||||||
z = q->str;
|
z = q->str;
|
||||||
c = LODS(z);
|
c = *z++;
|
||||||
while (c) {
|
while (c) {
|
||||||
for (j = 0;; ++j) {
|
for (j = 0;; ++j) {
|
||||||
if (c != PEEK(s, j, 0)) {
|
if (c != s[j]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!c) {
|
if (!c) {
|
||||||
return OBJECT(ATOM, z - q->str - j - 1);
|
return OBJECT(ATOM, z - q->str - j - 1);
|
||||||
}
|
}
|
||||||
c = LODS(z);
|
c = *z++;
|
||||||
}
|
}
|
||||||
while (c) c = LODS(z);
|
while (c) c = *z++;
|
||||||
c = LODS(z);
|
c = *z++;
|
||||||
}
|
}
|
||||||
--z;
|
--z;
|
||||||
StpCpy(z, s);
|
StpCpy(z, s);
|
||||||
return OBJECT(ATOM, SUB((long)z, q->str));
|
return OBJECT(ATOM, z - q->str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char XlatSyntax(unsigned char b) {
|
static void PrintChar(unsigned char b) {
|
||||||
return PEEK_ARRAY(q, syntax, b, 0);
|
if (write(1, &b, 1) == -1) exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintString(char *s) {
|
static void PrintString(char *s) {
|
||||||
char c;
|
char c;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (!(c = PEEK(s, 0, 0))) break;
|
if (!(c = s[0])) break;
|
||||||
PrintChar(c);
|
PrintChar(c);
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int GetChar(void) {
|
static int GetChar(void) {
|
||||||
int c;
|
unsigned char b;
|
||||||
c = ReadChar();
|
static char *l, *p;
|
||||||
#if RETRO
|
if (l || (l = p = bestlineWithHistory("* ", "sectorlisp"))) {
|
||||||
if (c >= 'a') {
|
if (*p) {
|
||||||
CompilerBarrier();
|
b = *p++;
|
||||||
if (c <= 'z') c -= 'a' - 'A';
|
} else {
|
||||||
|
free(l);
|
||||||
|
l = p = 0;
|
||||||
|
b = '\n';
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
} else {
|
||||||
|
PrintChar('\n');
|
||||||
|
exit(0);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#if DELETE
|
|
||||||
if (c == '\b') return c;
|
|
||||||
#endif
|
|
||||||
PrintChar(c);
|
|
||||||
if (c == '\r') PrintChar('\n');
|
|
||||||
return c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GetToken(void) {
|
static void GetToken(void) {
|
||||||
char *t;
|
char *t;
|
||||||
unsigned char b, x;
|
int b, x;
|
||||||
b = q->look;
|
b = q->look;
|
||||||
t = q->token;
|
t = q->token;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
x = XlatSyntax(b);
|
x = q->syntax[b];
|
||||||
if (x != ' ') break;
|
if (x != ' ') break;
|
||||||
b = GetChar();
|
b = GetChar();
|
||||||
}
|
}
|
||||||
if (x) {
|
if (x) {
|
||||||
STOS(t, b);
|
*t++ = b;
|
||||||
b = GetChar();
|
b = GetChar();
|
||||||
} else {
|
} else {
|
||||||
while (b && !x) {
|
while (b && !x) {
|
||||||
if (!DELETE || b != '\b') {
|
*t++ = b;
|
||||||
STOS(t, b);
|
|
||||||
} else if (t > q->token) {
|
|
||||||
PrintString("\b \b");
|
|
||||||
if (t > q->token) --t;
|
|
||||||
}
|
|
||||||
b = GetChar();
|
b = GetChar();
|
||||||
x = XlatSyntax(b);
|
x = q->syntax[b];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
STOS(t, 0);
|
*t++ = 0;
|
||||||
q->look = b;
|
q->look = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD ConsumeObject(void) {
|
static int ConsumeObject(void) {
|
||||||
GetToken();
|
GetToken();
|
||||||
return GetObject();
|
return GetObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD Cadr(long x) {
|
static int Cadr(int x) {
|
||||||
return Car(Cdr(x)); // ((A B C D) (E F G) H I) → (E F G)
|
return Car(Cdr(x)); /* ((A B C D) (E F G) H I) → (E F G) */
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD List(long x, long y) {
|
static int List(int x, int y) {
|
||||||
return Cons(x, Cons(y, NIL));
|
return Cons(x, Cons(y, NIL));
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD Quote(long x) {
|
static int Quote(int x) {
|
||||||
return List(ATOM_QUOTE, x);
|
return List(ATOM_QUOTE, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD GetQuote(void) {
|
static int GetQuote(void) {
|
||||||
return Quote(ConsumeObject());
|
return Quote(ConsumeObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD AddList(WORD x) {
|
static int AddList(int x) {
|
||||||
return Cons(x, GetList());
|
return Cons(x, GetList());
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD GetList(void) {
|
static int GetList(void) {
|
||||||
GetToken();
|
GetToken();
|
||||||
switch (*q->token & 0xFF) {
|
switch (*q->token & 0xFF) {
|
||||||
default:
|
default:
|
||||||
|
|
@ -257,7 +252,7 @@ static WORD GetList(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD GetObject(void) {
|
static int GetObject(void) {
|
||||||
switch (*q->token & 0xFF) {
|
switch (*q->token & 0xFF) {
|
||||||
default:
|
default:
|
||||||
return Intern(q->token);
|
return Intern(q->token);
|
||||||
|
|
@ -270,21 +265,21 @@ static WORD GetObject(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD ReadObject(void) {
|
static int ReadObject(void) {
|
||||||
q->look = GetChar();
|
q->look = GetChar();
|
||||||
GetToken();
|
GetToken();
|
||||||
return GetObject();
|
return GetObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD Read(void) {
|
static int Read(void) {
|
||||||
return ReadObject();
|
return ReadObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintAtom(long x) {
|
static void PrintAtom(int x) {
|
||||||
PrintString(q->str + VALUE(x));
|
PrintString(q->str + VALUE(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintList(long x) {
|
static void PrintList(int x) {
|
||||||
#if QUOTES
|
#if QUOTES
|
||||||
if (Car(x) == ATOM_QUOTE) {
|
if (Car(x) == ATOM_QUOTE) {
|
||||||
PrintChar('\'');
|
PrintChar('\'');
|
||||||
|
|
@ -307,7 +302,7 @@ static void PrintList(long x) {
|
||||||
PrintChar(')');
|
PrintChar(')');
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintObject(long x) {
|
static void PrintObject(int x) {
|
||||||
if (ISATOM(x)) {
|
if (ISATOM(x)) {
|
||||||
PrintAtom(x);
|
PrintAtom(x);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -315,7 +310,7 @@ static void PrintObject(long x) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Print(long i) {
|
static void Print(int i) {
|
||||||
PrintObject(i);
|
PrintObject(i);
|
||||||
PrintString("\r\n");
|
PrintString("\r\n");
|
||||||
}
|
}
|
||||||
|
|
@ -324,55 +319,58 @@ static void Print(long i) {
|
||||||
│ The LISP Challenge § Bootstrap John McCarthy's Metacircular Evaluator ─╬─│┼
|
│ The LISP Challenge § Bootstrap John McCarthy's Metacircular Evaluator ─╬─│┼
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
|
|
||||||
static WORD Caar(long x) {
|
static int Caar(int x) {
|
||||||
return Car(Car(x)); // ((A B C D) (E F G) H I) → A
|
return Car(Car(x)); /* ((A B C D) (E F G) H I) → A */
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD Cdar(long x) {
|
static int Cdar(int x) {
|
||||||
return Cdr(Car(x)); // ((A B C D) (E F G) H I) → (B C D)
|
return Cdr(Car(x)); /* ((A B C D) (E F G) H I) → (B C D) */
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD Cadar(long x) {
|
static int Cadar(int x) {
|
||||||
return Cadr(Car(x)); // ((A B C D) (E F G) H I) → B
|
return Cadr(Car(x)); /* ((A B C D) (E F G) H I) → B */
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD Caddr(long x) {
|
static int Caddr(int x) {
|
||||||
return Cadr(Cdr(x)); // ((A B C D) (E F G) H I) → H
|
return Cadr(Cdr(x)); /* ((A B C D) (E F G) H I) → H */
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD Caddar(long x) {
|
static int Caddar(int x) {
|
||||||
return Caddr(Car(x)); // ((A B C D) (E F G) H I) → C
|
return Caddr(Car(x)); /* ((A B C D) (E F G) H I) → C */
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD Evcon(long c, long a) {
|
static int Evcon(int c, int a) {
|
||||||
return Eval(Caar(c), a) != NIL ? Eval(Cadar(c), a) : Evcon(Cdr(c), a);
|
return Eval(Caar(c), a) != NIL ? Eval(Cadar(c), a) : Evcon(Cdr(c), a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD Assoc(long x, long a) {
|
static int Assoc(int x, int a) {
|
||||||
return a != NIL ? Caar(a) == x ? Cdar(a) : Assoc(x, Cdr(a)) : NIL;
|
return a ? Caar(a) == x ? Cdar(a) : Assoc(x, Cdr(a)) : NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD Pairlis(WORD x, WORD y, WORD a) {
|
static int Pairlis(int x, int y, int a) { /* it's zip() basically */
|
||||||
if (x == NIL)
|
int di, si;
|
||||||
return a;
|
if (!x) return a;
|
||||||
WORD di = Cons(Car(x), Car(y));
|
di = Cons(Car(x), Car(y));
|
||||||
WORD si = Pairlis(Cdr(x), Cdr(y), a);
|
si = Pairlis(Cdr(x), Cdr(y), a);
|
||||||
return Cons(di, si); // Tail-Modulo-Cons
|
return Cons(di, si); /* Tail-Modulo-Cons */
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD Evlis(WORD m, WORD a) {
|
static int Evlis(int m, int a) {
|
||||||
if (m == NIL)
|
int di, si;
|
||||||
return NIL;
|
if (!m) return NIL;
|
||||||
WORD di = Eval(Car(m), a);
|
di = Eval(Car(m), a);
|
||||||
WORD si = Evlis(Cdr(m), a);
|
si = Evlis(Cdr(m), a);
|
||||||
return Cons(di, si);
|
return Cons(di, si);
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD Apply(WORD fn, WORD x, WORD a) {
|
static int Apply(int fn, int x, int a) {
|
||||||
|
int t1, si, ax;
|
||||||
if (ISATOM(fn)) {
|
if (ISATOM(fn)) {
|
||||||
switch (fn) {
|
switch (fn) {
|
||||||
|
#if FUNDEF
|
||||||
case NIL:
|
case NIL:
|
||||||
return UNDEFINED;
|
return UNDEFINED;
|
||||||
|
#endif
|
||||||
case ATOM_CAR:
|
case ATOM_CAR:
|
||||||
return Caar(x);
|
return Caar(x);
|
||||||
case ATOM_CDR:
|
case ATOM_CDR:
|
||||||
|
|
@ -387,22 +385,20 @@ static WORD Apply(WORD fn, WORD x, WORD a) {
|
||||||
return Apply(Eval(fn, a), x, a);
|
return Apply(Eval(fn, a), x, a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Car(fn) == ATOM_LAMBDA) {
|
if (Car(fn) == ATOM_LAMBDA) {
|
||||||
WORD t1 = Cdr(fn);
|
t1 = Cdr(fn);
|
||||||
WORD si = Pairlis(Car(t1), x, a);
|
si = Pairlis(Car(t1), x, a);
|
||||||
WORD ax = Cadr(t1);
|
ax = Cadr(t1);
|
||||||
return Eval(ax, si);
|
return Eval(ax, si);
|
||||||
}
|
}
|
||||||
|
|
||||||
return UNDEFINED;
|
return UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static WORD Eval(WORD e, WORD a) {
|
static int Evaluate(int e, int a) {
|
||||||
|
int ax;
|
||||||
if (ISATOM(e))
|
if (ISATOM(e))
|
||||||
return Assoc(e, a);
|
return Assoc(e, a);
|
||||||
|
ax = Car(e);
|
||||||
WORD ax = Car(e);
|
|
||||||
if (ISATOM(ax)) {
|
if (ISATOM(ax)) {
|
||||||
if (ax == ATOM_QUOTE)
|
if (ax == ATOM_QUOTE)
|
||||||
return Cadr(e);
|
return Cadr(e);
|
||||||
|
|
@ -411,31 +407,42 @@ static WORD Eval(WORD e, WORD a) {
|
||||||
if (ax == ATOM_LAMBDA)
|
if (ax == ATOM_LAMBDA)
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Apply(ax, Evlis(Cdr(e), a), a);
|
return Apply(ax, Evlis(Cdr(e), a), a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int Eval(int e, int a) {
|
||||||
|
int ax;
|
||||||
|
#if TRACE
|
||||||
|
PrintString("> ");
|
||||||
|
PrintObject(e);
|
||||||
|
PrintString("\r\n ");
|
||||||
|
PrintObject(a);
|
||||||
|
PrintString("\r\n");
|
||||||
|
#endif
|
||||||
|
ax = Evaluate(e, a);
|
||||||
|
#if TRACE
|
||||||
|
PrintString("< ");
|
||||||
|
PrintObject(ax);
|
||||||
|
PrintString("\r\n");
|
||||||
|
#endif
|
||||||
|
return ax;
|
||||||
|
}
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
│ The LISP Challenge § User Interface ─╬─│┼
|
│ The LISP Challenge § User Interface ─╬─│┼
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
|
|
||||||
void Repl(void) {
|
void Repl(void) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
#if PROMPT
|
|
||||||
PrintString("* ");
|
|
||||||
#endif
|
|
||||||
Print(Eval(Read(), q->globals));
|
Print(Eval(Read(), q->globals));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
RawMode();
|
|
||||||
SetupSyntax();
|
SetupSyntax();
|
||||||
SetupBuiltins();
|
SetupBuiltins();
|
||||||
#if PROMPT
|
bestlineSetXlatCallback(bestlineUppercase);
|
||||||
PrintString("THE LISP CHALLENGE V1\r\n"
|
PrintString("THE LISP CHALLENGE V1\r\n"
|
||||||
"VISIT GITHUB.COM/JART\r\n");
|
"VISIT GITHUB.COM/JART\r\n");
|
||||||
#endif
|
|
||||||
Repl();
|
Repl();
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
180
lisp.h
180
lisp.h
|
|
@ -1,180 +0,0 @@
|
||||||
#ifndef SECTORLISP_H_
|
|
||||||
#define SECTORLISP_H_
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
|
||||||
│ The LISP Challenge § Richard Stallman Math 55 Systems Integration Code ─╬─│┼
|
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
|
||||||
|
|
||||||
#define CompilerBarrier() asm volatile("" ::: "memory")
|
|
||||||
|
|
||||||
#define ISATOM(x) /* a.k.a. !(x&1) */ \
|
|
||||||
({ \
|
|
||||||
_Bool IsAtom; \
|
|
||||||
asm("test%z1\t$1,%1" : "=@ccnz"(IsAtom) : "Qm"((char)x)); \
|
|
||||||
IsAtom; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define OBJECT(t, v) /* a.k.a. v<<1|t */ \
|
|
||||||
({ \
|
|
||||||
__typeof(v) Val = (v); \
|
|
||||||
asm("shl\t%0" : "+r"(Val)); \
|
|
||||||
Val | (t); \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define SUB(x, y) /* a.k.a. x-y */ \
|
|
||||||
({ \
|
|
||||||
__typeof(x) Reg = (x); \
|
|
||||||
asm("sub\t%1,%0" : "+rm"(Reg) : "g"(y)); \
|
|
||||||
Reg; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define STOS(di, c) asm("stos%z1" : "+D"(di), "=m"(*(di)) : "a"(c))
|
|
||||||
#define LODS(si) \
|
|
||||||
({ \
|
|
||||||
typeof(*(si)) c; \
|
|
||||||
asm("lods%z2" : "+S"(si), "=a"(c) : "m"(*(si))); \
|
|
||||||
c; \
|
|
||||||
})
|
|
||||||
|
|
||||||
static inline void *SetMemory(void *di, int al, unsigned long cx) {
|
|
||||||
asm("rep stosb"
|
|
||||||
: "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di)
|
|
||||||
: "0"(di), "1"(cx), "a"(al));
|
|
||||||
return di;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void *CopyMemory(void *di, const void *si, unsigned long cx) {
|
|
||||||
asm("rep movsb"
|
|
||||||
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
|
|
||||||
: "0"(di), "1"(si), "2"(cx));
|
|
||||||
return di;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RawMode(void) {
|
|
||||||
#ifndef __REAL_MODE__
|
|
||||||
struct termios t;
|
|
||||||
if (ioctl(1, TCGETS, &t) != -1) {
|
|
||||||
t.c_cc[VMIN] = 1;
|
|
||||||
t.c_cc[VTIME] = 1;
|
|
||||||
t.c_iflag &= ~(INPCK | ISTRIP | PARMRK | INLCR | IGNCR | ICRNL | IXON);
|
|
||||||
t.c_lflag &= ~(IEXTEN | ICANON | ECHO | ECHONL);
|
|
||||||
t.c_cflag &= ~(CSIZE | PARENB);
|
|
||||||
t.c_oflag &= ~OPOST;
|
|
||||||
t.c_cflag |= CS8;
|
|
||||||
t.c_iflag |= IUTF8;
|
|
||||||
ioctl(1, TCSETS, &t);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((__noinline__)) static void PrintChar(long c) {
|
|
||||||
#ifdef __REAL_MODE__
|
|
||||||
asm volatile("mov\t$0x0E,%%ah\n\t"
|
|
||||||
"int\t$0x10"
|
|
||||||
: /* no outputs */
|
|
||||||
: "a"(c), "b"(7)
|
|
||||||
: "memory");
|
|
||||||
#else
|
|
||||||
static short buf;
|
|
||||||
int rc;
|
|
||||||
buf = c;
|
|
||||||
write(1, &buf, 1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ReadChar(void) {
|
|
||||||
int c;
|
|
||||||
#ifdef __REAL_MODE__
|
|
||||||
asm volatile("int\t$0x16" : "=a"(c) : "0"(0) : "memory");
|
|
||||||
c &= 0xff;
|
|
||||||
#else
|
|
||||||
static int buf;
|
|
||||||
read(0, &buf, 1);
|
|
||||||
c = buf;
|
|
||||||
#endif
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PEEK_(REG, BASE, INDEX, DISP) \
|
|
||||||
({ \
|
|
||||||
__typeof(*(BASE)) Reg; \
|
|
||||||
if (__builtin_constant_p(INDEX) && !(INDEX)) { \
|
|
||||||
asm("mov\t%c2(%1),%0" \
|
|
||||||
: REG(Reg) \
|
|
||||||
: "bDS"(BASE), "i"((DISP) * sizeof(*(BASE))), \
|
|
||||||
"m"(BASE[(INDEX) + (DISP)])); \
|
|
||||||
} else { \
|
|
||||||
asm("mov\t%c3(%1,%2),%0" \
|
|
||||||
: REG(Reg) \
|
|
||||||
: "b"(BASE), "DS"((long)(INDEX) * sizeof(*(BASE))), \
|
|
||||||
"i"((DISP) * sizeof(*(BASE))), "m"(BASE[(INDEX) + (DISP)])); \
|
|
||||||
} \
|
|
||||||
Reg; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define PEEK(BASE, INDEX, DISP) /* a.k.a. b[i] */ \
|
|
||||||
(sizeof(*(BASE)) == 1 ? PEEK_("=Q", BASE, INDEX, DISP) \
|
|
||||||
: PEEK_("=r", BASE, INDEX, DISP))
|
|
||||||
|
|
||||||
#define PEEK_ARRAY_(REG, OBJECT, MEMBER, INDEX, DISP) \
|
|
||||||
({ \
|
|
||||||
__typeof(*(OBJECT->MEMBER)) Reg; \
|
|
||||||
if (!(OBJECT)) { \
|
|
||||||
asm("mov\t%c2(%1),%0" \
|
|
||||||
: REG(Reg) \
|
|
||||||
: "bDS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
|
|
||||||
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
|
|
||||||
sizeof(*(OBJECT->MEMBER)) * (DISP)), \
|
|
||||||
"m"(OBJECT->MEMBER)); \
|
|
||||||
} else { \
|
|
||||||
asm("mov\t%c3(%1,%2),%0" \
|
|
||||||
: REG(Reg) \
|
|
||||||
: "b"(OBJECT), "DS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
|
|
||||||
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
|
|
||||||
sizeof(*(OBJECT->MEMBER)) * (DISP)), \
|
|
||||||
"m"(OBJECT->MEMBER)); \
|
|
||||||
} \
|
|
||||||
Reg; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define PEEK_ARRAY(OBJECT, MEMBER, INDEX, DISP) /* o->m[i] */ \
|
|
||||||
(sizeof(*(OBJECT->MEMBER)) == 1 \
|
|
||||||
? PEEK_ARRAY_("=Q", OBJECT, MEMBER, INDEX, DISP) \
|
|
||||||
: PEEK_ARRAY_("=r", OBJECT, MEMBER, INDEX, DISP))
|
|
||||||
|
|
||||||
#define POKE_ARRAY_(REG, OBJECT, MEMBER, INDEX, DISP, VALUE) \
|
|
||||||
do { \
|
|
||||||
if (!(OBJECT)) { \
|
|
||||||
asm("mov\t%1,%c3(%2)" \
|
|
||||||
: "=m"(OBJECT->MEMBER) \
|
|
||||||
: REG((__typeof(*(OBJECT->MEMBER)))(VALUE)), \
|
|
||||||
"bDS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
|
|
||||||
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
|
|
||||||
sizeof(*(OBJECT->MEMBER)) * (DISP))); \
|
|
||||||
} else { \
|
|
||||||
asm("mov\t%1,%c4(%2,%3)" \
|
|
||||||
: "=m"(OBJECT->MEMBER) \
|
|
||||||
: REG((__typeof(*(OBJECT->MEMBER)))(VALUE)), "b"(OBJECT), \
|
|
||||||
"DS"((long)(INDEX) * sizeof(*(OBJECT->MEMBER))), \
|
|
||||||
"i"(__builtin_offsetof(__typeof(*(OBJECT)), MEMBER) + \
|
|
||||||
sizeof(*(OBJECT->MEMBER)) * (DISP))); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define POKE_ARRAY(OBJECT, MEMBER, INDEX, DISP, VALUE) /* o->m[i]=v */ \
|
|
||||||
do { \
|
|
||||||
__typeof(*(OBJECT->MEMBER)) Reg; \
|
|
||||||
switch (sizeof(*(OBJECT->MEMBER))) { \
|
|
||||||
case 1: \
|
|
||||||
POKE_ARRAY_("Q", OBJECT, MEMBER, INDEX, DISP, VALUE); \
|
|
||||||
break; \
|
|
||||||
default: \
|
|
||||||
POKE_ARRAY_("r", OBJECT, MEMBER, INDEX, DISP, VALUE); \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#endif /* SECTORLISP_H_ */
|
|
||||||
36
lisp.lds
36
lisp.lds
|
|
@ -1,36 +0,0 @@
|
||||||
ENTRY(_start)
|
|
||||||
|
|
||||||
SECTIONS {
|
|
||||||
|
|
||||||
.text 0x7c00 - 0x600 : {
|
|
||||||
*(.start)
|
|
||||||
*(.text.startup)
|
|
||||||
rodata = .;
|
|
||||||
*(.rodata .rodata.*)
|
|
||||||
. = 0x1fe;
|
|
||||||
SHORT(0xaa55);
|
|
||||||
*(.text .text.*)
|
|
||||||
_etext = .;
|
|
||||||
. = ALIGN(512);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bss : {
|
|
||||||
bss = .;
|
|
||||||
*(.bss .bss.*)
|
|
||||||
*(COMMON)
|
|
||||||
}
|
|
||||||
|
|
||||||
/DISCARD/ : {
|
|
||||||
*(.yoink)
|
|
||||||
*(.*)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boot = 0x7c00;
|
|
||||||
q.syntax = 8192*2;
|
|
||||||
q.look = 8192*2+256;
|
|
||||||
q.globals = 8192*2+256+2;
|
|
||||||
q.index = 8192*2+256+2+2;
|
|
||||||
q.token = 8192*2+256+2+2+2;
|
|
||||||
q.str = 8192*2+256+2+2+2+128;
|
|
||||||
v_sectors = SIZEOF(.text) / 512;
|
|
||||||
|
|
@ -23,8 +23,9 @@
|
||||||
;;
|
;;
|
||||||
;; Listed Projects
|
;; Listed Projects
|
||||||
;;
|
;;
|
||||||
;; - 836 bytes: https://github.com/jart/sectorlisp
|
;; - 512 bytes: https://github.com/jart/sectorlisp
|
||||||
;; - 13 kilobytes: https://t3x.org/klisp/
|
;; - 13 kilobytes: https://t3x.org/klisp/
|
||||||
|
;; - 47 kilobytes: https://github.com/matp/tiny-lisp
|
||||||
;; - 150 kilobytes: https://github.com/JeffBezanson/femtolisp
|
;; - 150 kilobytes: https://github.com/JeffBezanson/femtolisp
|
||||||
;; - Send pull request to be listed here
|
;; - Send pull request to be listed here
|
||||||
;;
|
;;
|
||||||
|
|
@ -72,6 +73,7 @@ NIL
|
||||||
;; CORRECT RESULT OF EXPRESSION IS STILL `A`
|
;; CORRECT RESULT OF EXPRESSION IS STILL `A`
|
||||||
;; REQUIRES CONS CAR CDR QUOTE ATOM EQ LAMBDA COND
|
;; REQUIRES CONS CAR CDR QUOTE ATOM EQ LAMBDA COND
|
||||||
;; SIMPLIFIED BUG FIXED VERSION OF JOHN MCCARTHY PAPER
|
;; SIMPLIFIED BUG FIXED VERSION OF JOHN MCCARTHY PAPER
|
||||||
|
;; NOTE: ((EQ (CAR E) NIL) (QUOTE *UNDEFINED)) CAN HELP
|
||||||
((LAMBDA (ASSOC EVCON BIND APPEND EVAL)
|
((LAMBDA (ASSOC EVCON BIND APPEND EVAL)
|
||||||
(EVAL (QUOTE ((LAMBDA (FF X) (FF X))
|
(EVAL (QUOTE ((LAMBDA (FF X) (FF X))
|
||||||
(QUOTE (LAMBDA (X)
|
(QUOTE (LAMBDA (X)
|
||||||
|
|
@ -98,7 +100,6 @@ NIL
|
||||||
((ATOM E) (ASSOC E A))
|
((ATOM E) (ASSOC E A))
|
||||||
((ATOM (CAR E))
|
((ATOM (CAR E))
|
||||||
(COND
|
(COND
|
||||||
((EQ (CAR E) NIL) (QUOTE *UNDEFINED))
|
|
||||||
((EQ (CAR E) (QUOTE QUOTE)) (CAR (CDR E)))
|
((EQ (CAR E) (QUOTE QUOTE)) (CAR (CDR E)))
|
||||||
((EQ (CAR E) (QUOTE ATOM)) (ATOM (EVAL (CAR (CDR E)) A)))
|
((EQ (CAR E) (QUOTE ATOM)) (ATOM (EVAL (CAR (CDR E)) A)))
|
||||||
((EQ (CAR E) (QUOTE EQ)) (EQ (EVAL (CAR (CDR E)) A)
|
((EQ (CAR E) (QUOTE EQ)) (EQ (EVAL (CAR (CDR E)) A)
|
||||||
|
|
|
||||||
177
realify.sed
177
realify.sed
|
|
@ -1,177 +0,0 @@
|
||||||
#-*-mode:sed;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
|
||||||
#───vi: et ft=sed ts=8 tw=8 fenc=utf-8 :vi─────────────────┘
|
|
||||||
#
|
|
||||||
# SYNOPSIS
|
|
||||||
#
|
|
||||||
# sed -i -f realify.sed foo.s
|
|
||||||
#
|
|
||||||
# OVERVIEW
|
|
||||||
#
|
|
||||||
# This converts ints and longs to shorts while preserving System V ABI
|
|
||||||
# x86_64 compatibility. This works better than gcc -m16 because we can
|
|
||||||
# avoid the ASZ and OSZ prefixes in most cases while also avoiding the
|
|
||||||
# legacy 32-bit calling conventions.
|
|
||||||
|
|
||||||
# remove comments
|
|
||||||
s/[ \t][ \t]*#.*//
|
|
||||||
|
|
||||||
s/leave\(q\|\)/leavew/
|
|
||||||
s/call\(q\|\)/callw/
|
|
||||||
s/ret\(q\|\)/retw/
|
|
||||||
s/popq\t%rbp/pop\t%bp/
|
|
||||||
s/pushq\t%rbp/push\t%bp/
|
|
||||||
s/pushq\t\(.*\)/sub\t$6,%sp\n\tpush\t\1/
|
|
||||||
s/popq\t\(.*\)/pop\t\1\n\tadd\t$6,%sp/
|
|
||||||
|
|
||||||
# # preserve hardcoded stack offsets
|
|
||||||
# # bloats code size 13%
|
|
||||||
# s/leave\(q\|\)/leavew\n\tadd\t$6,%sp/
|
|
||||||
# s/call\(q\|\)\t/sub\t$6,%sp\n\tcallw\t/
|
|
||||||
# s/ret\(q\|\)/retw\t$6/
|
|
||||||
# s/pushq\t\(.*\)/sub\t$6,%sp\n\tpush\t\1/
|
|
||||||
# s/popq\t\(.*\)/pop\t\1\n\tadd\t$6,%sp/
|
|
||||||
|
|
||||||
s/, /,/g
|
|
||||||
|
|
||||||
# 32-bitify
|
|
||||||
s/rax/eax/g
|
|
||||||
s/rbx/ebx/g
|
|
||||||
s/rcx/ecx/g
|
|
||||||
s/rdx/edx/g
|
|
||||||
s/rbp/ebp/g
|
|
||||||
s/rdi/edi/g
|
|
||||||
s/rsi/esi/g
|
|
||||||
s/rsp/esp/g
|
|
||||||
|
|
||||||
# unextension
|
|
||||||
s/movswl/mov/
|
|
||||||
s/movzwl/mov/
|
|
||||||
s/movslq/mov/
|
|
||||||
s/movzlq/mov/
|
|
||||||
s/movsbl/movsbw/
|
|
||||||
|
|
||||||
# unsuffix
|
|
||||||
s/^\(\t\(fild\|fist\|fistp\|fiadd\|fisub\|fisubr\|fimul\|fidiv\|fidivr\|ficom\)\)q\t/\1\t/
|
|
||||||
s/^\(\t\(mov\|add\|adc\|cmp\|test\|lea\|sbb\|mul\|imul\|div\|idiv\|in\|out\|xor\|sub\|and\|or\|rol\|ror\|rcl\|rcr\|shl\|shr\|sal\|sar\|inc\|dec\|not\|neg\)\)l\t/\1w\t/
|
|
||||||
s/^\(\t[a-z]*\)q\t/\1w\t/
|
|
||||||
s/movsww/mov/
|
|
||||||
|
|
||||||
# remove fluff
|
|
||||||
s/mov\t%eax,%eax//
|
|
||||||
s/mov\t%ebx,%ebx//
|
|
||||||
s/mov\t%ecx,%ecx//
|
|
||||||
s/mov\t%edx,%edx//
|
|
||||||
s/mov\t%ebp,%ebp//
|
|
||||||
s/mov\t%edi,%edi//
|
|
||||||
s/mov\t%esi,%esi//
|
|
||||||
s/mov\t%esp,%esp//
|
|
||||||
|
|
||||||
# make pic absolute
|
|
||||||
s/(%rip)//
|
|
||||||
|
|
||||||
# legal real mode modrm
|
|
||||||
s/(%ebx)/(%bx)/
|
|
||||||
s/(%edi)/(%di)/
|
|
||||||
s/(%esi)/(%si)/
|
|
||||||
s/(%ebp)/(%bp)/
|
|
||||||
s/(%ebx,%esi\(,1\|\))/(%bx,%si)/
|
|
||||||
s/(%ebx,%edi\(,1\|\))/(%bx,%di)/
|
|
||||||
s/(%ebp,%esi\(,1\|\))/(%bp,%si)/
|
|
||||||
s/(%ebp,%edi\(,1\|\))/(%bp,%di)/
|
|
||||||
|
|
||||||
# we need the asz prefix
|
|
||||||
s/(%eax,%eax/(%EAX,%EAX/
|
|
||||||
s/(%eax,%ebp/(%EAX,%EBP/
|
|
||||||
s/(%eax,%ebx/(%EAX,%EBX/
|
|
||||||
s/(%eax,%ecx/(%EAX,%ECX/
|
|
||||||
s/(%eax,%edi/(%EAX,%EDI/
|
|
||||||
s/(%eax,%edx/(%EAX,%EDX/
|
|
||||||
s/(%eax,%esi/(%EAX,%ESI/
|
|
||||||
s/(%ebp,%eax/(%EBP,%EAX/
|
|
||||||
s/(%ebp,%ebp/(%EBP,%EBP/
|
|
||||||
s/(%ebp,%ebx/(%EBP,%EBX/
|
|
||||||
s/(%ebp,%ecx/(%EBP,%ECX/
|
|
||||||
s/(%ebp,%edi/(%EBP,%EDI/
|
|
||||||
s/(%ebp,%edx/(%EBP,%EDX/
|
|
||||||
s/(%ebp,%esi/(%EBP,%ESI/
|
|
||||||
s/(%ebx,%eax/(%EBX,%EAX/
|
|
||||||
s/(%ebx,%ebp/(%EBX,%EBP/
|
|
||||||
s/(%ebx,%ebx/(%EBX,%EBX/
|
|
||||||
s/(%ebx,%ecx/(%EBX,%ECX/
|
|
||||||
s/(%ebx,%edi/(%EBX,%EDI/
|
|
||||||
s/(%ebx,%edx/(%EBX,%EDX/
|
|
||||||
s/(%ebx,%esi/(%EBX,%ESI/
|
|
||||||
s/(%ecx,%eax/(%ECX,%EAX/
|
|
||||||
s/(%ecx,%ebp/(%ECX,%EBP/
|
|
||||||
s/(%ecx,%ebx/(%ECX,%EBX/
|
|
||||||
s/(%ecx,%ecx/(%ECX,%ECX/
|
|
||||||
s/(%ecx,%edi/(%ECX,%EDI/
|
|
||||||
s/(%ecx,%edx/(%ECX,%EDX/
|
|
||||||
s/(%ecx,%esi/(%ECX,%ESI/
|
|
||||||
s/(%edi,%eax/(%EDI,%EAX/
|
|
||||||
s/(%edi,%ebp/(%EDI,%EBP/
|
|
||||||
s/(%edi,%ebx/(%EDI,%EBX/
|
|
||||||
s/(%edi,%ecx/(%EDI,%ECX/
|
|
||||||
s/(%edi,%edi/(%EDI,%EDI/
|
|
||||||
s/(%edi,%edx/(%EDI,%EDX/
|
|
||||||
s/(%edi,%esi/(%EDI,%ESI/
|
|
||||||
s/(%edx,%eax/(%EDX,%EAX/
|
|
||||||
s/(%edx,%ebp/(%EDX,%EBP/
|
|
||||||
s/(%edx,%ebx/(%EDX,%EBX/
|
|
||||||
s/(%edx,%ecx/(%EDX,%ECX/
|
|
||||||
s/(%edx,%edi/(%EDX,%EDI/
|
|
||||||
s/(%edx,%edx/(%EDX,%EDX/
|
|
||||||
s/(%edx,%esi/(%EDX,%ESI/
|
|
||||||
s/(%esi,%eax/(%ESI,%EAX/
|
|
||||||
s/(%esi,%ebp/(%ESI,%EBP/
|
|
||||||
s/(%esi,%ebx/(%ESI,%EBX/
|
|
||||||
s/(%esi,%ecx/(%ESI,%ECX/
|
|
||||||
s/(%esi,%edi/(%ESI,%EDI/
|
|
||||||
s/(%esi,%edx/(%ESI,%EDX/
|
|
||||||
s/(%esi,%esi/(%ESI,%ESI/
|
|
||||||
s/(%esp,%eax/(%ESP,%EAX/
|
|
||||||
s/(%esp,%ebp/(%ESP,%EBP/
|
|
||||||
s/(%esp,%ebx/(%ESP,%EBX/
|
|
||||||
s/(%esp,%ecx/(%ESP,%ECX/
|
|
||||||
s/(%esp,%edi/(%ESP,%EDI/
|
|
||||||
s/(%esp,%edx/(%ESP,%EDX/
|
|
||||||
s/(%esp,%esi/(%ESP,%ESI/
|
|
||||||
s/(,%eax/(,%EAX/
|
|
||||||
s/(,%ebx/(,%EBX/
|
|
||||||
s/(,%ecx/(,%ECX/
|
|
||||||
s/(,%edx/(,%EDX/
|
|
||||||
s/(,%esi/(,%ESI/
|
|
||||||
s/(,%edi/(,%EDI/
|
|
||||||
s/(,%ebp/(,%EBP/
|
|
||||||
s/(%eax)/(%EAX)/
|
|
||||||
s/(%ecx)/(%ECX)/
|
|
||||||
s/(%edx)/(%EDX)/
|
|
||||||
s/(%esp)/(%ESP)/
|
|
||||||
|
|
||||||
# 16bitify
|
|
||||||
s/eax/ax/g
|
|
||||||
s/ebx/bx/g
|
|
||||||
s/ecx/cx/g
|
|
||||||
s/edx/dx/g
|
|
||||||
s/ebp/bp/g
|
|
||||||
s/edi/di/g
|
|
||||||
s/esi/si/g
|
|
||||||
s/esp/sp/g
|
|
||||||
|
|
||||||
# sigh :\
|
|
||||||
# gcc needs a flag for not using rex byte regs. workaround:
|
|
||||||
# - %dil can be avoided through copious use of STOS() macro
|
|
||||||
# - %sil can be avoided through copious use of LODS() macro
|
|
||||||
# - %bpl shouldn't be allocated due to -fno-omit-frame-pointer
|
|
||||||
# - %spl shouldn't be allocated like ever
|
|
||||||
# beyond that there's only a few cases where %dil and %sil
|
|
||||||
# need some handcoded asm() macros to workaround, for example
|
|
||||||
# if ARG1 is long and you say (ARG1 & 1) gcc will use %dil
|
|
||||||
# so just kludge it using asm("and\t$1,%0" : "+Q"(ARG1))
|
|
||||||
#s/dil/bl/g
|
|
||||||
#s/sil/bh/g
|
|
||||||
#s/spl/bl/g
|
|
||||||
#s/bpl/bh/g
|
|
||||||
|
|
||||||
# nope
|
|
||||||
s/cltq//
|
|
||||||
23
realify.sh
23
realify.sh
|
|
@ -1,23 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# SYNOPSIS
|
|
||||||
#
|
|
||||||
# gcc -g0 -Os -wrapper realify.sh -ffixed-r{8,9,1{0,1,2,4,5}}
|
|
||||||
#
|
|
||||||
# OVERVIEW
|
|
||||||
#
|
|
||||||
# Reconfigures x86_64 compiler to emit 16-bit PC boot code.
|
|
||||||
|
|
||||||
if [ "${1##*/}" = as ]; then
|
|
||||||
for x; do
|
|
||||||
if [ "${x##*.}" = s ]; then
|
|
||||||
{
|
|
||||||
printf "\t.code16gcc"
|
|
||||||
sed -f realify.sed "$x"
|
|
||||||
} >"$x".tmp
|
|
||||||
mv -f "$x".tmp "$x"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec "$@"
|
|
||||||
46
start.S
46
start.S
|
|
@ -1,46 +0,0 @@
|
||||||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
|
||||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
|
||||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
||||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
|
||||||
│ │
|
|
||||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
|
||||||
│ any purpose with or without fee is hereby granted, provided that the │
|
|
||||||
│ above copyright notice and this permission notice appear in all copies. │
|
|
||||||
│ │
|
|
||||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
|
||||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
|
||||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
|
||||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
|
||||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
|
||||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
||||||
.section .start,"ax",@progbits
|
|
||||||
.globl _start
|
|
||||||
.code16
|
|
||||||
|
|
||||||
_start: jmp 1f # some bios scan for short jump
|
|
||||||
1: ljmp $0x600>>4,$_begin # end of bios data roundup page
|
|
||||||
|
|
||||||
_begin: push %cs # memory model cs=ds=es = 0x600
|
|
||||||
push %cs
|
|
||||||
push %cs
|
|
||||||
pop %ds
|
|
||||||
pop %es
|
|
||||||
pop %ss
|
|
||||||
mov $0x70000>>4,%sp
|
|
||||||
cld
|
|
||||||
xor %ax,%ax
|
|
||||||
xor %di,%di
|
|
||||||
mov $0x7c00-0x600,%cx
|
|
||||||
rep stosb # clears our bss memory
|
|
||||||
xchg %di,%bx # start buffer at 07c00
|
|
||||||
inc %cx # start at first sector
|
|
||||||
xor %dh,%dh # drive dl head zero
|
|
||||||
mov $0x0200+v_sectors,%ax # read sectors
|
|
||||||
int $0x13 # disk service
|
|
||||||
// 𝑠𝑙𝑖𝑑𝑒
|
|
||||||
|
|
||||||
.section .yoink
|
|
||||||
nopw main
|
|
||||||
Loading…
Reference in a new issue