|
@@ -26,19 +26,24 @@ exit
|
|
#define function
|
|
#define function
|
|
#define Null 16384
|
|
#define Null 16384
|
|
var M[Null * 2];
|
|
var M[Null * 2];
|
|
|
|
+var (*funcall)();
|
|
jmp_buf undefined;
|
|
jmp_buf undefined;
|
|
//`
|
|
//`
|
|
|
|
|
|
-var cx, dx, lo, kT, kEq, kCar, kCdr, kCond, kAtom, kCons, kQuote, kDefine;
|
|
|
|
-
|
|
|
|
-function Set(i, x) {
|
|
|
|
- M[Null + i] = x;
|
|
|
|
-}
|
|
|
|
|
|
+var cx, dx, depth, panic;
|
|
|
|
+var cHeap, cGets, cSets, cPrints;
|
|
|
|
+var kT, kEq, kCar, kCdr, kCond, kAtom, kCons, kQuote, kDefine;
|
|
|
|
|
|
function Get(i) {
|
|
function Get(i) {
|
|
|
|
+ ++cGets;
|
|
return M[Null + i];
|
|
return M[Null + i];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+function Set(i, x) {
|
|
|
|
+ ++cSets;
|
|
|
|
+ M[Null + i] = x;
|
|
|
|
+}
|
|
|
|
+
|
|
function Car(x) {
|
|
function Car(x) {
|
|
if (x > 0) Throw(List(kCar, x));
|
|
if (x > 0) Throw(List(kCar, x));
|
|
return x ? Get(x) : +0;
|
|
return x ? Get(x) : +0;
|
|
@@ -52,7 +57,7 @@ function Cdr(x) {
|
|
function Cons(car, cdr) {
|
|
function Cons(car, cdr) {
|
|
Set(--cx, cdr);
|
|
Set(--cx, cdr);
|
|
Set(--cx, car);
|
|
Set(--cx, car);
|
|
- if (cx < lo) lo = cx;
|
|
|
|
|
|
+ if (cx < cHeap) cHeap = cx;
|
|
return cx;
|
|
return cx;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -77,11 +82,6 @@ function ReadAtom(h) {
|
|
Hash(h, c) - Hash(0, Ord('N')));
|
|
Hash(h, c) - Hash(0, Ord('N')));
|
|
}
|
|
}
|
|
|
|
|
|
-function PrintAtom(x) {
|
|
|
|
- do PrintChar(Get(x));
|
|
|
|
- while ((x = Get(x + 1)));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
function ReadList() {
|
|
function ReadList() {
|
|
var x;
|
|
var x;
|
|
if ((x = Read()) > 0) {
|
|
if ((x = Read()) > 0) {
|
|
@@ -100,17 +100,33 @@ function ReadObject(t) {
|
|
return ReadList();
|
|
return ReadList();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+function Read() {
|
|
|
|
+ return ReadObject(ReadAtom(0));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function PrintAtom(x) {
|
|
|
|
+ do PrintChar(Get(x));
|
|
|
|
+ while ((x = Get(x + 1)));
|
|
|
|
+}
|
|
|
|
+
|
|
function PrintList(x) {
|
|
function PrintList(x) {
|
|
PrintChar(Ord('('));
|
|
PrintChar(Ord('('));
|
|
if (x < 0) {
|
|
if (x < 0) {
|
|
- PrintObject(Car(x));
|
|
|
|
|
|
+ Print(Car(x));
|
|
while ((x = Cdr(x))) {
|
|
while ((x = Cdr(x))) {
|
|
|
|
+ if (panic && cPrints > panic) {
|
|
|
|
+ PrintChar(Ord(' '));
|
|
|
|
+ PrintChar(0x2026);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
if (x < 0) {
|
|
if (x < 0) {
|
|
PrintChar(Ord(' '));
|
|
PrintChar(Ord(' '));
|
|
- PrintObject(Car(x));
|
|
|
|
|
|
+ Print(Car(x));
|
|
} else {
|
|
} else {
|
|
- PrintChar(0x2219);
|
|
|
|
- PrintObject(x);
|
|
|
|
|
|
+ PrintChar(Ord(' '));
|
|
|
|
+ PrintChar(Ord('.'));
|
|
|
|
+ PrintChar(Ord(' '));
|
|
|
|
+ Print(x);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -118,7 +134,8 @@ function PrintList(x) {
|
|
PrintChar(Ord(')'));
|
|
PrintChar(Ord(')'));
|
|
}
|
|
}
|
|
|
|
|
|
-function PrintObject(x) {
|
|
|
|
|
|
+function Print(x) {
|
|
|
|
+ ++cPrints;
|
|
if (1./x < 0) {
|
|
if (1./x < 0) {
|
|
PrintList(x);
|
|
PrintList(x);
|
|
} else {
|
|
} else {
|
|
@@ -126,13 +143,12 @@ function PrintObject(x) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-function Print(e) {
|
|
|
|
- PrintObject(e);
|
|
|
|
- PrintChar(Ord('\n'));
|
|
|
|
|
|
+function List(x, y) {
|
|
|
|
+ return Cons(x, Cons(y, 0));
|
|
}
|
|
}
|
|
|
|
|
|
-function Read() {
|
|
|
|
- return ReadObject(ReadAtom(0));
|
|
|
|
|
|
+function Define(A, x, a) {
|
|
|
|
+ return Gc(A, Cons(x, Remove(Car(x), a)));
|
|
}
|
|
}
|
|
|
|
|
|
function Remove(x, y) {
|
|
function Remove(x, y) {
|
|
@@ -141,14 +157,6 @@ function Remove(x, y) {
|
|
return Cons(Car(y), Remove(x, Cdr(y)));
|
|
return Cons(Car(y), Remove(x, Cdr(y)));
|
|
}
|
|
}
|
|
|
|
|
|
-function List(x, y) {
|
|
|
|
- return Cons(x, Cons(y, 0));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-function Define(x, y) {
|
|
|
|
- return Cons(Cons(x, Read()), Remove(x, y));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
function Gc(A, x) {
|
|
function Gc(A, x) {
|
|
var C, B = cx;
|
|
var C, B = cx;
|
|
x = Copy(x, A, A - B), C = cx;
|
|
x = Copy(x, A, A - B), C = cx;
|
|
@@ -167,7 +175,6 @@ function Evlis(m, a) {
|
|
}
|
|
}
|
|
|
|
|
|
function Pairlis(x, y, a) {
|
|
function Pairlis(x, y, a) {
|
|
- if (!!x ^ !!y) Throw(List(x, y));
|
|
|
|
return x ? Cons(Cons(Car(x), Car(y)),
|
|
return x ? Cons(Cons(Car(x), Car(y)),
|
|
Pairlis(Cdr(x), Cdr(y), a)) : a;
|
|
Pairlis(Cdr(x), Cdr(y), a)) : a;
|
|
}
|
|
}
|
|
@@ -184,7 +191,7 @@ function Evcon(c, a) {
|
|
} else if (Cdr(c)) {
|
|
} else if (Cdr(c)) {
|
|
return Evcon(Cdr(c), a);
|
|
return Evcon(Cdr(c), a);
|
|
} else {
|
|
} else {
|
|
- Throw(c);
|
|
|
|
|
|
+ Throw(Cons(kCond, c));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -195,16 +202,61 @@ function Apply(f, x, a) {
|
|
if (f == kAtom) return Car(x) < 0 ? 0 : kT;
|
|
if (f == kAtom) return Car(x) < 0 ? 0 : kT;
|
|
if (f == kCar) return Car(Car(x));
|
|
if (f == kCar) return Car(Car(x));
|
|
if (f == kCdr) return Cdr(Car(x));
|
|
if (f == kCdr) return Cdr(Car(x));
|
|
- return Apply(Assoc(f, a), x, a);
|
|
|
|
|
|
+ return funcall(f, Assoc(f, a), x, a);
|
|
}
|
|
}
|
|
|
|
|
|
function Eval(e, a) {
|
|
function Eval(e, a) {
|
|
- var A = cx;
|
|
|
|
if (!e) return e;
|
|
if (!e) return e;
|
|
if (e > 0) return Assoc(e, a);
|
|
if (e > 0) return Assoc(e, a);
|
|
if (Car(e) == kQuote) return Car(Cdr(e));
|
|
if (Car(e) == kQuote) return Car(Cdr(e));
|
|
- if (Car(e) == kCond) return Gc(A, Evcon(Cdr(e), a));
|
|
|
|
- return Gc(A, Apply(Car(e), Evlis(Cdr(e), a), a));
|
|
|
|
|
|
+ if (Car(e) == kCond) return Evcon(Cdr(e), a);
|
|
|
|
+ return Apply(Car(e), Evlis(Cdr(e), a), a);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function Funcall(f, l, x, a) {
|
|
|
|
+ var A = cx;
|
|
|
|
+ return Gc(A, Apply(l, x, a));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function Funtrace(f, l, x, a) {
|
|
|
|
+ var y, i, A = cx;
|
|
|
|
+ Indent(depth);
|
|
|
|
+ Print(f);
|
|
|
|
+ Print(x);
|
|
|
|
+ PrintChar(Ord('\n'));
|
|
|
|
+ depth += 2;
|
|
|
|
+ y = Funcall(f, l, x, a);
|
|
|
|
+ depth -= 2;
|
|
|
|
+ Indent(depth);
|
|
|
|
+ Print(f);
|
|
|
|
+ Print(x);
|
|
|
|
+ PrintChar(Ord(' '));
|
|
|
|
+ PrintChar(0x2192);
|
|
|
|
+ PrintChar(Ord(' '));
|
|
|
|
+ Print(y);
|
|
|
|
+ PrintChar(Ord('\n'));
|
|
|
|
+ return y;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function Indent(i) {
|
|
|
|
+ if (!i) return;
|
|
|
|
+ PrintChar(Ord(' '));
|
|
|
|
+ Indent(i - 1);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function Dump(a) {
|
|
|
|
+ if (!a) return;
|
|
|
|
+ Dump(Cdr(a));
|
|
|
|
+ PrintChar(Ord('('));
|
|
|
|
+ Print(kDefine);
|
|
|
|
+ PrintChar(Ord(' '));
|
|
|
|
+ Print(Car(Car(a)));
|
|
|
|
+ PrintChar(Ord(' '));
|
|
|
|
+ PrintChar(Ord('.'));
|
|
|
|
+ PrintChar(Ord(' '));
|
|
|
|
+ Print(Cdr(Car(a)));
|
|
|
|
+ PrintChar(Ord(')'));
|
|
|
|
+ PrintChar(Ord('\n'));
|
|
}
|
|
}
|
|
|
|
|
|
function LoadBuiltins() {
|
|
function LoadBuiltins() {
|
|
@@ -267,17 +319,24 @@ ReadChar() {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-main() {
|
|
|
|
|
|
+main(argc, argv)
|
|
|
|
+ char *argv[];
|
|
|
|
+{
|
|
var x, a, A;
|
|
var x, a, A;
|
|
setlocale(LC_ALL, "");
|
|
setlocale(LC_ALL, "");
|
|
bestlineSetXlatCallback(bestlineUppercase);
|
|
bestlineSetXlatCallback(bestlineUppercase);
|
|
|
|
+ if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 't') {
|
|
|
|
+ funcall = Funtrace;
|
|
|
|
+ } else {
|
|
|
|
+ funcall = Funcall;
|
|
|
|
+ }
|
|
LoadBuiltins();
|
|
LoadBuiltins();
|
|
for (a = 0;;) {
|
|
for (a = 0;;) {
|
|
A = cx;
|
|
A = cx;
|
|
if (!(x = setjmp(undefined))) {
|
|
if (!(x = setjmp(undefined))) {
|
|
x = Read();
|
|
x = Read();
|
|
- if (x == kDefine) {
|
|
|
|
- a = Gc(0, Define(Read(), a));
|
|
|
|
|
|
+ if (x < 0 && Car(x) == kDefine) {
|
|
|
|
+ a = Define(0, Cdr(x), a);
|
|
SaveMachine(a);
|
|
SaveMachine(a);
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
@@ -287,6 +346,7 @@ main() {
|
|
PrintChar('?');
|
|
PrintChar('?');
|
|
}
|
|
}
|
|
Print(x);
|
|
Print(x);
|
|
|
|
+ PrintChar('\n');
|
|
Gc(A, 0);
|
|
Gc(A, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -296,8 +356,8 @@ main() {
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// JavaScript Specific Code for https://justine.lol/
|
|
// JavaScript Specific Code for https://justine.lol/
|
|
|
|
|
|
-var a, code, index, output, M, Null;
|
|
|
|
-var eInput, eOutput, eSubmit, eReset, eLoad, ePrograms;
|
|
|
|
|
|
+var a, code, index, output, funcall, M, Null;
|
|
|
|
+var eInput, eOutput, eEval, eReset, eLoad, eTrace, ePrograms;
|
|
|
|
|
|
function Throw(x) {
|
|
function Throw(x) {
|
|
throw x;
|
|
throw x;
|
|
@@ -311,7 +371,10 @@ function Reset() {
|
|
var i;
|
|
var i;
|
|
a = 0;
|
|
a = 0;
|
|
cx = 0;
|
|
cx = 0;
|
|
- lo = 0;
|
|
|
|
|
|
+ cHeap = 0;
|
|
|
|
+ cGets = 0;
|
|
|
|
+ cSets = 0;
|
|
|
|
+ cPrints = 0;
|
|
Null = 16384;
|
|
Null = 16384;
|
|
M = new Array(Null * 2);
|
|
M = new Array(Null * 2);
|
|
for (i = 0; i < M.length; ++i) {
|
|
for (i = 0; i < M.length; ++i) {
|
|
@@ -343,8 +406,11 @@ function ReadChar() {
|
|
|
|
|
|
function Lisp() {
|
|
function Lisp() {
|
|
var x, A;
|
|
var x, A;
|
|
- lo = cx;
|
|
|
|
- output = '';
|
|
|
|
|
|
+ cGets = 0;
|
|
|
|
+ cSets = 0;
|
|
|
|
+ cHeap = cx;
|
|
|
|
+ cPrints = 0;
|
|
|
|
+ output = "";
|
|
while (dx) {
|
|
while (dx) {
|
|
if (dx <= Ord(' ')) {
|
|
if (dx <= Ord(' ')) {
|
|
ReadChar();
|
|
ReadChar();
|
|
@@ -352,8 +418,8 @@ function Lisp() {
|
|
A = cx;
|
|
A = cx;
|
|
try {
|
|
try {
|
|
x = Read();
|
|
x = Read();
|
|
- if (x == kDefine) {
|
|
|
|
- a = Gc(0, Define(Read(), a));
|
|
|
|
|
|
+ if (x < 0 && Car(x) == kDefine) {
|
|
|
|
+ a = Define(0, Cdr(x), a);
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
x = Eval(x, a);
|
|
x = Eval(x, a);
|
|
@@ -362,6 +428,7 @@ function Lisp() {
|
|
x = z;
|
|
x = z;
|
|
}
|
|
}
|
|
Print(x);
|
|
Print(x);
|
|
|
|
+ PrintChar(Ord('\n'));
|
|
Gc(A, 0);
|
|
Gc(A, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -377,21 +444,11 @@ function Load(s) {
|
|
index = 1;
|
|
index = 1;
|
|
}
|
|
}
|
|
|
|
|
|
-function OnSubmit() {
|
|
|
|
|
|
+function OnEval() {
|
|
Load(eInput.value.toUpperCase());
|
|
Load(eInput.value.toUpperCase());
|
|
Lisp();
|
|
Lisp();
|
|
}
|
|
}
|
|
|
|
|
|
-function Dump(a) {
|
|
|
|
- if (!a) return;
|
|
|
|
- Dump(Cdr(a));
|
|
|
|
- output += "DEFINE ";
|
|
|
|
- PrintObject(Car(Car(a)));
|
|
|
|
- output += " ";
|
|
|
|
- PrintObject(Cdr(Car(a)));
|
|
|
|
- output += "\n";
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
function OnReset() {
|
|
function OnReset() {
|
|
output = "";
|
|
output = "";
|
|
try {
|
|
try {
|
|
@@ -406,6 +463,18 @@ function OnReset() {
|
|
ReportUsage();
|
|
ReportUsage();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+function OnTrace() {
|
|
|
|
+ var t;
|
|
|
|
+ Load(eInput.value);
|
|
|
|
+ t = panic;
|
|
|
|
+ depth = 0;
|
|
|
|
+ panic = 10000;
|
|
|
|
+ funcall = Funtrace;
|
|
|
|
+ Lisp();
|
|
|
|
+ funcall = Funcall;
|
|
|
|
+ panic = t;
|
|
|
|
+}
|
|
|
|
+
|
|
function OnLoad() {
|
|
function OnLoad() {
|
|
ePrograms.classList.toggle("show");
|
|
ePrograms.classList.toggle("show");
|
|
}
|
|
}
|
|
@@ -431,7 +500,7 @@ function RestoreMachine() {
|
|
M = machine[0];
|
|
M = machine[0];
|
|
a = machine[1];
|
|
a = machine[1];
|
|
cx = machine[2];
|
|
cx = machine[2];
|
|
- lo = cx;
|
|
|
|
|
|
+ cHeap = cx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -449,25 +518,48 @@ function Number(i) {
|
|
function ReportUsage() {
|
|
function ReportUsage() {
|
|
var i, c;
|
|
var i, c;
|
|
for (c = i = 0; i < Null; i += 2) {
|
|
for (c = i = 0; i < Null; i += 2) {
|
|
- if (Get(i)) ++c;
|
|
|
|
|
|
+ if (M[Null + i]) ++c;
|
|
}
|
|
}
|
|
- document.getElementById("usage").innerText =
|
|
|
|
|
|
+ document.getElementById("ops").innerText =
|
|
|
|
+ Number(cGets) + " gets / " +
|
|
|
|
+ Number(cSets) + " sets";
|
|
|
|
+ document.getElementById("mem").innerText =
|
|
Number((-cx >> 1) + c) + " / " +
|
|
Number((-cx >> 1) + c) + " / " +
|
|
- Number((-lo >> 1) + c) + " / " +
|
|
|
|
|
|
+ Number((-cHeap >> 1) + c) + " / " +
|
|
Number(Null) + " doublewords";
|
|
Number(Null) + " doublewords";
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+function Discount(f) {
|
|
|
|
+ return function() {
|
|
|
|
+ var x, g, h, s;
|
|
|
|
+ g = cGets;
|
|
|
|
+ s = cSets;
|
|
|
|
+ h = cHeap;
|
|
|
|
+ x = f.apply(this, arguments);
|
|
|
|
+ cHeap = h;
|
|
|
|
+ cSets = s;
|
|
|
|
+ cGets = g;
|
|
|
|
+ return x;
|
|
|
|
+ };
|
|
|
|
+}
|
|
|
|
+
|
|
function SetUp() {
|
|
function SetUp() {
|
|
|
|
+ funcall = Funcall;
|
|
|
|
+ Read = Discount(Read);
|
|
|
|
+ Print = Discount(Print);
|
|
|
|
+ Define = Discount(Define);
|
|
eLoad = document.getElementById("load");
|
|
eLoad = document.getElementById("load");
|
|
eInput = document.getElementById("input");
|
|
eInput = document.getElementById("input");
|
|
eReset = document.getElementById("reset");
|
|
eReset = document.getElementById("reset");
|
|
|
|
+ eTrace = document.getElementById("trace");
|
|
eOutput = document.getElementById("output");
|
|
eOutput = document.getElementById("output");
|
|
- eSubmit = document.getElementById("submit");
|
|
|
|
|
|
+ eEval = document.getElementById("eval");
|
|
ePrograms = document.getElementById("programs");
|
|
ePrograms = document.getElementById("programs");
|
|
window.onclick = OnWindowClick;
|
|
window.onclick = OnWindowClick;
|
|
- eSubmit.onclick = OnSubmit;
|
|
|
|
- eReset.onclick = OnReset;
|
|
|
|
eLoad.onclick = OnLoad;
|
|
eLoad.onclick = OnLoad;
|
|
|
|
+ eReset.onclick = OnReset;
|
|
|
|
+ eTrace.onclick = OnTrace;
|
|
|
|
+ eEval.onclick = OnEval;
|
|
Reset();
|
|
Reset();
|
|
RestoreMachine();
|
|
RestoreMachine();
|
|
ReportUsage();
|
|
ReportUsage();
|