lisp.js 15 KB

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