lisp.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
  2. │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
  3. ╞══════════════════════════════════════════════════════════════════════════════╡
  4. │ Copyright 2020 Justine Alexandra Roberts Tunney │
  5. │ │
  6. │ Permission to use, copy, modify, and/or distribute this software for │
  7. │ any purpose with or without fee is hereby granted, provided that the │
  8. │ above copyright notice and this permission notice appear in all copies. │
  9. │ │
  10. │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
  11. │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
  12. │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
  13. │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
  14. │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
  15. │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
  16. │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
  17. │ PERFORMANCE OF THIS SOFTWARE. │
  18. ╚─────────────────────────────────────────────────────────────────────────────*/
  19. #include "bestline.h"
  20. #ifndef __COSMOPOLITAN__
  21. #include <stdio.h>
  22. #include <locale.h>
  23. #include <setjmp.h>
  24. #endif
  25. #define var int
  26. #define function
  27. #define Null 0100000
  28. var M[Null * 2];
  29. jmp_buf undefined;
  30. var cx, dx, kT, kEq, kCar, kCdr, kCond, kAtom, kCons, kQuote;
  31. function Set(i, x) {
  32. M[Null + i] = x;
  33. }
  34. function Get(i) {
  35. return M[Null + i];
  36. }
  37. function Hash(h, c) {
  38. return h + c * 2;
  39. }
  40. function Intern(x, y, i) {
  41. i &= Null - 1;
  42. if (x == Get(i) && y == Get(i + 1)) return i;
  43. if (Get(i)) return Intern(x, y, i + 2);
  44. Set(i, x);
  45. Set(i + 1, y);
  46. return i;
  47. }
  48. function ReadAtom(h) {
  49. var c = ReadChar();
  50. if (c <= Ord(' ')) return ReadAtom(h);
  51. return Intern(c, c > Ord(')') && dx > Ord(')') ?
  52. ReadAtom(Hash(h, c)) : 0,
  53. Hash(h, c) - Hash(0, Ord('N')));
  54. }
  55. function PrintAtom(x) {
  56. do PrintChar(Get(x));
  57. while ((x = Get(x + 1)));
  58. }
  59. function AddList(x) {
  60. return Cons(x, ReadList());
  61. }
  62. function ReadList() {
  63. var t = ReadAtom(0);
  64. if (Get(t) == Ord(')')) return -0;
  65. return AddList(ReadObject(t));
  66. }
  67. function ReadObject(t) {
  68. if (Get(t) != Ord('(')) return t;
  69. return ReadList();
  70. }
  71. function PrintList(x) {
  72. PrintChar(Ord('('));
  73. if (x < 0) {
  74. PrintObject(Car(x));
  75. while ((x = Cdr(x))) {
  76. if (x < 0) {
  77. PrintChar(Ord(' '));
  78. PrintObject(Car(x));
  79. } else {
  80. PrintChar(0x2219);
  81. PrintObject(x);
  82. break;
  83. }
  84. }
  85. }
  86. PrintChar(Ord(')'));
  87. }
  88. function PrintObject(x) {
  89. if (1./x < 0) {
  90. PrintList(x);
  91. } else {
  92. PrintAtom(x);
  93. }
  94. }
  95. function Print(e) {
  96. PrintObject(e);
  97. PrintChar(Ord('\n'));
  98. }
  99. function Read() {
  100. return ReadObject(ReadAtom(0));
  101. }
  102. function Car(x) {
  103. if (x < 0) {
  104. return Get(x);
  105. } else {
  106. Throw(x);
  107. }
  108. }
  109. function Cdr(x) {
  110. if (x < 0) {
  111. return Get(x + 1);
  112. } else {
  113. Throw(x);
  114. }
  115. }
  116. function Cons(car, cdr) {
  117. Set(--cx, cdr);
  118. Set(--cx, car);
  119. return cx;
  120. }
  121. function Gc(A, x) {
  122. var C, B = cx;
  123. x = Copy(x, A, A - B), C = cx;
  124. while (C < B) Set(--A, Get(--B));
  125. cx = A;
  126. return x;
  127. }
  128. function Copy(x, m, k) {
  129. return x < m ? Cons(Copy(Car(x), m, k),
  130. Copy(Cdr(x), m, k)) + k : x;
  131. }
  132. function Evlis(m, a) {
  133. return m ? Cons(Eval(Car(m), a),
  134. Evlis(Cdr(m), a)) : m;
  135. }
  136. function Pairlis(x, y, a) {
  137. return x ? Cons(Cons(Car(x), Car(y)),
  138. Pairlis(Cdr(x), Cdr(y), a)) : a;
  139. }
  140. function Assoc(x, y) {
  141. if (y >= 0) Throw(x);
  142. if (x == Car(Car(y))) return Cdr(Car(y));
  143. return Assoc(x, Cdr(y));
  144. }
  145. function Evcon(c, a) {
  146. if (Eval(Car(Car(c)), a)) {
  147. return Eval(Car(Cdr(Car(c))), a);
  148. } else if (Cdr(c)) {
  149. return Evcon(Cdr(c), a);
  150. } else {
  151. Throw(c);
  152. }
  153. }
  154. function Apply(f, x, a) {
  155. if (f < 0) return Eval(Car(Cdr(Cdr(f))), Pairlis(Car(Cdr(f)), x, a));
  156. if (f == kEq) return Car(x) == Car(Cdr(x)) ? kT : 0;
  157. if (f == kCons) return Cons(Car(x), Car(Cdr(x)));
  158. if (f == kAtom) return Car(x) < 0 ? 0 : kT;
  159. if (f == kCar) return Car(Car(x));
  160. if (f == kCdr) return Cdr(Car(x));
  161. return Apply(Assoc(f, a), x, a);
  162. }
  163. function Eval(e, a) {
  164. var A = cx;
  165. if (!e) return 0;
  166. if (e > 0) return Assoc(e, a);
  167. if (Car(e) == kQuote) return Car(Cdr(e));
  168. if (Car(e) == kCond) {
  169. e = Evcon(Cdr(e), a);
  170. } else {
  171. e = Apply(Car(e), Evlis(Cdr(e), a), a);
  172. }
  173. return Gc(A, e);
  174. }
  175. function Lisp() {
  176. var x, a;
  177. ReadAtom(0);
  178. kT = ReadAtom(0);
  179. kCar = ReadAtom(0);
  180. kCdr = ReadAtom(0);
  181. kAtom = ReadAtom(0);
  182. kCond = ReadAtom(0);
  183. kCons = ReadAtom(0);
  184. kQuote = ReadAtom(0);
  185. kEq = ReadAtom(0);
  186. for (a = 0;;) {
  187. if (!(x = setjmp(undefined))) {
  188. x = Read();
  189. x = Eval(x, a);
  190. if (x < 0) {
  191. a = Cons(x, a);
  192. }
  193. } else {
  194. PrintChar(63);
  195. }
  196. Print(x);
  197. }
  198. }
  199. Ord(c) {
  200. return c;
  201. }
  202. Throw(x) {
  203. longjmp(undefined, x);
  204. }
  205. PrintChar(b) {
  206. fputwc(b, stdout);
  207. }
  208. ReadChar() {
  209. int b, c, t;
  210. static char *freeme;
  211. static char *line = "NIL T CAR CDR ATOM COND CONS QUOTE EQ ";
  212. if (line || (line = freeme = bestlineWithHistory("* ", "sectorlisp"))) {
  213. if (*line) {
  214. c = *line++ & 0377;
  215. if (c >= 0300) {
  216. for (b = 0200; c & b; b >>= 1) c ^= b;
  217. while ((*line & 0300) == 0200) {
  218. c <<= 6;
  219. c |= *line++ & 0177;
  220. }
  221. }
  222. } else {
  223. free(freeme);
  224. freeme = 0;
  225. line = 0;
  226. c = Ord('\n');
  227. }
  228. t = dx;
  229. dx = c;
  230. return t;
  231. } else {
  232. PrintChar(Ord('\n'));
  233. exit(0);
  234. }
  235. }
  236. main() {
  237. setlocale(LC_ALL, "");
  238. bestlineSetXlatCallback(bestlineUppercase);
  239. Lisp();
  240. }