2
0

lisp.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. /*bin/echo '#-*- indent-tabs-mode:nil;js-indent-level:2;coding:utf-8 -*-
  2. SectorLISP v2.o (ISC License)
  3. Copyright 2021 Justine Tunney
  4. This file implements SectorLISP as a C / JavaScript polyglot and
  5. includes friendly branch features such as the undefined behavior
  6. exceptions handlers, optimized interning, and global definitions
  7. (aset standard-display-table #x2029 [?¶]) ;; emacs protip '>/dev/null
  8. curl -so bestline.c -z bestline.c https://justine.lol/sectorlisp2/bestline.c
  9. curl -so bestline.h -z bestline.h https://justine.lol/sectorlisp2/bestline.h
  10. [ lisp.js -nt lisp ] && cc -w -xc lisp.js bestline.c -o lisp
  11. exec ./lisp "$@"
  12. exit
  13. */
  14. //
`
  15. #include "bestline.h"
  16. #ifndef __COSMOPOLITAN__
  17. #include <assert.h>
  18. #include <stdio.h>
  19. #include <locale.h>
  20. #include <setjmp.h>
  21. #endif
  22. #define var int
  23. #define function
  24. #define Null 16384
  25. var M[Null * 2];
  26. var (*funcall)();
  27. jmp_buf undefined;
  28. //`
  29. var ax, cx, dx, depth, panic, fail;
  30. var cHeap, cGets, cSets, cReads, cPrints;
  31. var kEq, kCar, kCdr, kCond, kAtom, kCons, kQuote, kDefine;
  32. function Get(i) {
  33. ++cGets;
  34. return M[Null + i];
  35. }
  36. function Set(i, x) {
  37. ++cSets;
  38. M[Null + i] = x;
  39. }
  40. function Car(x) {
  41. if (x > 0) Throw(List(kCar, x));
  42. return x ? Get(x) : +0;
  43. }
  44. function Cdr(x) {
  45. if (x > 0) Throw(List(kCdr, x));
  46. return x ? Get(x + 1) : -0;
  47. }
  48. function Cons(car, cdr) {
  49. if (cx == -Null) Throw(kCons);
  50. Set(--cx, cdr);
  51. Set(--cx, car);
  52. if (cx < cHeap) cHeap = cx;
  53. return cx;
  54. }
  55. function Probe(h, p) {
  56. return (h + p * p) & (Null / 2 - 1);
  57. }
  58. function Hash(h, x) {
  59. return (((h + x) * 3083 + 3191) >> 4) & (Null / 2 - 1);
  60. }
  61. function Intern(x, y, h, p) {
  62. if (x == Get(h) && y == Get(h + Null / 2)) return h;
  63. if (Get(h)) return Intern(x, y, Probe(h, p), p + 1);
  64. Set(h, x);
  65. Set(h + Null/2, y);
  66. return h;
  67. }
  68. function ReadAtom() {
  69. var x, y;
  70. ax = y = 0;
  71. do x = ReadChar();
  72. while (x <= Ord(' '));
  73. if (x > Ord(')') && dx > Ord(')')) y = ReadAtom();
  74. return Intern(x, y, (ax = Hash(x, ax)), 1);
  75. }
  76. function ReadList() {
  77. var x, y;
  78. if ((x = Read()) > 0) {
  79. if (Get(x) == Ord(')')) return -0;
  80. if (Get(x) == Ord('.') && !Get(x + 1)) {
  81. x = Read();
  82. y = ReadList();
  83. if (!y) {
  84. return x;
  85. } else {
  86. Throw(y);
  87. }
  88. }
  89. }
  90. return Cons(x, ReadList());
  91. }
  92. function Read() {
  93. var t;
  94. ++cReads;
  95. t = ReadAtom();
  96. if (Get(t) != Ord('(')) return t;
  97. return ReadList();
  98. }
  99. function PrintAtom(x) {
  100. do PrintChar(Get(x));
  101. while ((x = Get(x + Null / 2)));
  102. }
  103. function PrintList(x) {
  104. PrintChar(Ord('('));
  105. if (x < 0) {
  106. Print(Car(x));
  107. while ((x = Cdr(x))) {
  108. if (panic && cPrints > panic) {
  109. PrintChar(Ord(' '));
  110. PrintChar(0x2026);
  111. break;
  112. }
  113. if (x < 0) {
  114. PrintChar(Ord(' '));
  115. Print(Car(x));
  116. } else {
  117. PrintChar(Ord(' '));
  118. PrintChar(Ord('.'));
  119. PrintChar(Ord(' '));
  120. Print(x);
  121. break;
  122. }
  123. }
  124. }
  125. PrintChar(Ord(')'));
  126. }
  127. function Print(x) {
  128. ++cPrints;
  129. if (1./x < 0) {
  130. PrintList(x);
  131. } else {
  132. PrintAtom(x);
  133. }
  134. }
  135. function List(x, y) {
  136. return Cons(x, Cons(y, -0));
  137. }
  138. function Gc(A, x) {
  139. var C, B = cx;
  140. x = Copy(x, A, A - B), C = cx;
  141. while (C < B) Set(--A, Get(--B));
  142. return cx = A, x;
  143. }
  144. function Evcon(c, a) {
  145. if (c >= 0) Throw(kCond);
  146. if (Eval(Car(Car(c)), a)) {
  147. return Eval(Car(Cdr(Car(c))), a);
  148. } else {
  149. return Evcon(Cdr(c), a);
  150. }
  151. }
  152. function Peel(x, a) {
  153. return a && x == Car(Car(a)) ? Cdr(a) : a;
  154. }
  155. function Copy(x, m, k) {
  156. return x < m ? Cons(Copy(Car(x), m, k),
  157. Copy(Cdr(x), m, k)) + k : x;
  158. }
  159. function Evlis(m, a) {
  160. return m ? Cons(Eval(Car(m), a),
  161. Evlis(Cdr(m), a)) : m;
  162. }
  163. function Pairlis(x, y, a) {
  164. return x ? Cons(Cons(Car(x), Car(y)),
  165. Pairlis(Cdr(x), Cdr(y),
  166. Peel(Car(x), a))) : a;
  167. }
  168. function Assoc(x, y) {
  169. if (!y) Throw(x);
  170. return x == Car(Car(y)) ? Cdr(Car(y)) : Assoc(x, Cdr(y));
  171. }
  172. function Apply(f, x, a) {
  173. if (f < 0) return Eval(Car(Cdr(Cdr(f))), Pairlis(Car(Cdr(f)), x, a));
  174. if (f == kCons) return Cons(Car(x), Car(Cdr(x)));
  175. if (f == kEq) return Car(x) == Car(Cdr(x));
  176. if (f == kAtom) return Car(x) >= 0;
  177. if (f == kCar) return Car(Car(x));
  178. if (f == kCdr) return Cdr(Car(x));
  179. return funcall(cx, f, Assoc(f, a), x, a);
  180. }
  181. function Eval(e, a) {
  182. if (!e) return e;
  183. if (e > 0) return Assoc(e, a);
  184. if (Car(e) == kQuote) return Car(Cdr(e));
  185. if (Car(e) == kCond) return Evcon(Cdr(e), a);
  186. return Apply(Car(e), Evlis(Cdr(e), a), a);
  187. }
  188. function Funcall(A, f, l, x, a) {
  189. return Gc(A, Apply(l, x, a));
  190. }
  191. function Funtrace(A, f, l, x, a) {
  192. var y;
  193. Indent(depth);
  194. Print(f);
  195. Print(x);
  196. PrintChar(Ord('\n'));
  197. depth += 2;
  198. y = Funcall(cx, f, l, x, a);
  199. depth -= 2;
  200. Indent(depth);
  201. Print(f);
  202. Print(x);
  203. PrintChar(Ord(' '));
  204. PrintChar(0x2192);
  205. PrintChar(Ord(' '));
  206. Print(y);
  207. PrintChar(Ord('\n'));
  208. return y;
  209. }
  210. function Indent(i) {
  211. if (i) {
  212. PrintChar(Ord(' '));
  213. Indent(i - 1);
  214. }
  215. }
  216. function DumpAlist(a) {
  217. PrintChar(Ord('('));
  218. PrintChar(Ord('\n'));
  219. for (;a ;a = Cdr(a)) {
  220. PrintChar(Ord('('));
  221. Print(Car(Car(a)));
  222. PrintChar(Ord(' '));
  223. PrintChar(Ord('.'));
  224. PrintChar(Ord(' '));
  225. Print(Cdr(Car(a)));
  226. PrintChar(Ord(')'));
  227. PrintChar(Ord('\n'));
  228. }
  229. PrintChar(Ord(')'));
  230. }
  231. function DumpDefines(a) {
  232. if (a) {
  233. DumpDefines(Cdr(a));
  234. PrintChar(Ord('('));
  235. Print(kDefine);
  236. PrintChar(Ord(' '));
  237. Print(Car(Car(a)));
  238. PrintChar(Ord(' '));
  239. PrintChar(Ord('.'));
  240. PrintChar(Ord(' '));
  241. Print(Cdr(Car(a)));
  242. PrintChar(Ord(')'));
  243. PrintChar(Ord('\n'));
  244. }
  245. }
  246. function LoadBuiltins() {
  247. Read();
  248. Read();
  249. kEq = Read();
  250. kCar = Read();
  251. kCdr = Read();
  252. kAtom = Read();
  253. kCond = Read();
  254. kCons = Read();
  255. kQuote = Read();
  256. kDefine = Read();
  257. }
  258. function Crunch(e, B) {
  259. var x, y, i;
  260. if (e >= 0) return e;
  261. x = Crunch(Car(e), B);
  262. y = Crunch(Cdr(e), B);
  263. for (i = B - 2; i >= cx; i -= 2) {
  264. if (x == Car(i) &&
  265. y == Cdr(i)) {
  266. return i - B;
  267. }
  268. }
  269. return Cons(x, y) - B;
  270. }
  271. function Compact(x) {
  272. var C, B = cx, A = 0;
  273. x = Crunch(x, B), C = cx;
  274. while (C < B) Set(--A, Get(--B));
  275. return cx = A, x;
  276. }
  277. function Remove(x, y) {
  278. if (!y) return y;
  279. if (x == Car(Car(y))) return Cdr(y);
  280. return Cons(Car(y), Remove(x, Cdr(y)));
  281. }
  282. function Define(x, a) {
  283. return Compact(Cons(x, Remove(Car(x), a)));
  284. }
  285. //
`
  286. ////////////////////////////////////////////////////////////////////////////////
  287. // ANSI POSIX C Specific Code
  288. Ord(c) {
  289. return c;
  290. }
  291. Throw(x) {
  292. if (fail < 255) ++fail;
  293. longjmp(undefined, ~x);
  294. }
  295. PrintChar(b) {
  296. fputwc(b, stdout);
  297. }
  298. SaveAlist(a) {
  299. }
  300. ReadChar() {
  301. int b, c, t;
  302. static char *freeme;
  303. static char *line = "NIL T EQ CAR CDR ATOM COND CONS QUOTE DEFINE ";
  304. if (line || (line = freeme = bestlineWithHistory("* ", "sectorlisp"))) {
  305. if (*line) {
  306. c = *line++ & 0377;
  307. if (c >= 0300) {
  308. for (b = 0200; c & b; b >>= 1) c ^= b;
  309. while ((*line & 0300) == 0200) {
  310. c <<= 6;
  311. c |= *line++ & 0177;
  312. }
  313. }
  314. } else {
  315. free(freeme);
  316. freeme = 0;
  317. line = 0;
  318. c = '\n';
  319. }
  320. t = dx;
  321. dx = c;
  322. return t;
  323. } else {
  324. exit(fail);
  325. }
  326. }
  327. main(argc, argv)
  328. char *argv[];
  329. {
  330. var x, a, A;
  331. setlocale(LC_ALL, "");
  332. bestlineSetXlatCallback(bestlineUppercase);
  333. funcall = Funcall;
  334. for (x = 1; x < argc; ++x) {
  335. if (argv[x][0] == '-' && argv[x][1] == 't') {
  336. funcall = Funtrace;
  337. } else {
  338. fputs("Usage: ", stderr);
  339. fputs(argv[0], stderr);
  340. fputs(" [-t] <input.lisp >errput.lisp\n", stderr);
  341. exit(1);
  342. }
  343. }
  344. LoadBuiltins();
  345. for (a = 0;;) {
  346. A = cx;
  347. if (!(x = setjmp(undefined))) {
  348. x = Read();
  349. if (x < 0 && Car(x) == kDefine) {
  350. a = Define(Cdr(x), a);
  351. SaveAlist(a);
  352. continue;
  353. }
  354. x = Eval(x, a);
  355. } else {
  356. x = ~x;
  357. PrintChar('?');
  358. }
  359. Print(x);
  360. PrintChar('\n');
  361. Gc(A, 0);
  362. }
  363. }
  364. #if 0
  365. //`
  366. ////////////////////////////////////////////////////////////////////////////////
  367. // JavaScript Specific Code for https://justine.lol/
  368. var a, code, index, output, funcall, M, Null;
  369. var eOutput, eEval, eReset, eLoad, eTrace, ePrograms, eDump;
  370. var eGets, eSets, eMs, eAtoms, eCode, eHeap, eReads, eWrites, eClear;
  371. function Throw(x) {
  372. throw x;
  373. }
  374. function Reset() {
  375. var i;
  376. a = 0;
  377. cx = 0;
  378. cHeap = 0;
  379. cGets = 0;
  380. cSets = 0;
  381. cReads = 0;
  382. cPrints = 0;
  383. Null = 16384;
  384. M = new Array(Null * 2);
  385. // for (i = 0; i < M.length; ++i) {
  386. // M[i] = 0; /* make json smaller */
  387. // }
  388. Load("NIL T EQ CAR CDR ATOM COND CONS QUOTE DEFINE ");
  389. LoadBuiltins()
  390. }
  391. function PrintU16(c) {
  392. output += String.fromCharCode(c);
  393. }
  394. function IsHighSurrogate(c) {
  395. return (0xfc00 & c) == 0xd800;
  396. }
  397. function IsLowSurrogate(c) {
  398. return (0xfc00 & c) == 0xdc00;
  399. }
  400. function GetHighSurrogate(c) {
  401. return ((c - 0x10000) >> 10) + 0xD800;
  402. }
  403. function GetLowSurrogate(c) {
  404. return ((c - 0x10000) & 1023) + 0xDC00;
  405. }
  406. function ComposeUtf16(c, d) {
  407. return ((c - 0xD800) << 10) + (d - 0xDC00) + 0x10000;
  408. }
  409. function PrintChar(c) {
  410. if (c < 0x10000) {
  411. PrintU16(c);
  412. } else if (c < 0x110000) {
  413. PrintU16(GetHighSurrogate(c));
  414. PrintU16(GetLowSurrogate(c));
  415. } else {
  416. PrintU16(0xFFFD);
  417. }
  418. }
  419. function Ord(s) {
  420. var c, d;
  421. c = s.charCodeAt(0);
  422. if (IsHighSurrogate(c)) {
  423. if (code.length > 1 && IsLowSurrogate((d = s.charCodeAt(1)))) {
  424. c = ComposeUtf16(c, d);
  425. } else {
  426. c = 0xFFFD;
  427. }
  428. } else if (IsLowSurrogate(c)) {
  429. c = 0xFFFD;
  430. }
  431. return c;
  432. }
  433. function ReadChar() {
  434. var c, d, t;
  435. if (code.length) {
  436. if (index < code.length) {
  437. c = code.charCodeAt(index++);
  438. if (IsHighSurrogate(c)) {
  439. if (index < code.length &&
  440. IsLowSurrogate((d = code.charCodeAt(index)))) {
  441. c = ComposeUtf16(c, d), ++index;
  442. } else {
  443. c = 0xFFFD;
  444. }
  445. } else if (IsLowSurrogate(c)) {
  446. c = 0xFFFD;
  447. }
  448. } else {
  449. code = "";
  450. c = 0;
  451. }
  452. t = dx;
  453. dx = c;
  454. return t;
  455. } else {
  456. Throw(0);
  457. }
  458. }
  459. function Lisp() {
  460. var x, A, d, t;
  461. d = 0;
  462. cGets = 0;
  463. cSets = 0;
  464. cHeap = cx;
  465. cReads = 0;
  466. cPrints = 0;
  467. output = "";
  468. while (dx) {
  469. if (dx <= Ord(' ')) {
  470. ReadChar();
  471. } else {
  472. t = GetMillis();
  473. A = cx;
  474. try {
  475. x = Read();
  476. if (x < 0 && Car(x) == kDefine) {
  477. a = Define(Cdr(x), a);
  478. continue;
  479. }
  480. x = Eval(x, a);
  481. } catch (z) {
  482. PrintChar(Ord('?'));
  483. x = z;
  484. }
  485. Print(x);
  486. PrintChar(Ord('\n'));
  487. Gc(A, 0);
  488. d += GetMillis() - t;
  489. }
  490. }
  491. eOutput.innerText = output;
  492. SaveAlist(a);
  493. SaveOutput();
  494. ReportUsage(d);
  495. }
  496. function Load(s) {
  497. index = 0;
  498. dx = Ord(' ');
  499. code = s + "\n";
  500. }
  501. function OnEval() {
  502. Load(g_editor.getValue());
  503. Lisp();
  504. SetStorage("input", g_editor.getValue());
  505. }
  506. function OnBeforeUnload() {
  507. SetStorage("input", g_editor.getValue());
  508. }
  509. function OnDump() {
  510. var t;
  511. output = "";
  512. t = GetMillis();
  513. DumpDefines(a);
  514. eOutput.innerText = output;
  515. t = GetMillis() - t;
  516. SaveOutput();
  517. ReportUsage(t);
  518. }
  519. function OnReset(e) {
  520. var t;
  521. output = "";
  522. t = GetMillis();
  523. try {
  524. if (!e.shiftKey) DumpDefines(a);
  525. eOutput.innerText = output;
  526. Reset();
  527. } catch (e) {
  528. /* ignored */
  529. }
  530. t = GetMillis() - t;
  531. RemoveStorage("alist");
  532. SaveOutput();
  533. ReportUsage(t);
  534. }
  535. function OnClear() {
  536. output = "";
  537. eOutput.innerText = output;
  538. SaveOutput();
  539. ReportUsage(0);
  540. }
  541. function OnTrace() {
  542. var t;
  543. Load(g_editor.getValue());
  544. t = panic;
  545. depth = 0;
  546. panic = 10000;
  547. funcall = Funtrace;
  548. Lisp();
  549. funcall = Funcall;
  550. panic = t;
  551. }
  552. function OnLoad() {
  553. if (ePrograms.className == "dropdown-content") {
  554. ePrograms.className = "dropdown-content show";
  555. } else {
  556. ePrograms.className = "dropdown-content";
  557. }
  558. }
  559. function OnWindowClick(e) {
  560. if (e.target && !e.target.matches("#load")) {
  561. ePrograms.className = "dropdown-content";
  562. }
  563. }
  564. function OnWindowKeyDown(e) {
  565. if (e.key == "Escape") {
  566. ePrograms.className = "dropdown-content";
  567. }
  568. }
  569. function SaveAlist(a) {
  570. output = "";
  571. DumpAlist(a);
  572. SetStorage("alist", output);
  573. }
  574. function RestoreMachine() {
  575. var v;
  576. if ((v = GetStorage("output"))) {
  577. eOutput.innerText = v;
  578. }
  579. if ((v = GetStorage("input"))) {
  580. g_editor.setValue(v);
  581. }
  582. if ((v = GetStorage("alist"))) {
  583. Reset();
  584. Load(v);
  585. a = Compact(Read());
  586. } else if ((v = JSON.parse(GetStorage("machine")))) {
  587. M = v[0];
  588. a = v[1];
  589. cx = v[2];
  590. cHeap = cx;
  591. }
  592. }
  593. function SaveOutput() {
  594. SetStorage("input", g_editor.getValue());
  595. SetStorage("output", eOutput.innerText);
  596. }
  597. function FormatInt(i) {
  598. return i.toLocaleString();
  599. }
  600. function FormatDuration(d) {
  601. return d ? Math.round(d * 1000) / 1000 : 0;
  602. }
  603. function ReportUsage(ms) {
  604. var i, atom, code, heap;
  605. code = -cx >> 1;
  606. heap = -cHeap >> 1;
  607. for (atom = i = 0; i < Null / 2; ++i) {
  608. if (M[Null + i]) ++atom;
  609. }
  610. if (eGets) eGets.innerText = FormatInt(cGets);
  611. if (eSets) eSets.innerText = FormatInt(cSets);
  612. if (eMs) eMs.innerText = FormatInt(ms);
  613. if (eAtoms) eAtoms.innerText = FormatInt(atom);
  614. if (eCode) eCode.innerText = FormatInt(code);
  615. if (eHeap) eHeap.innerText = FormatInt(heap - code);
  616. if (eReads) eReads.innerText = FormatInt(cReads);
  617. if (ePrints) ePrints.innerText = FormatInt(cPrints);
  618. }
  619. function Discount(f) {
  620. return function() {
  621. var x, g, h, s;
  622. g = cGets;
  623. s = cSets;
  624. h = cHeap;
  625. x = f.apply(this, arguments);
  626. cHeap = h;
  627. cSets = s;
  628. cGets = g;
  629. return x;
  630. };
  631. }
  632. function GetMillis() {
  633. if (typeof performance != "undefined") {
  634. return performance.now();
  635. } else {
  636. return 0;
  637. }
  638. }
  639. function GetStorage(k) {
  640. if (typeof localStorage != "undefined") {
  641. return localStorage.getItem(g_lisp + "." + k);
  642. } else {
  643. return null;
  644. }
  645. }
  646. function RemoveStorage(k) {
  647. if (typeof localStorage != "undefined") {
  648. localStorage.removeItem(g_lisp + "." + k);
  649. }
  650. }
  651. function SetStorage(k, v) {
  652. if (typeof localStorage != "undefined") {
  653. localStorage.setItem(g_lisp + "." + k, v);
  654. }
  655. }
  656. function SetUp() {
  657. funcall = Funcall;
  658. Read = Discount(Read);
  659. Print = Discount(Print);
  660. Define = Discount(Define);
  661. eLoad = document.getElementById("load");
  662. eReset = document.getElementById("reset");
  663. eTrace = document.getElementById("trace");
  664. eOutput = document.getElementById("output");
  665. eEval = document.getElementById("eval");
  666. eClear = document.getElementById("clear");
  667. eDump = document.getElementById("dump");
  668. ePrograms = document.getElementById("programs");
  669. eGets = document.getElementById("cGets");
  670. eSets = document.getElementById("cSets");
  671. eMs = document.getElementById("cMs");
  672. eAtoms = document.getElementById("cAtoms");
  673. eCode = document.getElementById("cCode");
  674. eHeap = document.getElementById("cHeap");
  675. eReads = document.getElementById("cReads");
  676. ePrints = document.getElementById("cPrints");
  677. window.onkeydown = OnWindowKeyDown;
  678. if (window.onbeforeunload) window.onbeforeunload = OnBeforeUnload;
  679. if (ePrograms) window.onclick = OnWindowClick;
  680. if (eLoad) eLoad.onclick = OnLoad;
  681. if (eReset) eReset.onclick = OnReset;
  682. if (eTrace) eTrace.onclick = OnTrace;
  683. if (eEval) eEval.onclick = OnEval;
  684. if (eDump) eDump.onclick = OnDump;
  685. if (eClear) eClear.onclick = OnClear;
  686. }
  687. //
`
  688. #endif
  689. //`