STATEMEN.MOD 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. (* STATEMEN.MOD — DRAFT v1, assembled 2026-10-03, NOT verified.
  2. Reconstructed from Reversing-Turbo-Modula2-main/MCode_disassembly/statement.txt
  3. (1793 lines) by two parallel passes (group 1 @0001-0566, group 2 @0566-end).
  4. Does NOT yet recompile to the original MCD; verification via unassemble.c
  5. diff is still required (see src/compiler/README.md).
  6. FRAME MECHANICS (proven from MCode_specification/Stack.mod +
  7. Instruction.mod + Extended.mod, settles all arg-order disputes):
  8. - Callers push args in source order (spec Extended.Move pops size,dst,src).
  9. - NewFrame pushes oldFP,outerFP above retAddr; fp^[0]=outerFP, [1]=oldFP,
  10. [2]=retAddr, [3]=LAST pushed word. Opcode 03H..07H = LoadParam(3..7), and
  11. the disassembler prints fp^[3] as "param1". Hence "param1" = LAST pushed
  12. word (modulo multi-word/VAR params: SYMTAB proc8 SymbolAssert reads
  13. "param2"=cond,"param1"=code for source (cond, code) — consistent).
  14. - Consequence: a body reading "param1"=first-formal is backwards; the
  15. correct source order is first-pushed=formal1. Call sites reconstructed
  16. from pushes are order-correct as written.
  17. - Proven by this: Express proc9 @02be tests `IN param2` and reports via
  18. ERRORS.proc14(param2, X, param1)=(want,got,ctx); STMT @05d9 pushes
  19. (512, 43): (allowed={9}, code=43) is the only sane reading, so
  20. Express.MatchOpClass is (allowed, errCode) — NOT (errCode, allowed) as
  21. EXPRESS.MOD draft v1 declares. FIX APPLIED HERE (call shapes unchanged);
  22. EXPRESS.MOD's own declaration still needs the same swap (next edit).
  23. - Same proof: Express.proc1 takes (cond, code) — STMT @058a shows
  24. [bool,20] with code on top. EXPRESS.MOD's 1-param CentralError FORWARD
  25. is stale; widened here via Express.CentralError(ok, code) usage and
  26. flagged there.
  27. CORRECTIONS to docs/compiler/60-frontend.md + FRONTEND.md (body-proven):
  28. - proc5 = CASE (jump table via EmitWord, OF, `|`, ELSE), proc6 = FOR
  29. (`:=`/TO/BY, control-var checks) — the map had them swapped.
  30. - STMT dispatch: 121 Loop, 122 Exit, 123 Result, 124 If, 125 For,
  31. 126 Repeat, 127 While, 128 With, 129 Return, 130 Case (125 = CASE default).
  32. - TWO case-shaped procedures exist: proc5 (STMT-driven, full jump-table
  33. parser) vs proc16 (BODY-driven via Accept(14), label-table emitter).
  34. Kept distinct: ParseCaseStmt vs ParseCaseTail. Why BODY re-enters case
  35. parsing on symbol 14 is unexplained — MCD diff must decide.
  36. - 123/129 = RESULT/RETURN inferred from store-vs-epilogue behavior.
  37. CONVENTIONS: Words(X)^[N] = numeric-word pun on ADDRESS/T1 handles
  38. (MCode is untyped; original emissive code TBD). GOTO kept as faithful
  39. jump rendering (restructure to LOOP/EXIT in verification).
  40. Scanner.word22/word23/word25 read as codeSize/listingEnabled/tokenPos
  41. (SCANNER.DEF positional mapping; listingEnabled assignments flagged).
  42. BITSET{..} literal sets on CARDINAL curSymbol kept verbatim (cast TBD). *)
  43. IMPLEMENTATION MODULE Statemen;
  44. IMPORT Compiler, Scanner, Errors, CodeGen, Express, SymTab, Files, Texts, Loader;
  45. FROM SYSTEM IMPORT ADDRESS, ADR, MOVE, WORD;
  46. FROM STORAGE IMPORT MARK, RELEASE;
  47. TYPE Words = POINTER TO ARRAY [0..15] OF WORD;
  48. VAR
  49. needEpilogue: CARDINAL; (* word2: set from body-nonEmpty + tail paths *)
  50. withPending: CARDINAL; (* word3: nonzero = with-base load pending *)
  51. nestDepth: CARDINAL; (* word4: LOOP/CASE/FOR nesting depth *)
  52. exitDepth: CARDINAL; (* word5: LOOP-entry depth for EXIT (= group2 loopExitMark) *)
  53. curBlockNode: ADDRESS; (* word6: BODY param1 (= group1 curRoutine) *)
  54. caseActive: CARDINAL; (* word7: proc16 sets 1 (= group1 caseSeen) *)
  55. withDesc: ADDRESS; (* word8: pending operand for EmitStandardOp(25) *)
  56. exitEmitted: CARDINAL; (* word9: proc17 sets 1 *)
  57. (* ---- helpers shared across both groups ---- *)
  58. PROCEDURE ReserveWords(n: CARDINAL): ADDRESS; FORWARD; (* FIXME: = Scanner.Allocate? *)
  59. PROCEDURE MoveWords(dst, src: ADDRESS; words: CARDINAL); FORWARD; (* FIXME: = MOVE? *)
  60. (* ---- group-1 procedures (FORWARDs; bodies below) ---- *)
  61. PROCEDURE CalcMemOffset(): CARDINAL; FORWARD;
  62. PROCEDURE SyncToStatStart; FORWARD;
  63. PROCEDURE ParseCaseStmt; FORWARD;
  64. PROCEDURE ParseFor; FORWARD;
  65. PROCEDURE ParseWhile; FORWARD;
  66. PROCEDURE ParseRepeat; FORWARD;
  67. PROCEDURE ParseIf; FORWARD;
  68. PROCEDURE ParseLoop; FORWARD;
  69. PROCEDURE ParseExit; FORWARD;
  70. PROCEDURE ParseResult; FORWARD;
  71. PROCEDURE ParseWith; FORWARD;
  72. PROCEDURE ParseReturn; FORWARD;
  73. (* ---- group-2 procedures (FORWARDs; bodies below) ---- *)
  74. PROCEDURE NextSymWrap; FORWARD;
  75. PROCEDURE ParseStatSeqLoop(stop: BITSET): BOOLEAN; FORWARD;
  76. PROCEDURE EmitJumpFixup; FORWARD;
  77. PROCEDURE ParseStatement; FORWARD;
  78. PROCEDURE GuardedStatSeq(follow: BITSET): BOOLEAN; FORWARD;
  79. PROCEDURE ParseCaseTail; FORWARD;
  80. PROCEDURE CloseBlockChain(VAR node: ADDRESS); FORWARD;
  81. PROCEDURE EmitNameHash(VAR name: ARRAY OF CHAR); FORWARD;
  82. PROCEDURE EmitComBytes; FORWARD;
  83. PROCEDURE ParseBeginBlock(tag: CARDINAL); FORWARD; (* audit: frame says 1 param; VAR rest dropped *)
  84. (* STATEMEN group 1 — procedures @0001-0566 *)
  85. (* proc2 @0001 — ~CalcMemOffset. 0 params: reads curBlockNode global *)
  86. PROCEDURE CalcMemOffset(): CARDINAL;
  87. VAR p, q: ADDRESS;
  88. flag: CARDINAL;
  89. BEGIN
  90. {/* 0001 */}
  91. p := Words(curBlockNode)^[6]; (*{0003-0005}*)
  92. IF p = NIL THEN (*{0006-0008} *)
  93. RETURN 0; (*{000a-000b} *)
  94. END;
  95. WHILE Words(p)^[0] # NIL DO (*{000d-0010} *)
  96. p := Words(p)^[0]; (*{0012-0014}*)
  97. END;
  98. q := Words(p)^[2]; (*{0017-0019}*)
  99. IF (Words(q)^[4] > 9) OR (4 IN Words(p)^[3]) THEN (*{001a-0024} *)
  100. flag := 1; (*{0026-0027} *)
  101. ELSE
  102. flag := (Words(q)^[3] + 1) DIV 2; (*{002a-002f} shr 1 *)
  103. END;
  104. RETURN Words(p)^[5] DIV 2 + flag - 3; (*{0030-0038} *)
  105. END CalcMemOffset;
  106. (* proc3 @003b — ~SyncToStatStart *)
  107. PROCEDURE SyncToStatStart;
  108. BEGIN
  109. {/* 003b */}
  110. IF Express.spillFlag # 0 THEN (*{003d-0040} *)
  111. IF withPending # 0 THEN (*{0042-0043} *)
  112. Express.PushOperand(withDesc); (*{0045-0046} FIXME: 1-arg vs 0-arg FORWARD *)
  113. CodeGen.EmitStandardOp(25); (*{0048-004a} *)
  114. END;
  115. IF Words(curBlockNode)^[2] = NIL THEN (*{004c-004f}*)
  116. CodeGen.EmitMiscOp(0, (*{0051-0052} *)
  117. CalcMemOffset() + ORD(Express.spillFlag = 1) * 128); (*{0053-005a} shl 7 *)
  118. ELSIF 8 IN Scanner.scanOpt THEN (*{005e-0062} *)
  119. CodeGen.QueueConst(9); (*{0064-0065} *)
  120. CodeGen.QueueConst(0); (*{0067-0068} *)
  121. CodeGen.QueueConst(0); (*{006a-006b} *)
  122. CodeGen.EmitStandardOp(14); (*{006d-006e} *)
  123. END;
  124. ELSE (*{0072} *)
  125. CodeGen.EmitMiscOp(5, 2); (*{0073-0074} *)
  126. END;
  127. END SyncToStatStart;
  128. (* proc5 @0078, STMT case 130 — ParseCaseStmt. Selector + OF + label ranges
  129. with jump-table emission, `|`-separated arms, ELSE. *)
  130. PROCEDURE ParseCaseStmt;
  131. VAR head: ADDRESS;
  132. chain: ADDRESS;
  133. buf: ADDRESS;
  134. tail: ADDRESS;
  135. prev: ADDRESS;
  136. selTyp: ADDRESS;
  137. lo: CARDINAL;
  138. hi: CARDINAL;
  139. endFix: CARDINAL;
  140. topFix: ADDRESS;
  141. armFix: CARDINAL;
  142. BEGIN
  143. INC(nestDepth); (*{007a-007d} *)
  144. Express.BoolCondHelper; (*{007d} parse CASE selector *)
  145. Express.MatchOpClass(7, 40); (*{007f-0082} *)
  146. selTyp := Express.curDesc.raw[0]; (*{0084-0087} FIXME: typ pun *)
  147. Scanner.ExpectSy(41); (*{0088-008a} OF *)
  148. CodeGen.EmitSystemCall(21); (*{008c-008e} *)
  149. CodeGen.EmitStandardOp(15); (*{008f-0092} jump to dispatch *)
  150. CodeGen.OpenFixup(topFix, TRUE); (*{0094-0097} *)
  151. head := NIL; (*{0099-009a} *)
  152. tail := NIL; (*{009b-009c} *)
  153. WHILE NOT (Scanner.curSym IN BITSET{8,10,13}) DO (*{009d-00a4} *)
  154. armFix := CodeGen.MarkCodePos(14); (*{00a6-00aa} *)
  155. Express.GetTypeDesc(selTyp, ADR(lo), ADR(hi)); (*{00ac-00b1} FIXME: (dest,mode,src) roles *)
  156. prev := NIL; (*{00b3-00b4} *)
  157. chain := head; (*{00b5-00b6} *)
  158. WHILE (chain # NIL) AND (Words(chain)^[1] < lo) DO (*{00b7-00be} *)
  159. prev := chain; (*{00c1-00c2} *)
  160. chain := Words(chain)^[0]; (*{00c3-00c6} *)
  161. END;
  162. Scanner.Allocate(buf, 6); (*{00c8-00cb} *)
  163. Words(buf)^[0] := chain; (*{00cd-00cf} *)
  164. Words(buf)^[1] := hi; (*{00d0-00d2} *)
  165. Words(buf)^[2] := armFix; (*{00d3-00d6} *)
  166. IF (chain # NIL) AND (Words(chain)^[1] = 0) THEN (*{00d7-00d9} *)
  167. tail := buf; (*{00db-00dc} *)
  168. END;
  169. IF (chain # NIL) AND (Words(chain)^[1] > hi) THEN (*{00df-00e2} *)
  170. Express.CentralError(FALSE, 47); (*{00e3-00e5} *)
  171. END;
  172. chain := buf; (*{00e7-00e8} *)
  173. DEC(hi); (*{00e9-00eb} *)
  174. WHILE hi >= lo DO (*{00ec-00ef} expand label range; duplicate check TBD *)
  175. END;
  176. IF prev # NIL THEN (*{00f1-00f3} *)
  177. Words(prev)^[0] := buf; (*{00f5-00f8} *)
  178. ELSE
  179. head := buf; (*{00fa-00fb} *)
  180. END;
  181. Scanner.TestSet(BITSET{1,2}); (*{00fc-00fd} `,`/`:` *)
  182. IF Scanner.AcceptSy(1) THEN (*{00ff-0100} `,`: another label, loop to 00ac *)
  183. END;
  184. Scanner.GetSym; (*{0105} consume `:` *)
  185. WHILE NOT ParseStatSeqLoop(BITSET{8,10,13}) DO END; (*{0107-010b} arm body *)
  186. CodeGen.EmitStandardOp(20); (*{010d-010f} jump to end *)
  187. END;
  188. IF NOT Scanner.AcceptSy(8) THEN (*{0111-0115} `|`: more arms loop to 009d *);
  189. END;
  190. DEC(nestDepth); (*{0117-0119} *)
  191. endFix := CodeGen.InsertFixup(topFix, TRUE); (*{011a-011e} *)
  192. IF head # NIL THEN (*{011f-0121} emit jump table over label chain *)
  193. lo := Words(head)^[1]; (*{0123-0125} *)
  194. CodeGen.EmitStandardOp(19); (*{0126-0128} *)
  195. CodeGen.EmitWord(lo + 32768); (*{012a-012f} *)
  196. CodeGen.EmitWord(tail - lo); (*{0131-0135} FIXME: ADDRESS pun *)
  197. CodeGen.OpenFixup(topFix, FALSE); (*{0137-013a} *)
  198. WHILE Words(head)^[0] = lo DO (*{013c-0140} FIXME *)
  199. CodeGen.CloseFixup(Words(head)^[2] + ORD(NOT endFix), FALSE); (*{0142-0148} *)
  200. head := Words(head)^[0]; (*{014a-014c} *)
  201. ELSE
  202. CodeGen.EmitWord((tail - lo) * 2 + 1); (*{014f-0156} *)
  203. END;
  204. INC(lo); (*{0158-015a} *)
  205. IF head = NIL THEN END; (*{015b-015d} loop to 013c while head#NIL *)
  206. END;
  207. IF Scanner.AcceptSy(10) THEN (*{015f-0160} ELSE *)
  208. WHILE NOT ParseStatSeqLoop(BITSET{13}) DO END; (*{0164-0168} *)
  209. END;
  210. Scanner.GetSym; (*{0187} consume END *)
  211. IF 8 IN Scanner.scanOpt THEN (*{016c-0170} range-check variant epilogue *)
  212. CodeGen.QueueConst(13); (*{0172-0173} *)
  213. CodeGen.QueueConst(0); (*{0175-0176} *)
  214. CodeGen.QueueConst(0); (*{0178-0179} *)
  215. CodeGen.EmitStandardOp(14); (*{017b-017c} *)
  216. END;
  217. IF tail # NIL THEN (*{017e-0180} *)
  218. endFix := CodeGen.InsertFixup(topFix, FALSE); (*{0182-0186} *)
  219. END;
  220. END ParseCaseStmt;
  221. (* proc6 @018b, STMT case 125 — ParseFor. Control var, `:=` lower TO
  222. upper [BY const] DO body END. Largest frame (4 desc buffers). *)
  223. PROCEDURE ParseFor;
  224. VAR ctrl: ADDRESS;
  225. loD: ADDRESS;
  226. hiD: ADDRESS;
  227. tmpD: ADDRESS;
  228. step: CARDINAL;
  229. cflag: CARDINAL;
  230. isInt: CARDINAL;
  231. dummy: CARDINAL;
  232. sub: CARDINAL;
  233. topMark: CARDINAL;
  234. fixA: ADDRESS;
  235. markB: CARDINAL;
  236. BEGIN
  237. {/* 018b */}
  238. Scanner.Allocate(ctrl, 10); (*{018d-018f} FIXME: group wrote ReserveWords *)
  239. Scanner.Allocate(loD, 10); (*{0190-0192} *)
  240. Scanner.Allocate(hiD, 10); (*{0193-0195} *)
  241. Scanner.Allocate(tmpD, 10); (*{0196-0198} *)
  242. Express.EvalConstExpr; (*{0199} control var head *)
  243. Express.MatchOpClass(7, 28); (*{019c-019f} *)
  244. IF Express.curDesc.raw[0] = Compiler.ByteType THEN (*{01a1-01a7} *)
  245. Express.MatchOpClass(5, 28); (*{01aa-01ad} *)
  246. END;
  247. Express.CentralError(NOT (12 IN Words(Express.curDesc.raw[0])^[4]), 24); (*{01af-01b7} FIXME: pun *)
  248. MOVE(Express.curDesc, ctrl, 10); (*{01b9-01bd} FIXME: group wrote MoveWords *)
  249. sub := ORD(Words(Express.curDesc.raw[0])^[4] = 4); (*{01be-01c3} FIXME *)
  250. IF sub # 0 THEN (*{01c4-01c5} rotate saved descs *)
  251. MOVE(ctrl, tmpD, 10); (*{01c7-01cb} FIXME: direction TBD by diff *)
  252. Express.PushExprDesc(ctrl, tmpD); (*{01cb-01ce} FIXME: arity/shape *)
  253. MOVE(tmpD, ctrl, 10);
  254. END;
  255. Express.EmitOp; (*{01d0} proc6 *)
  256. isInt := ORD(Express.curDesc.raw[0] = Compiler.IntType); (*{01d2-01d8} FIXME *)
  257. Scanner.ExpectSy(27); (*{01d9-01db} `:=` *)
  258. Express.BoolCondHelper; (*{01dd} lower bound *)
  259. Express.ConstToCard(Words(ctrl)^[0], 27); (*{01df-01e5} FIXME: ctrlDescTyp *)
  260. MOVE(Express.curDesc, loD, 10); (*{01e5-01e9} *)
  261. Express.PopExprDesc(ctrl); (*{01ea-01eb} FIXME: ADDRESS arg *)
  262. Scanner.ExpectSy(42); (*{01ed-01ef} TO *)
  263. Express.BoolCondHelper; (*{01f1} upper bound *)
  264. Express.ConstToCard(Words(ctrl)^[0], 42); (*{01f3-01f7} *)
  265. MOVE(Express.curDesc, hiD, 10); (*{01f9-01fd} *)
  266. step := 1; (*{01fe-01ff} *)
  267. IF Scanner.AcceptSy(29) THEN (*{0200-0204} BY *)
  268. Express.GetConstVal; (*{0206} proc13 *)
  269. Express.ConstToCard(Compiler.IntType, 29); (*{0208-020c} *)
  270. step := Express.curDesc.raw[2]; (*{020e-0211} const step *)
  271. END;
  272. (*{0212-0269} bound/step validation + counter init (const-fold vs runtime
  273. paths); faithful to raw, minutiae FIXME *)
  274. IF sub # 0 THEN (*{02e4-02e5} subrange control: normalize *)
  275. Express.NormalizeOperand; (*{02e7-02e8} FIXME: group passed tmpD *)
  276. Express.PushOperand(ctrl); (*{02ea-02eb} FIXME: 1-arg vs 0-arg FORWARD *)
  277. CodeGen.SetPendingOp(5, 2, 0, 0); (*{02ed-02f1} *)
  278. END;
  279. WHILE NOT ParseStatSeqLoop(BITSET{13}) DO END; (*{02f3-02f7} body to END *)
  280. Scanner.GetSym; (*{02f9} consume END *)
  281. (*{02fb-033d} loop-back + fixup close-out FIXME *)
  282. Scanner.GetSym;
  283. END ParseFor;
  284. (* proc7 @0341, STMT case 127 — ParseWhile. WHILE cond DO body END. *)
  285. PROCEDURE ParseWhile;
  286. VAR top: CARDINAL;
  287. fix: ADDRESS;
  288. endMark: CARDINAL;
  289. BEGIN
  290. top := CodeGen.MarkCodePos(13); (*{0343-0347} *)
  291. Express.BoolCondHelper; (*{0348} *)
  292. Express.ConstToCard(Compiler.BooleanType, 37); (*{034a-034e} *)
  293. Scanner.ExpectSy(30); (*{0350-0352} DO *)
  294. CodeGen.EmitStandardOp(16); (*{0354-0356} jump-if-false *)
  295. CodeGen.OpenFixup(fix, TRUE); (*{0358-035b} *)
  296. WHILE NOT ParseStatSeqLoop(BITSET{13}) DO END; (*{035d-0361} body to END *)
  297. Scanner.GetSym; (*{0363} consume END *)
  298. CodeGen.EmitStandardOp(15); (*{0365-0366} jump back to top *)
  299. endMark := CodeGen.nextEmitPos; (*{0368-036a} *)
  300. CodeGen.CloseFixup(top, TRUE); (*{036b-036d} *)
  301. IF NOT CodeGen.InsertFixup(fix, TRUE) THEN (*{036f-0374} *)
  302. CodeGen.AdjustFixup(endMark + 1); (*{0376-0378} *)
  303. END;
  304. END ParseWhile;
  305. (* proc8 @037c, STMT case 126 — ParseRepeat. REPEAT body UNTIL cond. *)
  306. PROCEDURE ParseRepeat;
  307. VAR top: CARDINAL;
  308. BEGIN
  309. top := CodeGen.MarkCodePos(12); (*{037e-0382} *)
  310. WHILE NOT ParseStatSeqLoop(BITSET{12}) DO END; (*{0383-0387} to UNTIL *)
  311. Scanner.GetSym; (*{0389} consume UNTIL *)
  312. Express.BoolCondHelper; (*{038b} *)
  313. Express.ConstToCard(Compiler.BooleanType, 12); (*{038d-0392} *)
  314. CodeGen.EmitStandardOp(16); (*{0392-0394} jump-if-false to top *)
  315. CodeGen.CloseFixup(top, TRUE); (*{0396-0398} *)
  316. END ParseRepeat;
  317. (* proc9 @039c, STMT case 124 — ParseIf. IF cond THEN stats
  318. [ELSIF cond THEN stats]... [ELSE stats] END. ELSIF via recursion. *)
  319. PROCEDURE ParseIf;
  320. VAR elseFix: ADDRESS;
  321. endFix: ADDRESS;
  322. savedEmit: CARDINAL;
  323. constCond: BOOLEAN;
  324. chained: CARDINAL;
  325. skipGen: CARDINAL;
  326. BEGIN
  327. Express.BoolCondHelper; (*{039e} *)
  328. Express.ConstToCard(Compiler.BooleanType, 34); (*{03a0-03a4} *)
  329. savedEmit := ORD(CodeGen.emitEnabled); (*{03a6-03a8} FIXME: BOOLEAN pun *)
  330. skipGen := 0; (*{03a9-03aa} *)
  331. constCond := (Express.curDesc.raw[1] = 0); (*{03ab-03af} mode=const *)
  332. IF constCond THEN (*{03b0-03b1} *)
  333. CodeGen.DiscardPending; (*{03b3} *)
  334. skipGen := 2; (*{03b5-03b6} *)
  335. IF Express.curDesc.raw[2] = 0 THEN (*{03b7-03bb} *)
  336. ELSE
  337. skipGen := 1; (*{03bd-03be} *)
  338. END;
  339. CodeGen.emitEnabled := FALSE; (*{03bf-03c0} suppress dead arm *)
  340. END;
  341. Scanner.ExpectSy(35); (*{03c2-03c4} THEN *)
  342. IF NOT constCond THEN (*{03c6-03c8} *)
  343. CodeGen.EmitStandardOp(16); (*{03ca-03cc} jump-if-false *)
  344. CodeGen.OpenFixup(elseFix, TRUE); (*{03ce-03d1} *)
  345. END;
  346. WHILE NOT ParseStatSeqLoop(BITSET{10,11,13}) DO END; (*{03d3-03d7} *)
  347. IF Scanner.AcceptSy(13) THEN (*{03d9-03dc} END: done *)
  348. IF NOT constCond THEN (*{03de-03e0} *)
  349. chained := ORD(CodeGen.InsertFixup(elseFix, TRUE)); (*{03e2-03e6} FIXME pun *)
  350. END;
  351. END;
  352. IF NOT constCond THEN (*{03e9-03eb} *)
  353. CodeGen.EmitStandardOp(15); (*{03ed-03ee} jump over else *)
  354. CodeGen.OpenFixup(endFix, TRUE); (*{03f0-03f3} *)
  355. IF NOT CodeGen.InsertFixup(elseFix, TRUE) THEN (*{03f5-03fa} *)
  356. INC(endFix); (*{03fc-03fe} FIXME: ADDRESS pun *)
  357. END;
  358. END;
  359. CodeGen.emitEnabled := savedEmit # 0; (*{0400-0405} FIXME: exact condition TBD *)
  360. IF Scanner.AcceptSy(11) THEN (*{0407-040a} ELSIF: nested IF *)
  361. ParseIf(); (*{040c} recursion *)
  362. ELSE
  363. Scanner.GetSym; (*{040f} consume ELSE *)
  364. WHILE NOT ParseStatSeqLoop(BITSET{13}) DO END; (*{0411-0415} else stats *)
  365. Scanner.GetSym; (*{0417} consume END *)
  366. END;
  367. IF NOT constCond THEN (*{0419-041a} InsertFixup(endFix, TRUE), result dropped *)
  368. END;
  369. CodeGen.emitEnabled := savedEmit # 0; (*{0426-0427} tail *)
  370. END ParseIf;
  371. (* proc10 @042b, STMT case 121 — ParseLoop. LOOP body END with EXIT support. *)
  372. PROCEDURE ParseLoop;
  373. VAR savedExit: CARDINAL;
  374. fix: ADDRESS;
  375. top: CARDINAL;
  376. endFix: CARDINAL;
  377. BEGIN
  378. savedExit := exitDepth; (*{042d-042e} *)
  379. INC(nestDepth); (*{042f-0431} *)
  380. exitDepth := nestDepth; (*{0432-0433} *)
  381. CodeGen.EmitStandardOp(21); (*{0434-0436} loop-head marker *)
  382. CodeGen.OpenFixup(fix, FALSE); (*{0438-043b} *)
  383. top := CodeGen.MarkCodePos(11); (*{043d-0441} *)
  384. WHILE NOT ParseStatSeqLoop(BITSET{13}) DO END; (*{0442-0446} body to END *)
  385. Scanner.GetSym; (*{0448} consume END *)
  386. CodeGen.EmitStandardOp(15); (*{044a-044b} jump back *)
  387. CodeGen.CloseFixup(top, TRUE); (*{044d-044f} *)
  388. endFix := ORD(CodeGen.InsertFixup(fix, FALSE)); (*{0451-0455} FIXME pun *)
  389. DEC(nestDepth); (*{0456-0458} *)
  390. exitDepth := savedExit; (*{0459-045a} *)
  391. END ParseLoop;
  392. (* proc11 @045d, STMT case 122 — ParseExit. Unwind to enclosing LOOP. *)
  393. PROCEDURE ParseExit;
  394. VAR level: CARDINAL;
  395. BEGIN
  396. Express.CentralError(exitDepth # 0, 26); (*{045f-0463} *)
  397. level := nestDepth; (*{0465-0466} *)
  398. WHILE level > exitDepth DO (*{0467-046a} *)
  399. CodeGen.EmitStandardOp(23); (*{046c-046e} unwind one level *)
  400. DEC(level); (*{0470-0472} *)
  401. END;
  402. CodeGen.EmitStandardOp(20); (*{0475-0477} jump out *)
  403. END ParseExit;
  404. (* proc12 @047b, STMT case 123 — ParseResult. RESULT expr: store value
  405. to function result slot; no exit jump. *)
  406. PROCEDURE ParseResult;
  407. VAR size: CARDINAL;
  408. desc: ADDRESS;
  409. BEGIN
  410. Express.CentralError((Words(curBlockNode)^[4] = 5) AND (Express.spillFlag # 0), 27); (*{047d-0488} *)
  411. Express.CheckAndStore(desc); (*{0491-0493} FIXME: 0-arg FORWARD *)
  412. Express.BoolCondHelper; (*{0496} result value *)
  413. Express.ConstToInt(desc, 33); (*{0498-049b} FIXME: ADDRESS arg *)
  414. Express.PopExprDesc(desc); (*{049d-049e} FIXME: ADDRESS arg *)
  415. IF withPending # 0 THEN (*{04a0-04a1} *)
  416. Express.PushOperand(withDesc); (*{04a3-04a4} FIXME arity *)
  417. CodeGen.EmitStandardOp(25); (*{04a6-04a8} *)
  418. END;
  419. size := 0; (*{04aa-04ab} *)
  420. IF desc # NIL THEN (*{04ac-04ae} *)
  421. size := (Words(desc)^[3] + 1) DIV 2; (*{04b0-04b5} *)
  422. END;
  423. CodeGen.EmitMiscOp(size, (*{04b6} staged *)
  424. CalcMemOffset() + ORD(Express.spillFlag = 1) * 128); (*{04b7-04bf} *)
  425. END ParseResult;
  426. (* proc13 @04c3, STMT case 128 — ParseWith. WITH rec DO body END. *)
  427. PROCEDURE ParseWith;
  428. VAR saved: ADDRESS;
  429. BEGIN
  430. Express.ParseDesignatorTail; (*{04c5} *)
  431. saved := Express.curDesc.raw[0]; (*{04c7-04c9} FIXME: typ pun *)
  432. Express.MatchOpClass(1024, 38); (*{04ca-04cf} *)
  433. IF Words(saved)^[4] IN BITSET{2,3,5} THEN (*{04d1-04de} FIXME set TBD *)
  434. Scanner.OpenScop(SymTab.currentScope, Words(saved)^[0]); (*{04d9-04dd} FIXME *)
  435. END;
  436. IF Words(Express.curDesc.raw[0])^[0] # Compiler.CardType THEN (*{04e0-04e8} FIXME *)
  437. Express.PushOperand(ADR(Express.curDesc)); (*{04e0-04e2} FIXME arity *)
  438. Express.PopExprDesc(ADR(Express.curDesc)); (*{04ea-04ec} FIXME *)
  439. END;
  440. MOVE(Words(SymTab.currentScope)^[2], ADR(Express.curDesc), 10); (*{04ee-04f5} FIXME *)
  441. Scanner.ExpectSy(30); (*{04f6-04f8} DO *)
  442. WHILE NOT ParseStatSeqLoop(BITSET{13}) DO END; (*{04fa-04fe} body to END *)
  443. SymTab.currentScope := Words(SymTab.currentScope)^[0]; (*{0500-0503} FIXME pun *)
  444. Scanner.GetSym; (*{0505} consume END *)
  445. END ParseWith;
  446. (* proc14 @0509, STMT case 129 — ParseReturn. RETURN [value]: routine
  447. exit epilogue with optional value. *)
  448. PROCEDURE ParseReturn;
  449. VAR info: CARDINAL;
  450. BEGIN
  451. Scanner.PushWith; (*{050b} *)
  452. IF caseActive = 0 THEN (*{050d-050f} *)
  453. Scanner.ExpectKd(2); (*{0511-0512} *)
  454. END;
  455. IF Scanner.identKd = 2 THEN (*{0514-0518} function context *)
  456. IF 1 IN Scanner.follSet THEN (*{051a-051e} *)
  457. info := Words(Scanner.curNode)^[6] + 2; (*{0520-0525} *)
  458. ELSE
  459. info := ORD(1 IN Scanner.follSet) - ORD(6 IN Scanner.follSet); (*{0528-052e} *)
  460. END;
  461. CodeGen.QueueConst(Words(Scanner.curNode)^[5] + info * 256); (*{052f-0536} *)
  462. Scanner.GetSym; (*{0538} *)
  463. IF Scanner.AcceptSy(1) THEN (*{053a-053d} `,` before value *)
  464. Express.BoolCondHelper; (*{053f} *)
  465. Express.ParseSelector(FALSE, Compiler.charArrayDesc, NIL); (*{0541-0546} FIXME: 39 dropped *)
  466. ELSE
  467. CodeGen.QueueConst(0); (*{054b-054c} *)
  468. CodeGen.QueueConst(0); (*{054e-054f} *)
  469. END;
  470. ELSE
  471. CodeGen.QueueConst(0); (*{0553-0554} *)
  472. CodeGen.QueueConst(0); (*{0556-0557} *)
  473. CodeGen.QueueConst(0); (*{0559-055a} *)
  474. END;
  475. CodeGen.EmitStandardOp(14); (*{055c-055d} *)
  476. END ParseReturn;
  477. (* STATEMEN group 2 — STMT/STATSE/tails/BODY + internals *)
  478. PROCEDURE NextSymWrap;
  479. (* ~proc1: no head, no call site in statement.txt; GetSym wrapper by name *)
  480. BEGIN
  481. Scanner.GetSym;
  482. END NextSymWrap;
  483. PROCEDURE ParseStatSeqLoop(stop: BITSET): BOOLEAN;
  484. (* ~proc4: every driver is REPEAT proc4(set) UNTIL TRUE with empty body,
  485. so proc4 parses ONE step; 14 pre-emption for nested CASE. *)
  486. BEGIN
  487. IF Scanner.curSym IN stop THEN RETURN TRUE END;
  488. IF Scanner.curSym = 14 THEN (* CaseSym FIXME *)
  489. ParseCaseTail;
  490. ELSE
  491. ParseStatement;
  492. END;
  493. RETURN Scanner.curSym IN stop;
  494. END ParseStatSeqLoop;
  495. PROCEDURE EmitJumpFixup;
  496. (* ~proc15: sole real site STATSE after mark-save, before THEN-expect. *)
  497. BEGIN
  498. CodeGen.DiscardPending;
  499. END EmitJumpFixup;
  500. PROCEDURE ParseStatement; (* STMT @0566 *)
  501. VAR
  502. kw: CARDINAL;
  503. saveSpill: CARDINAL;
  504. saveNest: CARDINAL;
  505. saveLoop: CARDINAL;
  506. saveScope: ADDRESS;
  507. BEGIN
  508. saveSpill := Express.spillTop; (*{0568} FIXME: group wrote spillTop; word3 spill save *)
  509. saveNest := nestDepth; (*{056b} *)
  510. saveLoop := exitDepth; (*{056d} FIXME: group wrote loopExitMark *)
  511. saveScope := SymTab.currentScope; (*{056f} FIXME: ADDRESS pun *)
  512. IF Scanner.curSym = 0 THEN GOTO identLed END; (*{0572} *)
  513. IF Scanner.curSym IN BITSET{8..14} THEN GOTO done END; (*{0577} *)
  514. Express.CentralError((121 <= Scanner.curSym) AND (Scanner.curSym <= 130), 20); (*{0580} *)
  515. kw := Scanner.curSym; (*{058c} *)
  516. Scanner.GetSym; (*{058f} *)
  517. CASE kw OF (*{0591-05a6} default (125) -> ParseFor *)
  518. 121: ParseLoop
  519. | 122: ParseExit
  520. | 123: ParseResult
  521. | 124: ParseIf
  522. | 126: ParseRepeat
  523. | 127: ParseWhile
  524. | 128: ParseWith
  525. | 129: ParseReturn
  526. | 130: ParseCaseStmt
  527. ELSE ParseFor (* 125 *)
  528. END;
  529. GOTO done;
  530. identLed:
  531. Scanner.PushWith; (*{05c4} *)
  532. IF Scanner.identKd = 4 THEN (*{05c6} proc call *)
  533. Express.ParseDesignatorTail; (*{05cc} *)
  534. IF Scanner.AcceptSy(43) THEN (*{05d0} '(' *)
  535. Express.MatchOpClass(512, 43); (*{05d9} *)
  536. Express.CentralError(Express.curDesc.raw[2] = 0, 61); (*{05db} FIXME: scratch2 TBD *)
  537. Express.StoreOperand; (* proc19 *) (*{05e9?} *)
  538. ELSE
  539. Scanner.ExpectSy(27); (*{05e9} ':=' *)
  540. Express.ParseAssignment; (*{05f2?} FIXME: group wrote ParseAssignRhs=proc17 *)
  541. END;
  542. ELSIF Scanner.identKd = 5 THEN (*{05f2} *)
  543. Express.CentralError(Scanner.litType = NIL, 61); (*{05f8} FIXME: pun *)
  544. Express.LoadOperand; (* proc18 *) (*{05e9?} *)
  545. ELSIF Scanner.identKd = 0 THEN (*{0604} *)
  546. Errors.ReportErrorWithText(128, Scanner.tokBuf); (*{0609} *)
  547. ELSE
  548. Errors.ReportError(21); (*{0612} *)
  549. END;
  550. done:
  551. Express.spillTop := saveSpill; (*{0616} *)
  552. (* 061a unwind path (exceptions only): restores exitDepth/currentScope, RAISE *)
  553. END ParseStatement;
  554. PROCEDURE GuardedStatSeq(follow: BITSET): BOOLEAN; (* STATSE @0634 *)
  555. VAR
  556. saveOpts: BITSET;
  557. savePos: CARDINAL;
  558. mark: ADDRESS;
  559. saveCode: CARDINAL;
  560. savePool: CARDINAL;
  561. BEGIN
  562. saveOpts := Scanner.scanOpt; (*{0636} *)
  563. savePos := Scanner.tokPos; (*{0639} FIXME: group wrote word25 *)
  564. Scanner.GetStack(mark); (*{063d} *)
  565. saveCode := CodeGen.nextEmitPos; (*{0641} *)
  566. savePool := SymTab.stringPoolPtr; (*{0644} *)
  567. EmitJumpFixup; (* ~proc15 *) (*{0647} *)
  568. Scanner.TestSet(follow + BITSET{9}); (*{0648} entry assert *)
  569. IF Scanner.AcceptSy(9) THEN (* guarded-seq introducer *)
  570. REPEAT UNTIL ParseStatSeqLoop(follow) END; (*{0654} *)
  571. END;
  572. RETURN TRUE;
  573. (* 065b error-recovery exit: restore scanOptions/tokenPos/mark/codepos/pool,
  574. Errors.RollbackToMark, CodeGen.OpenEmitter, RETURN FALSE *)
  575. END GuardedStatSeq;
  576. PROCEDURE ParseCaseTail; (* proc16 @0683, called only from BODY via ed *)
  577. VAR
  578. tab, cnt: CARDINAL;
  579. step: CARDINAL;
  580. fix1, elseSeen: CARDINAL;
  581. fix2: CARDINAL;
  582. labelAddr: ADDRESS;
  583. BEGIN
  584. caseActive := 1; (*{0685} *)
  585. cnt := 0; (*{0687} *)
  586. tab := 0; (*{0689} *)
  587. IF NOT (Scanner.curSym IN BITSET{8,10,13}) THEN (*{068b} *)
  588. fix1 := CodeGen.MarkCodePos(15); (*{0694} *)
  589. Scanner.PushWith; (*{0699} *)
  590. Scanner.ExpectKd(2); (*{069b} *)
  591. LOOP
  592. Scanner.Allocate(labelAddr, 6); (*{06a0} FIXME: operand slots TBD *)
  593. IF 1 IN Scanner.follSet THEN (* const-label class *)
  594. step := Words(Scanner.curNode)^[0] + 2; (*{06a5?} FIXME *)
  595. ELSE
  596. step := 1 - ORD(6 IN Scanner.follSet);
  597. END;
  598. WHILE tab <> 0 DO
  599. Express.CentralError(Words(tab)^[1] = Words(tab)^[1], 47); (*{06cd} FIXME: dup-label slots TBD *)
  600. tab := Words(tab)^[0]; (* advance FIXME *)
  601. END;
  602. INC(cnt);
  603. Scanner.GetSym;
  604. Scanner.TestSet(BITSET{1,2}); (*{06e0} *)
  605. IF NOT Scanner.AcceptSy(1) THEN EXIT END; (*{06e3} *)
  606. END;
  607. Scanner.GetSym;
  608. REPEAT UNTIL ParseStatSeqLoop(BITSET{8,10,13}) END; (*{06eb} arm seq *)
  609. SyncToStatStart; (* ~proc3 *)
  610. END;
  611. IF NOT Scanner.AcceptSy(8) THEN GOTO noMoreArms END; (*{06f2} '|' *)
  612. GOTO caseLoop; (* back to {068b} FIXME: restructure to LOOP *)
  613. noMoreArms:
  614. elseSeen := ORD(Scanner.AcceptSy(10)); (*{06f8} ELSE FIXME pun *)
  615. IF elseSeen # 0 THEN
  616. INC(cnt);
  617. fix1 := CodeGen.MarkCodePos(15);
  618. REPEAT UNTIL ParseStatSeqLoop(BITSET{13,14}) END; (*{06fb} FIXME set TBD *)
  619. SyncToStatStart;
  620. END;
  621. fix2 := CodeGen.InsertFixup(Scanner.codeSize - 2, FALSE); (*{070e} FIXME: word22 TBD *)
  622. CodeGen.Emit1(cnt);
  623. WHILE tab <> 0 DO
  624. CodeGen.EmitWord(tab);
  625. CodeGen.CloseFixup(tab, FALSE);
  626. tab := Words(tab)^[0]; (* advance FIXME *)
  627. END;
  628. IF elseSeen # 0 THEN
  629. CodeGen.EmitWord(0);
  630. CodeGen.CloseFixup(fix1, FALSE);
  631. END;
  632. END ParseCaseTail;
  633. PROCEDURE CloseBlockChain(VAR node: ADDRESS); (* proc17 @0738, display-call *)
  634. VAR isFirst: BOOLEAN; desc: CARDINAL;
  635. BEGIN
  636. WHILE node # NIL DO (*{073a} *)
  637. IF NOT (0 IN Words(node)^[3]) THEN GOTO advance END; (*{073e} FIXME pun *)
  638. IF 5 IN Words(node)^[3] THEN (*{0745} *)
  639. Scanner.FindIden(SymTab.currentScope, node, 9 IN Scanner.scanOpt); (*{074b} FIXME: group wrote Proc22 6-push id-check; arity TBD *)
  640. IF Scanner.FindIden(SymTab.currentScope, node, 9 IN Scanner.scanOpt) = node THEN
  641. Errors.ReportErrorWithText(128, Scanner.tokBuf); (*{0758} FIXME: raw (5, node, s1, 128) *)
  642. END;
  643. GOTO advance;
  644. END;
  645. IF Words(node)^[4] = 4 THEN (*{0765} *)
  646. IF (Words(node)^[3] - BITSET{3} = BITSET{}) THEN (*{076b} FIXME: s4 > 9 conjunct TBD *)
  647. CloseBlockChain(node); (*{077e} recurse FIXME: node^^ *)
  648. IF Express.spillFlag <> 0 THEN (*{0780} *)
  649. needEpilogue := 1;
  650. desc := Express.curDesc.raw[0]; (*{079c?} FIXME *)
  651. Express.LoadIndirect; (* proc11 *)
  652. IF 3 IN Words(node)^[3] THEN (*{079c} *)
  653. Express.NormalizeOperand; (* proc10 *)
  654. IF Express.spillFlag = 1 THEN CodeGen.EmitMiscOp(5, 23)
  655. ELSE CodeGen.EmitStandardOp(10) END;
  656. ELSE CodeGen.EmitStandardOp(9) END;
  657. Express.PopOperand; (* proc3 *)
  658. END;
  659. RETURN;
  660. END;
  661. GOTO advance;
  662. END;
  663. IF Words(node)^[4] = 6 THEN (*{07c7} *)
  664. isFirst := NOT exitEmitted;
  665. exitEmitted := 1;
  666. CloseBlockChain(node); (* FIXME: node^ pun *)
  667. IF Words(node)^[5] # NIL THEN
  668. needEpilogue := 1;
  669. CodeGen.EmitStandardOp(15);
  670. CodeGen.CloseFixup(Words(node)^[2], FALSE);
  671. IF NOT CodeGen.InsertFixup(Words(node)^[5], FALSE) THEN END;
  672. END;
  673. IF isFirst THEN CodeGen.EmitSystemCall(24) END;
  674. RETURN;
  675. END;
  676. advance:
  677. node := Words(node)^[0]; (*{07f7} FIXME: next link via scratch; pun *)
  678. END;
  679. IF exitEmitted = 0 THEN CodeGen.EmitSystemCall(24) END; (*{07fc} *)
  680. END CloseBlockChain;
  681. PROCEDURE EmitNameHash(VAR name: ARRAY OF CHAR); (* proc18 @0808 FIXME: 2nd param HIGH=128 *)
  682. VAR h, m3, acc: CARDINAL; chunk, i: CARDINAL; c: CARDINAL;
  683. BEGIN
  684. acc := 0; chunk := 0;
  685. REPEAT
  686. h := 0; m3 := 0; c := 0; i := 1; (*{080a-0812} *)
  687. WHILE h <> 37 DO
  688. c := ORD(name[chunk + m3]);
  689. IF c = 0C THEN h := 37;
  690. ELSIF c <= ORD("9") THEN h := c - 22C; (* FIXME: exact bounds TBD *)
  691. ELSE h := c - ORD("A") - ORD(NOT ODD((c AND 64) DIV 2)); (* case-fold FIXME *)
  692. END;
  693. END;
  694. acc := acc + h * i;
  695. i := i * 38; INC(m3);
  696. IF m3 <= 2 THEN (* redo *) END;
  697. CodeGen.EmitWord(acc);
  698. chunk := chunk + 3;
  699. UNTIL chunk > 3;
  700. END EmitNameHash;
  701. PROCEDURE EmitComBytes; (* proc19 @0863, display-call reading BODY locals *)
  702. VAR f: CARDINAL; n: CARDINAL; saveHeap: ADDRESS;
  703. BEGIN
  704. MARK(saveHeap);
  705. CodeGen.EmitMiscOp(3, ORD(Express.spillFlag = 1));
  706. Files.FindFileOnDrives(f, Scanner.tokBuf, "COM"); (*{0863?} FIXME: raw (addr-2, buf, 128) *)
  707. n := 0;
  708. REPEAT
  709. CodeGen.Emit1(0); (* FIXME: bodyL5 byte; Files.FileProc09 TBD *)
  710. INC(n);
  711. UNTIL n = 0; (* FIXME: bodyL3 count TBD *)
  712. RELEASE(saveHeap);
  713. END EmitComBytes;
  714. PROCEDURE ParseBeginBlock(tag: CARDINAL); (* BODY @08a4 *)
  715. VAR
  716. nonEmpty, wasVar: CARDINAL;
  717. fix: CARDINAL;
  718. s2, s5: CARDINAL;
  719. BEGIN
  720. curBlockNode := tag; (*{08a6} *)
  721. Express.spillTop := SymTab.stringPoolPtr; (*{08a8} FIXME: group wrote spillTop *)
  722. nestDepth := 0; exitDepth := 0;
  723. Scanner.listing := TRUE; (*{08b8?} FIXME: group wrote word23 *)
  724. caseActive := 0; exitEmitted := 0;
  725. Scanner.codeSize := CodeGen.nextEmitPos; (*{08b8} FIXME: group wrote word22 *)
  726. wasVar := ORD(Scanner.identKd = 5); (*{08bd} *)
  727. nonEmpty := ORD(Scanner.curSym = 23); (*{08c2} body-lead FIXME *)
  728. IF nonEmpty # 0 THEN
  729. Scanner.GetSym;
  730. WHILE NOT Scanner.AcceptSy(9) DO Scanner.GetSym END; (*{08cd} skip past BEGIN *)
  731. nonEmpty := ORD(Scanner.curSym <> 13);
  732. END;
  733. needEpilogue := nonEmpty; (*{08d8} *)
  734. IF (Words(curBlockNode)^[4] = 5) AND (Express.spillFlag = 0) THEN (*{08da} *)
  735. CodeGen.EmitExtCall3(3, curBlockNode, CalcMemOffset()); (*{08e0} FIXME: 3rd arg BYTEAt TBD *)
  736. IF Compiler.rangeCheckEnabled THEN CodeGen.OpenFixup(fix, TRUE) END; (*{08ea} *)
  737. IF 15 IN Scanner.scanOpt THEN CodeGen.Emit1(255) (*{08f3} *)
  738. ELSE
  739. EmitNameHash(Scanner.tokBuf); (*{08ff} FIXME: raw (g6, s1, 128) *)
  740. CodeGen.EmitWord(0);
  741. END;
  742. Scanner.codeSize := CodeGen.nextEmitPos; (*{0908} FIXME *)
  743. IF wasVar # 0 THEN
  744. Scanner.GetSym;
  745. Scanner.ExpectSy(43); (*{0912} '(' *)
  746. Express.CentralError(Scanner.isLit AND (Scanner.litType = Compiler.CharType), 33); (*{0916} *)
  747. EmitComBytes; (* nested proc19 *)
  748. Scanner.GetSym;
  749. Scanner.ExpectSy(5); (*{0927} ')' *)
  750. fix := ORD(Scanner.AcceptSy(9)); (*{092b} FIXME pun *)
  751. ELSE
  752. CodeGen.EmitStandardOp(22);
  753. CodeGen.Emit1(255);
  754. IF (Express.spillFlag <> 0) AND (withPending # 0) THEN (*{0938} FIXME: group wrote spare3 *)
  755. Express.PushExprDesc(withDesc, Compiler.BitsetType); (*{0938?} FIXME: operand slots TBD *)
  756. CodeGen.EmitStandardOp(24);
  757. Express.PopOperand;
  758. END;
  759. CloseBlockChain(SymTab.currentScope); (*{094c} FIXME: ADDRESS pun *)
  760. IF nonEmpty # 0 THEN REPEAT UNTIL ParseStatSeqLoop(BITSET{13,14}) END END; (*{0951} *)
  761. SyncToStatStart;
  762. IF Scanner.AcceptSy(14) THEN ParseCaseTail END; (*{095c} *)
  763. IF Express.spillFlag <> 0 THEN (*{0962} *)
  764. CodeGen.PokeCodeByte(SymTab.stringPoolPtr - 255, Scanner.codeSize + 1); (* FIXME *)
  765. END;
  766. END;
  767. ELSE
  768. CodeGen.EmitSystemCall(4); (*{0974} *)
  769. IF Compiler.rangeCheckEnabled THEN CodeGen.OpenFixup(fix, FALSE) END; (*{0978} *)
  770. Scanner.codeSize := CodeGen.nextEmitPos; (* FIXME *)
  771. CloseBlockChain(SymTab.currentScope); (* FIXME pun *)
  772. IF nonEmpty # 0 THEN REPEAT UNTIL ParseStatSeqLoop(BITSET{13}) END END; (*{098b} *)
  773. IF needEpilogue # 0 THEN (*{0994} *)
  774. CodeGen.EmitStandardOp(15);
  775. s5 := CodeGen.nextEmitPos; CodeGen.EmitWord(0); (* FIXME *)
  776. s2 := Scanner.codeSize; (* FIXME *)
  777. ELSE
  778. s5 := 0;
  779. END;
  780. END;
  781. IF Compiler.rangeCheckEnabled THEN fix := ORD(CodeGen.InsertFixup(fix, FALSE)) END; (*{09ab} FIXME pun *)
  782. Scanner.listing := FALSE; (* FIXME: group wrote word23 *)
  783. Scanner.ExpectSy(13); (*{09b8} END *)
  784. Scanner.ExpectSt(Scanner.tokBuf); (*{09bb} FIXME: group wrote Proc21; END-name match TBD *)
  785. IF (Words(curBlockNode)^[4] = 5) AND (Express.spillFlag = 0) THEN (*{09c2} *)
  786. Scanner.TestSet(BITSET{3}); (* '.' module end *)
  787. ELSE
  788. Scanner.TestSet(BITSET{9});
  789. END;
  790. IF (NOT Compiler.rangeCheckEnabled) AND (0 IN Scanner.scanOpt) THEN (*{09d7} *)
  791. Texts.WriteString(3, "----- Size = "); (* FIXME: Texts.proc09 idiom *)
  792. Texts.WriteCard(3, CodeGen.nextEmitPos - Scanner.codeSize, 0); (* FIXME: Texts.proc11 *)
  793. END;
  794. IF 4 IN Scanner.scanOpt THEN (*{0a02} *)
  795. Loader.Call("PRINTCOD"); (* FIXME: +CARDINAL 7 *)
  796. END;
  797. END ParseBeginBlock;
  798. BEGIN (* proc0 @0a25 module init *)
  799. END Statemen.