123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
- │vi: set net ft=c ts=2 sts=2 sw=2 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. │
- ╚─────────────────────────────────────────────────────────────────────────────*/
- #include "bestline.h"
- #ifndef __COSMOPOLITAN__
- #include <ctype.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #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 ─╬─│┼
- ╚────────────────────────────────────────────────────────────────────────────│*/
- #define ATOM 1
- #define CONS 0
- #define ISATOM(x) ((x)&1)
- #define VALUE(x) ((x)>>1)
- #define OBJECT(t,v) ((v)<<1|(t))
- #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)
- const char kSymbols[] =
- "NIL\0"
- "T\0"
- "QUOTE\0"
- "COND\0"
- "ATOM\0"
- "CAR\0"
- "CDR\0"
- "CONS\0"
- "EQ\0"
- "LAMBDA\0"
- #if FUNDEF
- "*UNDEFINED"
- #endif
- ;
- int g_look;
- int g_index;
- char g_token[128];
- int g_mem[8192];
- char g_str[8192];
- int GetList(void);
- int GetObject(void);
- void PrintObject(int);
- int Eval(int, int);
- void SetupBuiltins(void) {
- memmove(g_str, kSymbols, sizeof(kSymbols));
- }
- int Car(int x) {
- return g_mem[VALUE(x) + 0];
- }
- int Cdr(int x) {
- return g_mem[VALUE(x) + 1];
- }
- int Cons(int car, int cdr) {
- int i, cell;
- i = g_index;
- g_mem[i + 0] = car;
- g_mem[i + 1] = cdr;
- g_index = i + 2;
- cell = OBJECT(CONS, i);
- return cell;
- }
- char *StpCpy(char *d, char *s) {
- char c;
- do {
- c = *s++;
- *d++ = c;
- } while (c);
- return d;
- }
- int Intern(char *s) {
- int j, cx;
- char c, *z, *t;
- z = g_str;
- c = *z++;
- while (c) {
- for (j = 0;; ++j) {
- if (c != s[j]) {
- break;
- }
- if (!c) {
- return OBJECT(ATOM, z - g_str - j - 1);
- }
- c = *z++;
- }
- while (c) c = *z++;
- c = *z++;
- }
- --z;
- StpCpy(z, s);
- return OBJECT(ATOM, z - g_str);
- }
- void PrintChar(unsigned char b) {
- if (write(1, &b, 1) == -1) exit(1);
- }
- void PrintString(char *s) {
- char c;
- for (;;) {
- if (!(c = s[0])) break;
- PrintChar(c);
- ++s;
- }
- }
- int GetChar(void) {
- int b;
- static char *l, *p;
- if (l || (l = p = bestlineWithHistory("* ", "sectorlisp"))) {
- if (*p) {
- b = *p++ & 255;
- } else {
- free(l);
- l = p = 0;
- b = '\n';
- }
- return b;
- } else {
- PrintString("\n");
- exit(0);
- }
- }
- void GetToken(void) {
- int al;
- char *di;
- di = g_token;
- do {
- if (g_look > ' ') {
- *di++ = g_look;
- }
- al = g_look;
- g_look = GetChar();
- } while (al <= ' ' || (al > ')' && g_look > ')'));
- *di++ = 0;
- }
- int ConsumeObject(void) {
- GetToken();
- return GetObject();
- }
- int List(int x, int y) {
- return Cons(x, Cons(y, NIL));
- }
- int Quote(int x) {
- return List(ATOM_QUOTE, x);
- }
- int GetQuote(void) {
- return Quote(ConsumeObject());
- }
- int AddList(int x) {
- return Cons(x, GetList());
- }
- int GetList(void) {
- GetToken();
- #if QUOTES
- if (*g_token == '.') return ConsumeObject();
- if (*g_token == '\'') return AddList(GetQuote());
- #endif
- if (*g_token == ')') return NIL;
- return AddList(GetObject());
- }
- int GetObject(void) {
- #if QUOTES
- if (*g_token == '\'') return GetQuote();
- #endif
- if (*g_token == '(') return GetList();
- return Intern(g_token);
- }
- int ReadObject(void) {
- g_look = GetChar();
- GetToken();
- return GetObject();
- }
- int Read(void) {
- return ReadObject();
- }
- void PrintAtom(int x) {
- PrintString(g_str + VALUE(x));
- }
- void PrintList(int x) {
- #if QUOTES
- if (Car(x) == ATOM_QUOTE) {
- PrintChar('\'');
- PrintObject(Car(Cdr(x)));
- return;
- }
- #endif
- PrintChar('(');
- PrintObject(Car(x));
- while ((x = Cdr(x))) {
- if (!ISATOM(x)) {
- PrintChar(' ');
- PrintObject(Car(x));
- } else {
- PrintString("∙");
- PrintObject(x);
- break;
- }
- }
- PrintChar(')');
- }
- void PrintObject(int x) {
- if (ISATOM(x)) {
- PrintAtom(x);
- } else {
- PrintList(x);
- }
- }
- void Print(int i) {
- PrintObject(i);
- PrintString("\n");
- }
- /*───────────────────────────────────────────────────────────────────────────│─╗
- │ The LISP Challenge § Bootstrap John McCarthy's Metacircular Evaluator ─╬─│┼
- ╚────────────────────────────────────────────────────────────────────────────│*/
- int Assoc(int x, int y) {
- if (y == NIL) return NIL;
- if (x == Car(Car(y))) return Cdr(Car(y));
- return Assoc(x, Cdr(y));
- }
- int Evcon(int c, int a) {
- if (Eval(Car(Car(c)), a) != NIL) {
- return Eval(Car(Cdr(Car(c))), a);
- } else {
- return Evcon(Cdr(c), a);
- }
- }
- int Pairlis(int x, int y, int a) {
- int di, si; /* it's zip() basically */
- if (x == NIL) return a;
- di = Cons(Car(x), Car(y));
- si = Pairlis(Cdr(x), Cdr(y), a);
- return Cons(di, si); /* Tail-Modulo-Cons */
- }
- int Evlis(int m, int a) {
- int di, si;
- if (m == NIL) return NIL;
- di = Eval(Car(m), a);
- si = Evlis(Cdr(m), a);
- return Cons(di, si);
- }
- int Apply(int fn, int x, int a) {
- int t1, si, ax;
- if (ISATOM(fn)) {
- switch (fn) {
- #if FUNDEF
- case NIL:
- return UNDEFINED;
- #endif
- case ATOM_CAR:
- return Car(Car(x));
- case ATOM_CDR:
- return Cdr(Car(x));
- case ATOM_ATOM:
- return ISATOM(Car(x)) ? ATOM_T : NIL;
- case ATOM_CONS:
- return Cons(Car(x), Car(Cdr(x)));
- case ATOM_EQ:
- return Car(x) == Car(Cdr(x)) ? ATOM_T : NIL;
- default:
- return Apply(Eval(fn, a), x, a);
- }
- }
- if (Car(fn) == ATOM_LAMBDA) {
- t1 = Cdr(fn);
- si = Pairlis(Car(t1), x, a);
- ax = Car(Cdr(t1));
- return Eval(ax, si);
- }
- return UNDEFINED;
- }
- int Evaluate(int e, int a) {
- int ax;
- if (ISATOM(e))
- return Assoc(e, a);
- ax = Car(e);
- if (ISATOM(ax)) {
- if (ax == ATOM_QUOTE)
- return Car(Cdr(e));
- if (ax == ATOM_COND)
- return Evcon(Cdr(e), a);
- }
- return Apply(ax, Evlis(Cdr(e), a), a);
- }
- 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 ─╬─│┼
- ╚────────────────────────────────────────────────────────────────────────────│*/
- void Repl(void) {
- for (;;) {
- Print(Eval(Read(), NIL));
- }
- }
- int main(int argc, char *argv[]) {
- SetupBuiltins();
- bestlineSetXlatCallback(bestlineUppercase);
- PrintString("THE LISP CHALLENGE V1\r\n"
- "VISIT GITHUB.COM/JART\r\n");
- Repl();
- }
|