unbyte.red 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603
  1. lisp;
  2. linelength 72;
  3. on comp, backtrace;
  4. in "struct.red"$
  5. fluid '(all_jumps);
  6. %
  7. % "unbyte" is the main body of the decoder
  8. %
  9. fluid '(!@a !@b !@w !@stack !@catch);
  10. global '(opnames);
  11. symbolic procedure unbyte name;
  12. begin
  13. scalar pc, code, len, env, byte, r, entry_stack,
  14. w, w1, w2, args, nargs, stack, deepest, locals,
  15. all_jumps, !@a, !@b, !@w, !@stack, !@catch;
  16. !@a := gensym(); !@b := gensym(); !@w := gensym(); !@stack := gensym();
  17. code := symbol!-env name;
  18. nargs := symbol!-argcount name;
  19. if atom code or not bpsp car code then return nil;
  20. env := cdr code;
  21. code := car code;
  22. len := bps!-upbv code;
  23. % If the function has 4 or more arge then the first byte of the bytestream
  24. % says just how many. If it has &optional and/or &rest support the first
  25. % two bytes give information on the largest and smallest valid number of
  26. % args.
  27. if fixp nargs then
  28. << entry_stack := nargs;
  29. if nargs < 4 then pc := 0 else pc := 1 >>
  30. else <<
  31. entry_stack := cadr nargs;
  32. if logand(caddr nargs, 2) neq 0 then entry_stack := entry_stack+1;
  33. pc := 2 >>;
  34. % The first stage will be to unpick the byte-stream into at least some sort
  35. % of more spread-out data structure, recognising the lengths of various
  36. % instructions. The output I will collect will be a list where each item is
  37. % of the form
  38. % (address nil s-expression-1 s-expression-1 ...)
  39. % with stack operands shown as (stack nn) and label operands as numeric
  40. % offsets. Subsequent passes will use the field that is initially set as
  41. % nil to help me decide where labels should be set and I will need to
  42. % convert data references from being relative to the top of the stack into
  43. % being relative to a known stack-base.
  44. r := nil;
  45. all_jumps := list(nil, pc); % Force label on entrypoint
  46. while pc <= len do <<
  47. byte := bps!-getv(code, pc);
  48. w := funcall(getv(opnames, byte), pc+1, code, env);
  49. % If the previous instruction had been a branch (marked here as an IF
  50. % statement) then I would have indicated a jump to an explicit label as
  51. % the ELSE part and I want to set the label concerned on whatever follows.
  52. % The stacked-up IF is stored as
  53. % (address label (IF cond dest (GO ggg)))
  54. % where ggg is what I want.
  55. if r then w1 := caddr car r
  56. else w1 := nil;
  57. if eqcar(w1, 'if) then
  58. r := (pc . cadr cadddr w1 . cdr w) . r
  59. else r := (pc . nil . cdr w) . r;
  60. pc := pc + car w >>;
  61. % All jumps in the code will have been represented as
  62. % (if xxx (go xx) (go yy))
  63. % but in the first pass I can not have these resolved as symbolic labels.
  64. % To begin with xx will be a numeric address, and the items (go xx) will be
  65. % cahined through their CAR fields (so the 'go is not present yet). The
  66. % (go yy) will have a symbolic label for yy and this must be set on the
  67. % instruction immediately after then goto.
  68. while all_jumps do <<
  69. w := assoc(cadr all_jumps, r); % The branch destination
  70. if null w then error(1, "Branch destination not found");
  71. if null cadr w then rplaca(cdr w, gensym());
  72. rplaca(cdr all_jumps, cadr w);
  73. w := car all_jumps;
  74. rplaca(all_jumps, 'go);
  75. all_jumps := w >>;
  76. % Now jumps are under control I will consolidate the entire decoded mess into
  77. % a collection of basic blocks, keyed by labels. At this stage it is
  78. % possible for a block not to have any explicit branch at its end. I want to
  79. % change that so that every block does end in an explicit jump or exit. The
  80. % cases I will recognise are:
  81. % (if ...)
  82. % (go ..)
  83. % (return ..)
  84. % (throw) and maybe some others that I am not worrying about yet
  85. w := nil;
  86. while r do <<
  87. w1 := cddar r;
  88. w2 := w1;
  89. while cdr w2 do w2 := cdr w2;
  90. w2 := car w2; % Final instruction in this block
  91. % Append GO to drop through, if necessary
  92. if w and not (
  93. eqcar(w2, 'if) or
  94. eqcar(w2, 'go) or
  95. eqcar(w2, 'return) or
  96. eqcar(w2, 'throw)) then <<
  97. w1 := append(w1, list list('go, caar w)) >>;
  98. while null cadar r do <<
  99. r := cdr r;
  100. w1 := append(cddar r, w1) >>;
  101. w := (cadar r . nil . w1) . w;
  102. r := cdr r >>;
  103. % The next thing I have to do is to link FREERSTR opcodes up with the
  104. % FREEBIND opcodes that they belong to. I NEED to do this early on
  105. % because a FREEBIND and its FREERSTR move the stack up or down by
  106. % an amount dependent on the number of variables being bound. For FREEBIND
  107. % this is instantly visible, but for FREERSTR the information is only
  108. % available by determining which FREEBIND it matches. But finding this
  109. % out should be OK since every FREERSTR should correspond to exactly one
  110. % FREEBIND. Because there should be no ambiguity at all about matching
  111. % binds with restores I can have a fairly simple version of data flow
  112. % analysis to make the link-up.
  113. rplaca(cdar w, list nil); % No free bindings at entry-point
  114. r := list caar w; % pending blocks
  115. while r do begin
  116. scalar n;
  117. w1 := assoc(car r, w);
  118. r := cdr r;
  119. n := caadr w1;
  120. for each z in cddr w1 do <<
  121. if eqcar(z, 'freebind) then n := cadr z . n
  122. else if eqcar(z, 'freerstr) then <<
  123. rplaca(cdr z, car n);
  124. n := cdr n >>
  125. else if eqcar(z, 'if) then <<
  126. r := set_bind(assoc(cadr caddr z, w), r, n);
  127. r := set_bind(assoc(cadr cadddr z, w), r, n) >>
  128. else if eqcar(z, 'go) then
  129. r := set_bind(assoc(cadr z, w), r, n) >>
  130. end;
  131. % Blocks are now in order with the starting basic block at the top of
  132. % the list (w). Each block is (label flag contents..) where the flag is nil
  133. % at present. I will traverse the collection of blocks replacing the nils
  134. % with the stack depth in force at the start of each block. This gives
  135. % me a chance to detect inconsistencies in this area, but is also
  136. % a vital prelude to replacing stack references with names.
  137. for each z in w do rplaca(cdr z, nil);
  138. rplaca(cdar w, entry_stack); % stack depth for entry block
  139. deepest := entry_stack;
  140. r := list caar w; % list of "pending" blocks
  141. while r do begin
  142. scalar n;
  143. w1 := assoc(car r, w);
  144. if null w1 then <<
  145. prin car r; princ " not found in "; print w;
  146. error(1, r) >>;
  147. r := cdr r;
  148. n := cadr w1;
  149. if n > deepest then deepest := n;
  150. for each z in cddr w1 do <<
  151. if z = 'push then n := n + 1
  152. else if z = 'lose then n := n - 1
  153. else if eqcar(z, 'freebind) then n := n + 2 + length cadr z
  154. else if z = 'pvbind then n := n + 2
  155. else if eqcar(z, 'freerstr) then n := n - 2 - length cadr z
  156. else if z = 'pvrestore then n := n - 2
  157. else if z = 'uncatch or z = 'unprotect then n := n - 3
  158. else if eqcar(z, 'if) then <<
  159. if eqcar(cadr z, !@catch) then <<
  160. n := n+3;
  161. rplaca(z, 'ifcatch) >>;
  162. r := set_stack(assoc(cadr caddr z, w), r, n);
  163. r := set_stack(assoc(cadr cadddr z, w), r, n) >>
  164. else if eqcar(z, 'go) then
  165. r := set_stack(assoc(cadr z, w), r, n);
  166. if n < entry_stack then error(1, "Too many POPs in the codestream")
  167. else if n > deepest then deepest := n >>
  168. end;
  169. % Now I want three separate things. One is the list of formal arguments
  170. % to be put in a procedure header. This must contain annotations such as
  171. % &optional and &rest where relevant. The other is a map of the stack.
  172. % this will include all arguments, but without &optional etc. The final thing
  173. % will be a list of local variables required for this procedure. This
  174. % will include all the stack items not present as arguments together with
  175. % the workspace items !@a, !@b and !@w.
  176. args := stack := locals := nil;
  177. if fixp nargs then <<
  178. for i := 1:nargs do stack := gensym() . stack;
  179. args := reverse stack >>
  180. else <<
  181. for i := 1:car nargs do stack := gensym() . stack;
  182. args := stack;
  183. if not (cadr nargs = car nargs) then <<
  184. args := '!&optional . args;
  185. for i := car nargs+1:cadr nargs do <<
  186. w1 := gensym();
  187. stack := w1 . stack;
  188. if logand(caddr nargs, 1) = 0 then args := w1 . args
  189. else args := list(w1, ''!*spid!*) . args >>;
  190. if logand(caddr nargs, 2) neq 0 then <<
  191. w1 := gensym();
  192. stack := w1 . stack;
  193. args := w1 . '!&rest . args >> >>;
  194. args := reverse args >>;
  195. locals := list(!@a, !@b, !@w);
  196. for i := 1+length stack:deepest do locals := gensym() . locals;
  197. % Now if I find a reference to a location (!@stack n) at a stage when
  198. % the logical stack depth is m I can map it onto a reference to a simple
  199. % variable - either a local or one of the arguments. The code in
  200. % stackref knows how to do this.
  201. for each b in w do begin
  202. scalar m, z1;
  203. m := cadr b;
  204. if not fixp m then error(1, "Unreferenced code block");
  205. for each z in cddr b do <<
  206. if z = 'push then m := m + 1
  207. else if z = 'lose then m := m - 1
  208. else if eqcar(z, 'freebind) then m := m + 2 + length cadr z
  209. else if z = 'pvbind then m := m + 2
  210. else if eqcar(z, 'freerstr) then m := m - 2 - length cadr z
  211. else if z = 'pvrestore then m := m - 2
  212. else if z = 'uncatch or z = 'unprotect then m := m - 3
  213. else <<
  214. z1 := stackref(z, m, stack, locals, entry_stack);
  215. rplaca(z, car z1); rplacd(z, cdr z1) >> >>;
  216. end;
  217. % Now is the time to deal with constructs that include matching
  218. % pairs of byte-opcodes that must be brought together in the reconstructed
  219. % Lisp code. The cases that arise are
  220. % FREEBIND(data); ... FREERSTR
  221. % which must map onto
  222. % (prog (vars) ...)
  223. % and note that there could be several places where the FREERSTR
  224. % is present - these can correspond to places where the original
  225. % code contained a RETURN or a GO that exited from the scope
  226. % of the fluid binding. Since at the level I am working here
  227. % values are passed in the !@a variable I do not need to distinguish
  228. % these cases too specially and reconstruct clever arguments for
  229. % a RETURN. If there is just one exit point from the reconstructed
  230. % block I may as well use RETURN but it is not vital.
  231. %
  232. % CATCH(label); ....UNCATCH; label: ...
  233. % the label mentioned in the CATCH ought always to be the one
  234. % just after an UNCATCH. There can be other UNCATCH statements
  235. % on branches through the code that represent lexical exits from the
  236. % protected region (eg GO or RETURN). Distinguishing between
  237. % exits of this sort that represent GO and those that are RETURN
  238. % seems un-obvious but is a similar issue to the case with FREEBIND
  239. % and so perhaps does not matter too much.
  240. % (catch !@a ... (go label)) label:
  241. %
  242. % PVBIND; ... PVRESTORE
  243. % this is for
  244. % (progv !@a !@b ...)
  245. % teh compiler arranges for PVRESTOREs to be placed on every exit
  246. % from the funny region, and so arguments similar to those for
  247. % FREEBIND and CATCH apply about multiple exits.
  248. %
  249. % (setq @a (load-spid)) CATCH(label); ... PROTECT; label: ... UNPROTECT
  250. % the CATCH used here is passed the result from the builtin function
  251. % (load-spid), which obtains a value that would not be valid as a
  252. % proper catch tag. The purpose of the PROTECT and UNPROTECT is
  253. % to delimit the cleanup forms and so indicate that a proper
  254. % value from the main protected form should survive across
  255. % that region.
  256. % Any lexical (eg GO or RETURN) exit from the protected region
  257. % will have the sequence PROTECT cleanup-forms UNPROTECT inserted
  258. % along the path. Lexical exits from the region between PROTECT
  259. % and UNPROTECT are possible and will just LOSE three items from
  260. % the stack on the way, thereby discarding the way in which
  261. % the execution of UNPROTECT would have re-instated the exit
  262. % values and condition from the protected region.
  263. %
  264. w := fix_free_bindings w; % Ignore catch, unwind-protect, progv for now.
  265. w := optimise_blocks(w, stack, locals);
  266. r := 'prog . locals . flowgraph_to_lisp w;
  267. terpri(); princ "=> "; prettyprint r;
  268. w := errorset(list('structchk, mkquote r), t, t);
  269. if not atom w then r := car w;
  270. r := list('de, name, args, r);
  271. terpri(); princ "Finally: ";
  272. prettyprint r;
  273. return nil
  274. end;
  275. symbolic procedure flowgraph_to_lisp w;
  276. begin
  277. scalar r;
  278. for each i in w do <<
  279. r := car i . r;
  280. for each j in cddr i do <<
  281. if eqcar(j, 'prog) then
  282. r := ('prog . cadr j . flowgraph_to_lisp cddr j) . r
  283. % I convert from IF into COND because that will interact better with the
  284. % re-structuring code that is used later on.
  285. else if eqcar(j, 'if) then
  286. r := list('cond, list(cadr j, caddr j),
  287. list('t, cadddr j)) . r
  288. else if eqcar(j, 'freerstr) or
  289. eqcar(j, 'progexits) then nil
  290. else if not member(j, '(push lose)) then r := j . r >> >>;
  291. return reversip r
  292. end;
  293. symbolic procedure set_stack(block, r, n);
  294. if null cadr block then <<
  295. rplaca(cdr block, n);
  296. car block . r >>
  297. else if not (cadr block = n) then <<
  298. printc "++++ Stack confusion";
  299. prin n; princ " vs. "; print block;
  300. r >>
  301. else r;
  302. symbolic procedure set_bind(block, r, n);
  303. if null cadr block then <<
  304. rplaca(cdr block, list n);
  305. car block . r >>
  306. else if not (caadr block = n) then <<
  307. printc "++++ Binding confusion";
  308. prin n; princ " vs. "; print block;
  309. r >>
  310. else r;
  311. symbolic procedure stackref(u, m, stack, locals, entry_stack);
  312. if atom u or eqcar(u, 'quote) then u
  313. else if eqcar(u, !@stack) then begin
  314. scalar n, x;
  315. n := cadr u;
  316. x := n - m + entry_stack;
  317. if x >= 0 then <<
  318. if x >= entry_stack then error(1, "Reference outside stack-frame");
  319. for i := 1:x do stack := cdr stack;
  320. return car stack >>
  321. else <<
  322. for i := 1:-(x+1) do locals := cdr locals;
  323. return car locals >> end
  324. else for each x in u collect
  325. stackref(x, m, stack, locals, entry_stack);
  326. opnames := mkvect 255$
  327. % The table that follows lists the various opcodes that are used here.
  328. % Each of these must be decoded, and the irregularity of the "machine"
  329. % involved will leave this process rather untidy. For instance opcodes
  330. % with similar actions are grouped together here but addressing modes are
  331. % not at all consistently supported. This irregularity is not an accident:
  332. % it is a consequence of attempting to keep code sequences as short as
  333. % convenient.
  334. %-- LOADLOC general opcode to load from the stack
  335. %-- LOADLOC0 LOADLOC1 LOADLOC2 LOADLOC3 specific offsets
  336. %-- LOADLOC4 LOADLOC5 LOADLOC6 LOADLOC7
  337. %-- LOADLOC8 LOADLOC9 LOADLOC10 LOADLOC11
  338. %-- combinations to load two values (especially common cases)
  339. %-- LOC0LOC1 LOC1LOC2 LOC2LOC3
  340. %-- LOC1LOC0 LOC2LOC1 LOC3LOC2
  341. %--
  342. %-- VNIL load the value NIL
  343. %--
  344. %-- LOADLIT load a literal from the literal vector
  345. %-- LOADLIT1 LOADLIT2 LOADLIT3 specific offsets
  346. %-- LOADLIT4 LOADLIT5 LOADLIT6 LOADLIT7
  347. %--
  348. %-- LOADFREE load value of a free (FLUID/SPECIAL) variable
  349. %-- LOADFREE1 LOADFREE2 LOADFREE3 specific offsets
  350. %-- LOADFREE4
  351. %--
  352. %-- STORELOC Store onto stack
  353. %-- STORELOC0 STORELOC1 STORELOC2 STORELOC3 specific offsets
  354. %-- STORELOC4 STORELOC5 STORELOC6 STORELOC7
  355. %--
  356. %-- STOREFREE Set value of FLUID/SPECIAL variable
  357. %-- STOREFREE1 STOREFREE2 STOREFREE3
  358. %--
  359. %-- LOADLEX access to non-local lexical variables (for Common Lisp)
  360. %-- STORELEX
  361. %-- CLOSURE
  362. %--
  363. %-- Code to access local variables and also take CAR or CDR
  364. %-- CARLOC0 CARLOC1 CARLOC2 CARLOC3
  365. %-- CARLOC4 CARLOC5 CARLOC6 CARLOC7
  366. %-- CARLOC8 CARLOC9 CARLOC10 CARLOC11
  367. %-- CDRLOC0 CDRLOC1 CDRLOC2 CDRLOC3
  368. %-- CDRLOC4 CDRLOC5
  369. %-- CAARLOC0 CAARLOC1 CAARLOC2 CAARLOC3
  370. %--
  371. %-- Function call support
  372. %-- CALL0 CALL1 CALL2 CALL2R CALL3 CALLN
  373. %-- CALL0_0 CALL0_1 CALL0_2 CALL0_3
  374. %-- CALL1_0 CALL1_1 CALL1_2 CALL1_3 CALL1_4 CALL1_5
  375. %-- CALL2_0 CALL2_1 CALL2_2 CALL2_3 CALL2_4
  376. %-- BUILTIN0 BUILTIN1 BUILTIN2 BUILTIN2R BUILTIN3
  377. %-- APPLY1 APPLY2 APPLY3 APPLY4
  378. %-- JCALL JCALLN
  379. %--
  380. %-- Branches. The main collection come in variants with long or short
  381. %-- offsets and with the branch to go fowards or backwards.
  382. %-- JUMP JUMP_B JUMP_L JUMP_BL
  383. %-- JUMPNIL JUMPNIL_B JUMPNIL_L JUMPNIL_BL
  384. %-- JUMPT JUMPT_B JUMPT_L JUMPT_BL
  385. %-- JUMPATOM JUMPATOM_B JUMPATOM_L JUMPATOM_BL
  386. %-- JUMPNATOM JUMPNATOM_B JUMPNATOM_L JUMPNATOM_BL
  387. %-- JUMPEQ JUMPEQ_B JUMPEQ_L JUMPEQ_BL
  388. %-- JUMPNE JUMPNE_B JUMPNE_L JUMPNE_BL
  389. %-- JUMPEQUAL JUMPEQUAL_B JUMPEQUAL_L JUMPEQUAL_BL
  390. %-- JUMPNEQUAL JUMPNEQUAL_B JUMPNEQUAL_L JUMPNEQUAL_BL
  391. %--
  392. %-- The following jumps go forwards only, and by only short offsets. They
  393. %-- are provided to support a collection of common special cases
  394. %-- (a) test local variables for NIl or TRUE
  395. %-- JUMPL0NIL JUMPL0T JUMPL1NIL JUMPL1T
  396. %-- JUMPL2NIL JUMPL2T JUMPL3NIL JUMPL3T
  397. %-- JUMPL4NIL JUMPL4T
  398. %-- (b) store in a local variable and test for NIL or TRUE
  399. %-- JUMPST0NIL JUMPST0T JUMPST1NIL JUMPST1T
  400. %-- JUMPST2NIL JUMPST2T
  401. %-- (c) test if local variable is atomic or not
  402. %-- JUMPL0ATOM JUMPL0NATOM JUMPL1ATOM JUMPL1NATOM
  403. %-- JUMPL2ATOM JUMPL2NATOM JUMPL3ATOM JUMPL3NATOM
  404. %-- (d) test free variable for NIL or TRUE
  405. %-- JUMPFREE1NIL JUMPFREE1T JUMPFREE2NIL JUMPFREE2T
  406. %-- JUMPFREE3NIL JUMPFREE3T JUMPFREE4NIL JUMPFREE4T
  407. %-- JUMPFREENIL JUMPFREET
  408. %-- (e) test for equality (EQ) against literal value
  409. %-- JUMPLIT1EQ JUMPLIT1NE JUMPLIT2EQ JUMPLIT2NE
  410. %-- JUMPLIT3EQ JUMPLIT3NE JUMPLIT4EQ JUMPLIT4NE
  411. %-- JUMPLITEQ JUMPLITNE
  412. %-- (f) call built-in one-arg function and use that as a predicate
  413. %-- JUMPB1NIL JUMPB1T JUMPB2NIL JUMPB2T
  414. %-- (g) flagp with a literal tag
  415. %-- JUMPFLAGP JUMPNFLAGP
  416. %-- (h) EQCAR test against literal
  417. %-- JUMPEQCAR JUMPNEQCAR
  418. %--
  419. %-- CATCH needs something that behaves a bit like a (general) jump.
  420. %-- CATCH CATCH_B CATCH_L CATCH_BL
  421. %-- After a CATCH the stack (etc) needs restoring
  422. %-- UNCATCH THROW PROTECT UNPROTECT
  423. %--
  424. %-- PVBIND PVRESTORE PROGV support
  425. %-- FREEBIND FREERSTR Bind/restore FLUID/SPECIAL variables
  426. %--
  427. %-- Exiting from a procedure, optionally popping the stack a bit
  428. %-- EXIT NILEXIT LOC0EXIT LOC1EXIT LOC2EXIT
  429. %--
  430. %-- General stack management
  431. %-- PUSH PUSHNIL PUSHNIL2 PUSHNIL3 PUSHNILS
  432. %-- POP LOSE LOSE2 LOSE3 LOSES
  433. %--
  434. %-- Exchange A and B registers
  435. %-- SWOP
  436. %--
  437. %-- Various especially havily used Lisp functions
  438. %-- EQ EQCAR EQUAL NUMBERP
  439. %-- CAR CDR CAAR CADR CDAR CDDR
  440. %-- CONS NCONS XCONS ACONS LENGTH
  441. %-- LIST2 LIST2STAR LIST3
  442. %-- PLUS2 ADD1 DIFFERENCE SUB1 TIMES2
  443. %-- GREATERP LESSP
  444. %-- FLAGP GET LITGET
  445. %-- GETV QGETV QGETVN
  446. %--
  447. %-- Support for over-large stack-frames (LOADLOC/STORELOC + lexical access)
  448. %-- BIGSTACK
  449. %-- Support for CALLs where the literal vector has become huge
  450. %-- BIGCALL
  451. %--
  452. %-- An integer-based SWITCH or CASE statement has special support
  453. %-- ICASE
  454. %--
  455. %-- Speed-up support for compiled GET and FLAGP when tag is important
  456. %-- FASTGET
  457. %--
  458. %-- Opcodes that have not yet been allocated.
  459. %-- SPARE1
  460. %-- SPARE2
  461. %--
  462. in "../cslbase/opcodes.red";
  463. begin
  464. scalar w;
  465. w := s!:opcodelist;
  466. for i := 0:255 do <<
  467. putv(opnames, i, compress('h . '!! . '!: . explode car w));
  468. w := cdr w >>
  469. end;
  470. global '(builtin0 builtin1 builtin2 builtin3);
  471. builtin0 := mkvect 255$
  472. builtin1 := mkvect 255$
  473. builtin2 := mkvect 255$
  474. builtin3 := mkvect 255$
  475. for each x in oblist() do
  476. begin scalar w;
  477. if (w := get(x, 's!:builtin0)) then putv(builtin0, w, x)
  478. else if (w := get(x, 's!:builtin1)) then putv(builtin1, w, x)
  479. else if (w := get(x, 's!:builtin2)) then putv(builtin2, w, x)
  480. else if (w := get(x, 's!:builtin3)) then putv(builtin3, w, x)
  481. end;
  482. % Now I have one procedure per opcode, so I can call the helper code to
  483. % do the decoding. The result that must be handed back will be
  484. % (n-bytes lisp1 lisp2 ...) where n-bytes is the number of
  485. % bytes that composes this instruction. One could readily argue that the
  486. % large number of somewhat repetitive procedures here represents bad
  487. % software design and that some table-driven approach would be much better.
  488. % My defence is that the bytecode model is inherently irregular and so the
  489. % flexibility of using code is useful.
  490. off echo;
  491. smacro procedure byte1;
  492. bps!-getv(code, pc);
  493. smacro procedure byte2;
  494. bps!-getv(code, pc+1);
  495. smacro procedure twobytes;
  496. 256*byte1() + byte2();
  497. smacro procedure makeif(why, loc);
  498. list('if, why, loc, list('go, gensym()));
  499. smacro procedure jumpto x;
  500. all_jumps := list(all_jumps, x);
  501. smacro procedure jumpop why;
  502. list(2, makeif(why, jumpto(pc + byte1() + 1)));
  503. smacro procedure jumpopb why;
  504. list(2, makeif(why, jumpto(pc - byte1() + 1)));
  505. smacro procedure jumpopl why;
  506. list(3, makeif(why, jumpto(pc + twobytes() + 1)));
  507. smacro procedure jumpopbl why;
  508. list(3, makeif(why, jumpto(pc - twobytes() + 1)));
  509. <<
  510. symbolic procedure h!:LOADLOC(pc, code, env);
  511. list(2, list('setq, !@b, !@a), list('setq, !@a, list(!@stack, byte1())));
  512. symbolic procedure h!:LOADLOC0(pc, code, env);
  513. list(1, list('setq, !@b, !@a), list('setq, !@a, list(!@stack, 0)));
  514. symbolic procedure h!:LOADLOC1(pc, code, env);
  515. list(1, list('setq, !@b, !@a), list('setq, !@a, list(!@stack, 1)));
  516. symbolic procedure h!:LOADLOC2(pc, code, env);
  517. list(1, list('setq, !@b, !@a), list('setq, !@a, list(!@stack, 2)));
  518. symbolic procedure h!:LOADLOC3(pc, code, env);
  519. list(1, list('setq, !@b, !@a), list('setq, !@a, list(!@stack, 3)));
  520. symbolic procedure h!:LOADLOC4(pc, code, env);
  521. list(1, list('setq, !@b, !@a), list('setq, !@a, list(!@stack, 4)));
  522. symbolic procedure h!:LOADLOC5(pc, code, env);
  523. list(1, list('setq, !@b, !@a), list('setq, !@a, list(!@stack, 5)));
  524. symbolic procedure h!:LOADLOC6(pc, code, env);
  525. list(1, list('setq, !@b, !@a), list('setq, !@a, list(!@stack, 6)));
  526. symbolic procedure h!:LOADLOC7(pc, code, env);
  527. list(1, list('setq, !@b, !@a), list('setq, !@a, list(!@stack, 7)));
  528. symbolic procedure h!:LOADLOC8(pc, code, env);
  529. list(1, list('setq, !@b, !@a), list('setq, !@a, list(!@stack, 8)));
  530. symbolic procedure h!:LOADLOC9(pc, code, env);
  531. list(1, list('setq, !@b, !@a), list('setq, !@a, list(!@stack, 9)));
  532. symbolic procedure h!:LOADLOC10(pc, code, env);
  533. list(1, list('setq, !@b, !@a), list('setq, !@a, list(!@stack, 10)));
  534. symbolic procedure h!:LOADLOC11(pc, code, env);
  535. list(1, list('setq, !@b, !@a), list('setq, !@a, list(!@stack, 11)));
  536. symbolic procedure h!:LOC0LOC1(pc, code, env);
  537. list(1, list('setq, !@b, list(!@stack, 0)), list('setq, !@a, list(!@stack, 1)));
  538. symbolic procedure h!:LOC1LOC2(pc, code, env);
  539. list(1, list('setq, !@b, list(!@stack, 1)), list('setq, !@a, list(!@stack, 2)));
  540. symbolic procedure h!:LOC2LOC3(pc, code, env);
  541. list(1, list('setq, !@b, list(!@stack, 2)), list('setq, !@a, list(!@stack, 3)));
  542. symbolic procedure h!:LOC1LOC0(pc, code, env);
  543. list(1, list('setq, !@b, list(!@stack, 1)), list('setq, !@a, list(!@stack, 1)));
  544. symbolic procedure h!:LOC2LOC1(pc, code, env);
  545. list(1, list('setq, !@b, list(!@stack, 2)), list('setq, !@a, list(!@stack, 1)));
  546. symbolic procedure h!:LOC3LOC2(pc, code, env);
  547. list(1, list('setq, !@b, list(!@stack, 3)), list('setq, !@a, list(!@stack, 2)));
  548. symbolic procedure h!:VNIL(pc, code, env);
  549. list(1, list('setq, !@b, !@a), list('setq, !@a, nil));
  550. symbolic procedure freeref(env, n);
  551. if n < 0 or n > upbv env then error(1, "free variable (etc) reference failure")
  552. else getv(env, n);
  553. symbolic procedure litref(env, n);
  554. if n < 0 or n > upbv env then error(1, "literal reference failure")
  555. else mkquote getv(env, n);
  556. symbolic procedure h!:LOADLIT(pc, code, env);
  557. list(2, list('setq, !@b, !@a), list('setq, !@a, litref(env, byte1())));
  558. symbolic procedure h!:LOADLIT1(pc, code, env);
  559. list(1, list('setq, !@b, !@a), list('setq, !@a, litref(env, 1)));
  560. symbolic procedure h!:LOADLIT2(pc, code, env);
  561. list(1, list('setq, !@b, !@a), list('setq, !@a, litref(env, 2)));
  562. symbolic procedure h!:LOADLIT3(pc, code, env);
  563. list(1, list('setq, !@b, !@a), list('setq, !@a, litref(env, 3)));
  564. symbolic procedure h!:LOADLIT4(pc, code, env);
  565. list(1, list('setq, !@b, !@a), list('setq, !@a, litref(env, 4)));
  566. symbolic procedure h!:LOADLIT5(pc, code, env);
  567. list(1, list('setq, !@b, !@a), list('setq, !@a, litref(env, 5)));
  568. symbolic procedure h!:LOADLIT6(pc, code, env);
  569. list(1, list('setq, !@b, !@a), list('setq, !@a, litref(env, 6)));
  570. symbolic procedure h!:LOADLIT7(pc, code, env);
  571. list(1, list('setq, !@b, !@a), list('setq, !@a, litref(env, 7)));
  572. symbolic procedure h!:LOADFREE(pc, code, env);
  573. list(2, list('setq, !@b, !@a), list('setq, !@a, freeref(env, byte1())));
  574. symbolic procedure h!:LOADFREE1(pc, code, env);
  575. list(1, list('setq, !@b, !@a), list('setq, !@a, freeref(env, 1)));
  576. symbolic procedure h!:LOADFREE2(pc, code, env);
  577. list(1, list('setq, !@b, !@a), list('setq, !@a, freeref(env, 2)));
  578. symbolic procedure h!:LOADFREE3(pc, code, env);
  579. list(1, list('setq, !@b, !@a), list('setq, !@a, freeref(env, 3)));
  580. symbolic procedure h!:LOADFREE4(pc, code, env);
  581. list(1, list('setq, !@b, !@a), list('setq, !@a, freeref(env, 4)));
  582. symbolic procedure h!:STORELOC(pc, code, env);
  583. list(2, list('setq, list(!@stack, byte1()), !@a));
  584. symbolic procedure h!:STORELOC0(pc, code, env);
  585. list(1, list('setq, list(!@stack, 0), !@a));
  586. symbolic procedure h!:STORELOC1(pc, code, env);
  587. list(1, list('setq, list(!@stack, 1), !@a));
  588. symbolic procedure h!:STORELOC2(pc, code, env);
  589. list(1, list('setq, list(!@stack, 2), !@a));
  590. symbolic procedure h!:STORELOC3(pc, code, env);
  591. list(1, list('setq, list(!@stack, 3), !@a));
  592. symbolic procedure h!:STORELOC4(pc, code, env);
  593. list(1, list('setq, list(!@stack, 4), !@a));
  594. symbolic procedure h!:STORELOC5(pc, code, env);
  595. list(1, list('setq, list(!@stack, 5), !@a));
  596. symbolic procedure h!:STORELOC6(pc, code, env);
  597. list(1, list('setq, list(!@stack, 6), !@a));
  598. symbolic procedure h!:STORELOC7(pc, code, env);
  599. list(1, list('setq, list(!@stack, 7), !@a));
  600. symbolic procedure h!:STOREFREE(pc, code, env);
  601. list(2, list('setq, freeref(env, byte1()), !@a));
  602. symbolic procedure h!:STOREFREE1(pc, code, env);
  603. list(1, list('setq, freeref(env, 1), !@a));
  604. symbolic procedure h!:STOREFREE2(pc, code, env);
  605. list(1, list('setq, freeref(env, 2), !@a));
  606. symbolic procedure h!:STOREFREE3(pc, code, env);
  607. list(1, list('setq, freeref(env, 3), !@a));
  608. symbolic procedure h!:LOADLEX(pc, code, env);
  609. begin
  610. error(1, "loadlex"); % Not yet implemented here
  611. return list(3, 'loadlex)
  612. end;
  613. symbolic procedure h!:STORELEX(pc, code, env);
  614. begin
  615. error(1, "storelex"); % Not yet implemented here
  616. return list(3, 'storelex)
  617. end;
  618. symbolic procedure h!:CLOSURE(pc, code, env);
  619. begin
  620. error(1, "closure"); % Not yet implemented here
  621. return list(2, 'closure)
  622. end;
  623. symbolic procedure h!:CARLOC0(pc, code, env);
  624. list(1, list('setq, !@b, !@a), list('setq, !@a, list('car, list(!@stack, 0))));
  625. symbolic procedure h!:CARLOC1(pc, code, env);
  626. list(1, list('setq, !@b, !@a), list('setq, !@a, list('car, list(!@stack, 1))));
  627. symbolic procedure h!:CARLOC2(pc, code, env);
  628. list(1, list('setq, !@b, !@a), list('setq, !@a, list('car, list(!@stack, 2))));
  629. symbolic procedure h!:CARLOC3(pc, code, env);
  630. list(1, list('setq, !@b, !@a), list('setq, !@a, list('car, list(!@stack, 3))));
  631. symbolic procedure h!:CARLOC4(pc, code, env);
  632. list(1, list('setq, !@b, !@a), list('setq, !@a, list('car, list(!@stack, 4))));
  633. symbolic procedure h!:CARLOC5(pc, code, env);
  634. list(1, list('setq, !@b, !@a), list('setq, !@a, list('car, list(!@stack, 5))));
  635. symbolic procedure h!:CARLOC6(pc, code, env);
  636. list(1, list('setq, !@b, !@a), list('setq, !@a, list('car, list(!@stack, 6))));
  637. symbolic procedure h!:CARLOC7(pc, code, env);
  638. list(1, list('setq, !@b, !@a), list('setq, !@a, list('car, list(!@stack, 7))));
  639. symbolic procedure h!:CARLOC8(pc, code, env);
  640. list(1, list('setq, !@b, !@a), list('setq, !@a, list('car, list(!@stack, 8))));
  641. symbolic procedure h!:CARLOC9(pc, code, env);
  642. list(1, list('setq, !@b, !@a), list('setq, !@a, list('car, list(!@stack, 9))));
  643. symbolic procedure h!:CARLOC10(pc, code, env);
  644. list(1, list('setq, !@b, !@a), list('setq, !@a, list('car, list(!@stack, 10))));
  645. symbolic procedure h!:CARLOC11(pc, code, env);
  646. list(1, list('setq, !@b, !@a), list('setq, !@a, list('car, list(!@stack, 11))));
  647. symbolic procedure h!:CDRLOC0(pc, code, env);
  648. list(1, list('setq, !@b, !@a), list('setq, !@a, list('cdr, list(!@stack, 0))));
  649. symbolic procedure h!:CDRLOC1(pc, code, env);
  650. list(1, list('setq, !@b, !@a), list('setq, !@a, list('cdr, list(!@stack, 1))));
  651. symbolic procedure h!:CDRLOC2(pc, code, env);
  652. list(1, list('setq, !@b, !@a), list('setq, !@a, list('cdr, list(!@stack, 2))));
  653. symbolic procedure h!:CDRLOC3(pc, code, env);
  654. list(1, list('setq, !@b, !@a), list('setq, !@a, list('cdr, list(!@stack, 3))));
  655. symbolic procedure h!:CDRLOC4(pc, code, env);
  656. list(1, list('setq, !@b, !@a), list('setq, !@a, list('cdr, list(!@stack, 4))));
  657. symbolic procedure h!:CDRLOC5(pc, code, env);
  658. list(1, list('setq, !@b, !@a), list('setq, !@a, list('cdr, list(!@stack, 5))));
  659. symbolic procedure h!:CAARLOC0(pc, code, env);
  660. list(1, list('setq, !@b, !@a), list('setq, !@a, list('caar, list(!@stack, 0))));
  661. symbolic procedure h!:CAARLOC1(pc, code, env);
  662. list(1, list('setq, !@b, !@a), list('setq, !@a, list('caar, list(!@stack, 1))));
  663. symbolic procedure h!:CAARLOC2(pc, code, env);
  664. list(1, list('setq, !@b, !@a), list('setq, !@a, list('caar, list(!@stack, 2))));
  665. symbolic procedure h!:CAARLOC3(pc, code, env);
  666. list(1, list('setq, !@b, !@a), list('setq, !@a, list('car, list(!@stack, 3))));
  667. symbolic procedure h!:CALL0(pc, code, env);
  668. list(2, list('setq, !@b, !@a), list('setq, !@a, list(freeref(env, byte1()))));
  669. symbolic procedure h!:CALL1(pc, code, env);
  670. list(2, list('setq, !@a, list(freeref(env, byte1()), !@a)));
  671. symbolic procedure h!:CALL2(pc, code, env);
  672. list(2, list('setq, !@a, list(freeref(env, byte1()), !@b, !@a)));
  673. symbolic procedure h!:CALL2R(pc, code, env);
  674. list(2, list('setq, !@a, list(freeref(env, byte1()), !@a, !@b)));
  675. symbolic procedure h!:CALL3(pc, code, env);
  676. list(2, list('setq, !@a, expand_call(3, freeref(env, byte1()))), 'lose);
  677. symbolic procedure h!:CALLN(pc, code, env);
  678. begin
  679. scalar n, w;
  680. n := byte1();
  681. for i := 1:n-2 do w := 'lose . w;
  682. return list!*(3,
  683. list('setq, !@a, expand_call(n, freeref(env, byte2()))), w)
  684. end;
  685. symbolic procedure h!:CALL0_0(pc, code, env);
  686. list(1, list('setq, !@b, !@a), list('setq, !@a, list(freeref(env, 0))));
  687. symbolic procedure h!:CALL0_1(pc, code, env);
  688. list(1, list('setq, !@b, !@a), list('setq, !@a, list(freeref(env, 1))));
  689. symbolic procedure h!:CALL0_2(pc, code, env);
  690. list(1, list('setq, !@b, !@a), list('setq, !@a, list(freeref(env, 2))));
  691. symbolic procedure h!:CALL0_3(pc, code, env);
  692. list(1, list('setq, !@b, !@a), list('setq, !@a, list(freeref(env, 3))));
  693. symbolic procedure h!:CALL1_0(pc, code, env);
  694. list(1, list('setq, !@a, list(freeref(env, 0), !@a)));
  695. symbolic procedure h!:CALL1_1(pc, code, env);
  696. list(1, list('setq, !@a, list(freeref(env, 1), !@a)));
  697. symbolic procedure h!:CALL1_2(pc, code, env);
  698. list(1, list('setq, !@a, list(freeref(env, 2), !@a)));
  699. symbolic procedure h!:CALL1_3(pc, code, env);
  700. list(1, list('setq, !@a, list(freeref(env, 3), !@a)));
  701. symbolic procedure h!:CALL1_4(pc, code, env);
  702. list(1, list('setq, !@a, list(freeref(env, 4), !@a)));
  703. symbolic procedure h!:CALL1_5(pc, code, env);
  704. list(1, list('setq, !@a, list(freeref(env, 5), !@a)));
  705. symbolic procedure h!:CALL2_0(pc, code, env);
  706. list(1, list('setq, !@a, list(freeref(env, 0), !@b, !@a)));
  707. symbolic procedure h!:CALL2_1(pc, code, env);
  708. list(1, list('setq, !@a, list(freeref(env, 1), !@b, !@a)));
  709. symbolic procedure h!:CALL2_2(pc, code, env);
  710. list(1, list('setq, !@a, list(freeref(env, 2), !@b, !@a)));
  711. symbolic procedure h!:CALL2_3(pc, code, env);
  712. list(1, list('setq, !@a, list(freeref(env, 3), !@b, !@a)));
  713. symbolic procedure h!:CALL2_4(pc, code, env);
  714. list(1, list('setq, !@a, list(freeref(env, 4), !@b, !@a)));
  715. symbolic procedure h!:BUILTIN0(pc, code, env);
  716. begin
  717. scalar w;
  718. w := getv(builtin0, byte1());
  719. if null w then error(1, "Invalid builtin-function specifier");
  720. return list(2, list('setq, !@a, list w))
  721. end;
  722. symbolic procedure h!:BUILTIN1(pc, code, env);
  723. begin
  724. scalar w;
  725. w := getv(builtin1, byte1());
  726. if null w then error(1, "Invalid builtin-function specifier");
  727. return list(2, list('setq, !@a, list(w, !@a)))
  728. end;
  729. symbolic procedure h!:BUILTIN2(pc, code, env);
  730. begin
  731. scalar w;
  732. w := getv(builtin2, byte1());
  733. if null w then error(1, "Invalid builtin-function specifier");
  734. return list(2, list('setq, !@a, list(w, !@b, !@a)))
  735. end;
  736. symbolic procedure h!:BUILTIN2R(pc, code, env);
  737. begin
  738. scalar w;
  739. w := getv(builtin2, byte1());
  740. if null w then error(1, "Invalid builtin-function specifier");
  741. return list(2, list('setq, !@a, list(w, !@a, !@b)))
  742. end;
  743. symbolic procedure h!:BUILTIN3(pc, code, env);
  744. begin
  745. scalar w;
  746. w := getv(builtin3, byte1());
  747. if null w then error(1, "Invalid builtin-function specifier");
  748. return list(2, list('setq, !@a, expand_call(3, w)), 'lose)
  749. end;
  750. symbolic procedure h!:APPLY1(pc, code, env);
  751. list(1, list('setq, !@a, list('apply, !@b, !@a)));
  752. symbolic procedure h!:APPLY2(pc, code, env);
  753. list(1, list('setq, !@a, list('apply, list(!@stack, 0), !@b, !@a)), 'lose);
  754. symbolic procedure h!:APPLY3(pc, code, env);
  755. list(1, list('setq, !@a, list('apply, list(!@stack, 0), list(!@stack, 1), !@b, !@a)), 'lose, 'lose);
  756. symbolic procedure h!:APPLY4(pc, code, env);
  757. list(1, list('setq, !@a, list('apply, list(!@stack, 0), list(!@stack, 1), list(!@stack, 2), !@b, !@a)),
  758. 'lose, 'lose, 'lose);
  759. symbolic procedure h!:JCALL(pc, code, env);
  760. begin
  761. scalar nargs, dest;
  762. nargs := byte1();
  763. dest := freeref(env, logand(nargs, 31));
  764. nargs := irightshift(nargs, 5);
  765. return list(2, expand_jcall(nargs, dest))
  766. end;
  767. symbolic procedure h!:JCALLN(pc, code, env);
  768. list(3, expand_jcall(byte2(), freeref(env, byte1())));
  769. symbolic procedure expand_jcall(nargs, dest);
  770. list('return, expand_call(nargs, dest));
  771. symbolic procedure expand_call(nargs, dest);
  772. if nargs = 0 then list dest
  773. else if nargs = 1 then list(dest, !@a)
  774. else if nargs = 2 then list(dest, !@b, !@a)
  775. else begin scalar w;
  776. w := list(!@b, !@a);
  777. for i := 1:nargs-2 do w := list(!@stack, i) . w;
  778. return dest . w end;
  779. symbolic procedure h!:JUMP(pc, code, env);
  780. list(2, jumpto(pc + byte1() + 1));
  781. symbolic procedure h!:JUMP_B(pc, code, env);
  782. list(2, jumpto(pc - byte1() + 1));
  783. symbolic procedure h!:JUMP_L(pc, code, env);
  784. list(3, jumpto(pc + twobytes() + 1));
  785. symbolic procedure h!:JUMP_BL(pc, code, env);
  786. list(3, jumpto(pc - twobytes() + 1));
  787. symbolic procedure h!:JUMPNIL(pc, code, env);
  788. jumpop list('null, !@a);
  789. symbolic procedure h!:JUMPNIL_B(pc, code, env);
  790. jumpopb list('null, !@a);
  791. symbolic procedure h!:JUMPNIL_L(pc, code, env);
  792. jumpopl list('null, !@a);
  793. symbolic procedure h!:JUMPNIL_BL(pc, code, env);
  794. jumpopbl list('null, !@a);
  795. symbolic procedure h!:JUMPT(pc, code, env);
  796. jumpop !@a;
  797. symbolic procedure h!:JUMPT_B(pc, code, env);
  798. jumpopb !@a;
  799. symbolic procedure h!:JUMPT_L(pc, code, env);
  800. jumpopl !@a;
  801. symbolic procedure h!:JUMPT_BL(pc, code, env);
  802. jumpopbl !@a;
  803. symbolic procedure h!:JUMPATOM(pc, code, env);
  804. jumpop list('atom, !@a);
  805. symbolic procedure h!:JUMPATOM_B(pc, code, env);
  806. jumpopb list('atom, !@a);
  807. symbolic procedure h!:JUMPATOM_L(pc, code, env);
  808. jumpopl list('atom, !@a);
  809. symbolic procedure h!:JUMPATOM_BL(pc, code, env);
  810. jumpopbl list('atom, !@a);
  811. symbolic procedure h!:JUMPNATOM(pc, code, env);
  812. jumpop list('not, list('atom, !@a));
  813. symbolic procedure h!:JUMPNATOM_B(pc, code, env);
  814. jumpopb list('not, list('atom, !@a));
  815. symbolic procedure h!:JUMPNATOM_L(pc, code, env);
  816. jumpopl list('not, list('atom, !@a));
  817. symbolic procedure h!:JUMPNATOM_BL(pc, code, env);
  818. jumpopbl list('not, list('atom, !@a));
  819. symbolic procedure h!:JUMPEQ(pc, code, env);
  820. jumpop list('eq, !@b, !@a);
  821. symbolic procedure h!:JUMPEQ_B(pc, code, env);
  822. jumpopb list('eq, !@b, !@a);
  823. symbolic procedure h!:JUMPEQ_L(pc, code, env);
  824. jumpopl list('eq, !@b, !@a);
  825. symbolic procedure h!:JUMPEQ_BL(pc, code, env);
  826. jumpopbl list('eq, !@b, !@a);
  827. symbolic procedure h!:JUMPNE(pc, code, env);
  828. jumpop list('not, list('eq, !@b, !@a));
  829. symbolic procedure h!:JUMPNE_B(pc, code, env);
  830. jumpopb list('not, list('eq, !@b, !@a));
  831. symbolic procedure h!:JUMPNE_L(pc, code, env);
  832. jumpopl list('not, list('eq, !@b, !@a));
  833. symbolic procedure h!:JUMPNE_BL(pc, code, env);
  834. jumpopbl list('not, list('eq, !@b, !@a));
  835. symbolic procedure h!:JUMPEQUAL(pc, code, env);
  836. jumpop list('equal, !@b, !@a);
  837. symbolic procedure h!:JUMPEQUAL_B(pc, code, env);
  838. jumpopb list('equal, !@b, !@a);
  839. symbolic procedure h!:JUMPEQUAL_L(pc, code, env);
  840. jumpopl list('equal, !@b, !@a);
  841. symbolic procedure h!:JUMPEQUAL_BL(pc, code, env);
  842. jumpopbl list('equal, !@b, !@a);
  843. symbolic procedure h!:JUMPNEQUAL(pc, code, env);
  844. jumpop list('not, list('equal, !@b, !@a));
  845. symbolic procedure h!:JUMPNEQUAL_B(pc, code, env);
  846. jumpopb list('not, list('equal, !@b, !@a));
  847. symbolic procedure h!:JUMPNEQUAL_L(pc, code, env);
  848. jumpopl list('not, list('equal, !@b, !@a));
  849. symbolic procedure h!:JUMPNEQUAL_BL(pc, code, env);
  850. jumpopbl list('not, list('equal, !@b, !@a));
  851. symbolic procedure h!:JUMPL0NIL(pc, code, env);
  852. jumpop list('null, list(!@stack, 0));
  853. symbolic procedure h!:JUMPL0T(pc, code, env);
  854. jumpop list(!@stack, 0);
  855. symbolic procedure h!:JUMPL1NIL(pc, code, env);
  856. jumpop list('null, list(!@stack, 1));
  857. symbolic procedure h!:JUMPL1T(pc, code, env);
  858. jumpop list(!@stack, 1);
  859. symbolic procedure h!:JUMPL2NIL(pc, code, env);
  860. jumpop list('null, list(!@stack, 2));
  861. symbolic procedure h!:JUMPL2T(pc, code, env);
  862. jumpop list(!@stack, 2);
  863. symbolic procedure h!:JUMPL3NIL(pc, code, env);
  864. jumpop list('null, list(!@stack, 3));
  865. symbolic procedure h!:JUMPL3T(pc, code, env);
  866. jumpop list(!@stack, 3);
  867. symbolic procedure h!:JUMPL4NIL(pc, code, env);
  868. jumpop list('null, list(!@stack, 4));
  869. symbolic procedure h!:JUMPL4T(pc, code, env);
  870. jumpop list(!@stack, 4);
  871. symbolic procedure h!:JUMPST0NIL(pc, code, env);
  872. jumpop list('null, list('setq, list(!@stack, 0), !@a));
  873. symbolic procedure h!:JUMPST0T(pc, code, env);
  874. jumpop list('setq, list(!@stack, 0), !@a);
  875. symbolic procedure h!:JUMPST1NIL(pc, code, env);
  876. jumpop list('null, list('setq, list(!@stack, 1), !@a));
  877. symbolic procedure h!:JUMPST1T(pc, code, env);
  878. jumpop list('setq, list(!@stack, 1), !@a);
  879. symbolic procedure h!:JUMPST2NIL(pc, code, env);
  880. jumpop list('null, list('setq, list(!@stack, 2), !@a));
  881. symbolic procedure h!:JUMPST2T(pc, code, env);
  882. jumpop list('setq, list(!@stack, 2), !@a);
  883. symbolic procedure h!:JUMPL0ATOM(pc, code, env);
  884. jumpop list('atom, list(!@stack, 0));
  885. symbolic procedure h!:JUMPL0NATOM(pc, code, env);
  886. jumpop list('not, list('atom, list(!@stack, 0)));
  887. symbolic procedure h!:JUMPL1ATOM(pc, code, env);
  888. jumpop list('atom, list(!@stack, 1));
  889. symbolic procedure h!:JUMPL1NATOM(pc, code, env);
  890. jumpop list('not, list('atom, list(!@stack, 1)));
  891. symbolic procedure h!:JUMPL2ATOM(pc, code, env);
  892. jumpop list('atom, list(!@stack, 2));
  893. symbolic procedure h!:JUMPL2NATOM(pc, code, env);
  894. jumpop list('not, list('atom, list(!@stack, 2)));
  895. symbolic procedure h!:JUMPL3ATOM(pc, code, env);
  896. jumpop list('atom, list(!@stack, 3));
  897. symbolic procedure h!:JUMPL3NATOM(pc, code, env);
  898. jumpop list('not, list('atom, list(!@stack, 3)));
  899. symbolic procedure h!:JUMPFREE1NIL(pc, code, env);
  900. jumpop list('null, freeref(env, 1));
  901. symbolic procedure h!:JUMPFREE1T(pc, code, env);
  902. jumpop freeref(env, 1);
  903. symbolic procedure h!:JUMPFREE2NIL(pc, code, env);
  904. jumpop list('null, freeref(env, 2));
  905. symbolic procedure h!:JUMPFREE2T(pc, code, env);
  906. jumpop freeref(env, 2);
  907. symbolic procedure h!:JUMPFREE3NIL(pc, code, env);
  908. jumpop list('null, freeref(env, 3));
  909. symbolic procedure h!:JUMPFREE3T(pc, code, env);
  910. jumpop freeref(env, 3);
  911. symbolic procedure h!:JUMPFREE4NIL(pc, code, env);
  912. jumpop list('null, freeref(env, 4));
  913. symbolic procedure h!:JUMPFREE4T(pc, code, env);
  914. jumpop freeref(env, 4);
  915. symbolic procedure h!:JUMPFREENIL(pc, code, env);
  916. list(3, makeif(list('null, freeref(env, byte1())),
  917. jumpto(pc + byte2() + 2)));
  918. symbolic procedure h!:JUMPFREET(pc, code, env);
  919. list(3, makeif(freeref(env, byte1()), jumpto(pc + byte2() + 2)));
  920. symbolic procedure h!:JUMPLIT1EQ(pc, code, env);
  921. jumpop list('eq, !@a, litref(env, 1));
  922. symbolic procedure h!:JUMPLIT1NE(pc, code, env);
  923. jumpop list('not, list('eq, !@a, litref(env, 1)));
  924. symbolic procedure h!:JUMPLIT2EQ(pc, code, env);
  925. jumpop list('eq, !@a, litref(env, 2));
  926. symbolic procedure h!:JUMPLIT2NE(pc, code, env);
  927. jumpop list('not, list('eq, !@a, litref(env, 1)));
  928. symbolic procedure h!:JUMPLIT3EQ(pc, code, env);
  929. jumpop list('eq, !@a, litref(env, 3));
  930. symbolic procedure h!:JUMPLIT3NE(pc, code, env);
  931. jumpop list('not, list('eq, !@a, litref(env, 1)));
  932. symbolic procedure h!:JUMPLIT4EQ(pc, code, env);
  933. jumpop list('eq, !@a, litref(env, 4));
  934. symbolic procedure h!:JUMPLIT4NE(pc, code, env);
  935. jumpop list('not, list('eq, !@a, litref(env, 1)));
  936. symbolic procedure h!:JUMPLITEQ(pc, code, env);
  937. list(3, makeif(list('eq, !@a, litref(env, byte1())),
  938. jumpto(pc + byte2() + 2)));
  939. symbolic procedure h!:JUMPLITNE(pc, code, env);
  940. list(3, makeif(list('not, list('eq, !@a, litref(env, byte1()))),
  941. jumpto(pc + byte2() + 2)));
  942. symbolic procedure h!:JUMPB1NIL(pc, code, env);
  943. begin
  944. scalar w;
  945. w := elt(builtin1, byte1());
  946. if null w then error(1, "Bad in JUMPB1NIL");
  947. return list(3, makeif(list('null, list(w, !@a)),
  948. jumpto(pc + byte2() + 2)));
  949. end;
  950. symbolic procedure h!:JUMPB1T(pc, code, env);
  951. begin
  952. scalar w;
  953. w := elt(builtin1, byte1());
  954. if null w then error(1, "Bad in JUMPB1T");
  955. return list(3, makeif(list(w, !@a),
  956. jumpto(pc + byte2() + 2)));
  957. end;
  958. symbolic procedure h!:JUMPB2NIL(pc, code, env);
  959. begin
  960. scalar w;
  961. w := elt(builtin2, byte1());
  962. if null w then error(1, "Bad in JUMPB2NIL");
  963. return list(3, makeif(list('null, list(w, !@b, !@a)),
  964. jumpto(pc + byte2() + 2)));
  965. end;
  966. symbolic procedure h!:JUMPB2T(pc, code, env);
  967. begin
  968. scalar w;
  969. w := elt(builtin2, byte1());
  970. if null w then error(1, "Bad in JUMPB2T");
  971. return list(3, makeif(list(w, !@b, !@a),
  972. jumpto(pc + byte2() + 2)));
  973. end;
  974. symbolic procedure h!:JUMPFLAGP(pc, code, env);
  975. jumpop list('flagp, !@b, !@a);
  976. symbolic procedure h!:JUMPNFLAGP(pc, code, env);
  977. jumpop list('not, list('flagp, !@b, !@a));
  978. symbolic procedure h!:JUMPEQCAR(pc, code, env);
  979. list(3, makeif(list('eqcar, !@a, litref(env, byte1())),
  980. jumpto(pc + byte2() + 2)));
  981. symbolic procedure h!:JUMPNEQCAR(pc, code, env);
  982. list(3, makeif(list('not, list('eqcar, !@a, litref(env, byte1()))),
  983. jumpto(pc + byte2() + 2)));
  984. symbolic procedure h!:CATCH(pc, code, env);
  985. jumpop list(!@catch, !@a);
  986. symbolic procedure h!:CATCH_B(pc, code, env);
  987. jumpopb list(!@catch, !@a);
  988. symbolic procedure h!:CATCH_L(pc, code, env);
  989. jumpopl list(!@catch, !@a);
  990. symbolic procedure h!:CATCH_BL(pc, code, env);
  991. jumpopbl list(!@catch, !@a);
  992. symbolic procedure h!:UNCATCH(pc, code, env);
  993. list(1, 'uncatch, jumpto(pc));
  994. symbolic procedure h!:THROW(pc, code, env);
  995. '(1 throw);
  996. % There is a jolly feature here. I force in a JUMP just after any
  997. % FREEBIND/FREERSTR since that will make later processing easier for me.
  998. % Ditto CATCH etc.
  999. symbolic procedure h!:PROTECT(pc, code, env);
  1000. list(1 ,'protect, jumpto(pc));
  1001. symbolic procedure h!:UNPROTECT(pc, code, env);
  1002. list(1, 'unprotect, jumpto(pc));
  1003. symbolic procedure h!:PVBIND(pc, code, env);
  1004. list(1, 'pvbind, jumpto(pc));
  1005. symbolic procedure h!:PVRESTORE(pc, code, env);
  1006. list(1, 'pvrestore, jumpto(pc));
  1007. symbolic procedure vector_to_list v;
  1008. if not vectorp v then error(1, "Error in binding fluid variables")
  1009. else begin
  1010. scalar r;
  1011. for i := 0:upbv v do r := getv(v, i) . r;
  1012. return reversip r
  1013. end;
  1014. symbolic procedure h!:FREEBIND(pc, code, env);
  1015. list(2, list('freebind, vector_to_list freeref(env, byte1())), jumpto(pc+1));
  1016. symbolic procedure h!:FREERSTR(pc, code, env);
  1017. list(1, '(freerstr !*), jumpto(pc));
  1018. symbolic procedure h!:EXIT(pc, code, env);
  1019. list(1, list('return, !@a));
  1020. symbolic procedure h!:NILEXIT(pc, code, env);
  1021. list(1, list('return, nil));
  1022. symbolic procedure h!:LOC0EXIT(pc, code, env);
  1023. list(1, list('return, list(!@stack, 0)));
  1024. symbolic procedure h!:LOC1EXIT(pc, code, env);
  1025. list(1, list('return, list(!@stack, 1)));
  1026. symbolic procedure h!:LOC2EXIT(pc, code, env);
  1027. list(1, list('return, list(!@stack, 2)));
  1028. symbolic procedure h!:PUSH(pc, code, env);
  1029. list(1, 'push, list('setq, list(!@stack, 0), !@a));
  1030. symbolic procedure h!:PUSHNIL(pc, code, env);
  1031. list(1, 'push, list('setq, list(!@stack, 0), nil));
  1032. symbolic procedure h!:PUSHNIL2(pc, code, env);
  1033. list(1, 'push, list('setq, list(!@stack, 0), nil),
  1034. 'push, list('setq, list(!@stack, 0), nil));
  1035. symbolic procedure h!:PUSHNIL3(pc, code, env);
  1036. list(1, 'push, list('setq, list(!@stack, 0), nil),
  1037. 'push, list('setq, list(!@stack, 0), nil),
  1038. 'push, list('setq, list(!@stack, 0), nil));
  1039. symbolic procedure h!:PUSHNILS(pc, code, env);
  1040. begin
  1041. scalar n, w;
  1042. n := byte1();
  1043. for i := 1:n do w := 'push . list('setq, list(!@stack, 0), nil) . w;
  1044. return 2 . w
  1045. end;
  1046. symbolic procedure h!:POP(pc, code, env);
  1047. list(1, list('setq, list('!@stack, 0)), 'lose);
  1048. symbolic procedure h!:LOSE(pc, code, env);
  1049. '(1 lose);
  1050. symbolic procedure h!:LOSE2(pc, code, env);
  1051. '(1 lose lose);
  1052. symbolic procedure h!:LOSE3(pc, code, env);
  1053. '(1 lose lose lose);
  1054. symbolic procedure h!:LOSES(pc, code, env);
  1055. begin
  1056. scalar n, w;
  1057. n := byte1();
  1058. for i := 1:n do w := 'lose . w;
  1059. return 2 . w
  1060. end;
  1061. symbolic procedure h!:SWOP(pc, code, env);
  1062. list(1, list('setq, !@w, !@a),
  1063. list('setq, !@a, !@b),
  1064. list('setq, !@b, !@w));
  1065. symbolic procedure h!:EQ(pc, code, env);
  1066. list(1, list('setq, !@a, list('eq, !@b, !@a)));
  1067. symbolic procedure h!:EQCAR(pc, code, env);
  1068. list(1, list('setq, !@a, list('eqcar, !@b, !@a)));
  1069. symbolic procedure h!:EQUAL(pc, code, env);
  1070. list(1, list('setq, !@a, list('equal, !@b, !@a)));
  1071. symbolic procedure h!:NUMBERP(pc, code, env);
  1072. list(1, list('setq, !@a, list('numberp, !@a)));
  1073. symbolic procedure h!:CAR(pc, code, env);
  1074. list(1, list('setq, !@a, list('car, !@a)));
  1075. symbolic procedure h!:CDR(pc, code, env);
  1076. list(1, list('setq, !@a, list('cdr, !@a)));
  1077. symbolic procedure h!:CAAR(pc, code, env);
  1078. list(1, list('setq, !@a, list('caar, !@a)));
  1079. symbolic procedure h!:CADR(pc, code, env);
  1080. list(1, list('setq, !@a, list('cadr, !@a)));
  1081. symbolic procedure h!:CDAR(pc, code, env);
  1082. list(1, list('setq, !@a, list('cdar, !@a)));
  1083. symbolic procedure h!:CDDR(pc, code, env);
  1084. list(1, list('setq, !@a, list('cddr, !@a)));
  1085. symbolic procedure h!:CONS(pc, code, env);
  1086. list(1, list('setq, !@a, list('cons, !@b, !@a)));
  1087. symbolic procedure h!:NCONS(pc, code, env);
  1088. list(1, list('setq, !@a, list('ncons, !@a)));
  1089. symbolic procedure h!:XCONS(pc, code, env);
  1090. list(1, list('setq, !@a, list('cons, !@a, !@b)));
  1091. symbolic procedure h!:ACONS(pc, code, env);
  1092. list(1, list('setq, !@a, list('acons, !@b, !@a, list(!@stack, 0))), 'lose);
  1093. symbolic procedure h!:LENGTH(pc, code, env);
  1094. list(1, list('setq, !@a, list('length, !@a)));
  1095. symbolic procedure h!:LIST2(pc, code, env);
  1096. list(1, list('setq, !@a, list('list, !@b, !@a)));
  1097. symbolic procedure h!:LIST2STAR(pc, code, env);
  1098. list(1, list('setq, !@a, list('list!*, !@b, !@a, list(!@stack, 0))), 'lose);
  1099. symbolic procedure h!:LIST3(pc, code, env);
  1100. list(1, list('setq, !@a, list('list, !@b, !@a, list(!@stack, 0))), 'lose);
  1101. symbolic procedure h!:PLUS2(pc, code, env);
  1102. list(1, list('setq, !@a, list('plus, !@b, !@a)));
  1103. symbolic procedure h!:ADD1(pc, code, env);
  1104. list(1, list('setq, !@a, list('add1, !@a)));
  1105. symbolic procedure h!:DIFFERENCE(pc, code, env);
  1106. list(1, list('setq, !@a, list('difference, !@b, !@a)));
  1107. symbolic procedure h!:SUB1(pc, code, env);
  1108. list(1, list('setq, !@a, list('sub1, !@a)));
  1109. symbolic procedure h!:TIMES2(pc, code, env);
  1110. list(1, list('setq, !@a, list('times, !@b, !@a)));
  1111. symbolic procedure h!:GREATERP(pc, code, env);
  1112. list(1, list('setq, !@a, list('greaterp, !@b, !@a)));
  1113. symbolic procedure h!:LESSP(pc, code, env);
  1114. list(1, list('setq, !@a, list('lessp, !@b, !@a)));
  1115. symbolic procedure h!:FLAGP(pc, code, env);
  1116. list(1, list('setq, !@a, list('flagp, !@b, !@a)));
  1117. symbolic procedure h!:GET(pc, code, env);
  1118. list(1, list('setq, !@a, list('get, !@b, !@a)));
  1119. symbolic procedure h!:LITGET(pc, code, env);
  1120. list(2, list('setq, !@a, list('get, !@a, litref(env, byte1()))));
  1121. symbolic procedure h!:GETV(pc, code, env);
  1122. list(1, list('setq, !@a, list('getv, !@b, !@a)));
  1123. symbolic procedure h!:QGETV(pc, code, env);
  1124. list(1, list('setq, !@a, list('qgetv, !@b, !@a)));
  1125. symbolic procedure h!:QGETVN(pc, code, env);
  1126. list(2, list('setq, !@a, list('qgetv, !@a, byte1())));
  1127. symbolic procedure h!:BIGSTACK(pc, code, env);
  1128. begin
  1129. error(1, "bigstack"); % Not yet implemented here
  1130. return list(3, 'bigstack)
  1131. end;
  1132. symbolic procedure h!:BIGCALL(pc, code, env);
  1133. begin
  1134. error(1, "bigcall"); % Not yet implemented here
  1135. return list(3, 'bigcall)
  1136. end;
  1137. symbolic procedure h!:ICASE(pc, code, env);
  1138. begin
  1139. error(1, "ICASE opcode found"); % Not yet implemented here
  1140. % This is followed by a whole bunch of addresses for destinations
  1141. return list(4 + 2*byte1(), 'icase)
  1142. end;
  1143. symbolic procedure h!:FASTGET(pc, code, env);
  1144. begin
  1145. error(1, "fastget"); % Not yet implemented here
  1146. return list(2, 'fastget)
  1147. end;
  1148. symbolic procedure h!:SPARE1(pc, code, env);
  1149. error(1, "Invalid (spare) opcode found in byte-stream");
  1150. symbolic procedure h!:SPARE2(pc, code, env);
  1151. error(1, "Invalid (spare) opcode found in byte-stream");
  1152. "All helper functions present" >>;
  1153. %
  1154. % fix_free_bindings searches for a (FREEBIND) and clips out everything
  1155. % up as far as all matching FREERSTRs
  1156. %
  1157. symbolic procedure find_freebind x;
  1158. if null x then nil
  1159. else if eqcar(car x, 'freebind) then x
  1160. else find_freebind cdr x;
  1161. symbolic procedure find_freerstr x;
  1162. if null x then nil
  1163. else if eqcar(car x, 'freerstr) then x
  1164. else find_freerstr cdr x;
  1165. symbolic procedure mark_restores(w, lab);
  1166. begin
  1167. scalar b;
  1168. b := assoc(lab, w);
  1169. if null b then error(1, "block not found");
  1170. if cadr b then return nil; % processed earlier...
  1171. rplaca(cdr b, t); % Mark this one as already noticed
  1172. if find_freerstr cddr b then return nil
  1173. else if find_freebind cddr b then return t;
  1174. while not atom cdr b do b := cdr b;
  1175. b := car b;
  1176. if eqcar(b, 'go) then return mark_restores(w, cadr b)
  1177. else if eqcar(b, 'if) then <<
  1178. if mark_restores(w, cadr caddr b) then return t
  1179. else return mark_restores(w, cadr cadddr b) >>
  1180. else if eqcar(b, 'progexits) then return mark_several_restores(w, cdr b)
  1181. else return nil
  1182. end;
  1183. symbolic procedure mark_several_restores(w, l);
  1184. if null l then nil
  1185. else if mark_restores(w, car l) then t
  1186. else mark_several_restores(w, cdr l);
  1187. symbolic procedure lift_free_binding(w, fb);
  1188. % Now all the marked basic blocks form part of a nested chunk, so I
  1189. % pull that out and re-insert it headed by the word "prog".
  1190. begin
  1191. scalar r1, r2, w1;
  1192. while w do <<
  1193. w1 := cdr w;
  1194. if cadar w then << rplaca(cdar w, nil); rplacd(w, r1); r1 := w >>
  1195. else << rplacd(w, r2); r2 := w >>;
  1196. w := w1 >>;
  1197. r1 := reversip r1;
  1198. rplaca(fb, 'prog . cadar fb . r1);
  1199. rplacd(fb, list ('progexits . free_exits r1));
  1200. return reversip r2
  1201. end;
  1202. symbolic procedure free_exits b;
  1203. begin
  1204. scalar r, r1;
  1205. for each i in b do <<
  1206. while not atom cdr i do i := cdr i;
  1207. i := car i;
  1208. if eqcar(i, 'go) then r := union(cdr i, r)
  1209. else if eqcar(i, 'if) then
  1210. r := union(cdr caddr i, union(cdr cadddr i, r))
  1211. else if eqcar(i, 'progexits) then r := union(cdr i, r) >>;
  1212. for each i in r do
  1213. if null assoc(i, b) then r1 := i . r1;
  1214. return r1
  1215. end;
  1216. symbolic procedure fix_free_bindings w;
  1217. begin
  1218. scalar changed, aborted, p, fb;
  1219. changed := t;
  1220. while changed do <<
  1221. changed := nil;
  1222. for each z in w do rplaca(cdr z, nil);
  1223. if aborted then p := cdr p
  1224. else p := w;
  1225. aborted := nil;
  1226. while p and not (fb := find_freebind cddar p) do p := cdr p;
  1227. if p then <<
  1228. changed := t;
  1229. % fb = ((freebind (x y z)) (go lab))
  1230. if mark_restores(w, cadr cadr fb) then aborted := t
  1231. else w := lift_free_binding(w, fb) >> >>;
  1232. return w
  1233. end;
  1234. %
  1235. % The code above here is concerned with generating VALID Lisp code out of
  1236. % a byte-stream. It can be used as nothing more than a byte-code verifier
  1237. % if that is what you want. There is one call-out left in it, to a
  1238. % function called "optimise-blocks", and this is expected to turn the initial
  1239. % bunch of machine-code-like basic blocks into ones whose contents
  1240. % look a lot more like reasonable Lisp.
  1241. %
  1242. symbolic procedure optimise_blocks(w, args, locals);
  1243. begin
  1244. scalar vars, changed, avail;
  1245. vars := append(args, locals);
  1246. for each z in w do rplaca(cdr z, 'unknown);
  1247. rplaca(cdar w, nil);
  1248. changed := t;
  1249. while changed do <<
  1250. changed := nil;
  1251. for each z in w do <<
  1252. avail := cadr z;
  1253. % prin car z; printc ":";
  1254. for each q in cddr z do <<
  1255. % princ "OPT: "; print q;
  1256. nil >>
  1257. >>
  1258. >>;
  1259. return w
  1260. end;
  1261. on echo;
  1262. on plap;
  1263. symbolic procedure simple x;
  1264. if atom x then x
  1265. else if null cdr x then car x
  1266. else simple cdr x;
  1267. fluid '(x y);
  1268. symbolic procedure mylast x;
  1269. if atom x then x
  1270. else if null cdr x then car x
  1271. else mylast cdr x;
  1272. symbolic procedure test a;
  1273. begin scalar x;
  1274. x := a+a+a;
  1275. x := begin scalar y;
  1276. y := x*x;
  1277. print list(x, y);
  1278. return y end;
  1279. return x/a
  1280. end;
  1281. unfluid '(x y);
  1282. off plap;
  1283. unbyte 'simple;
  1284. unbyte 'mylast;
  1285. unbyte 'test;
  1286. end;