MGen.mod 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208
  1. IMPLEMENTATION MODULE MGen;
  2. IMPORT FileIO, SymTab;
  3. CONST
  4. MaxCode = 8191;
  5. MaxImg = 16383;
  6. MaxGlb = 255;
  7. MaxInit = 255;
  8. MaxLab = 255;
  9. MaxFix = 2047;
  10. MaxLoop = 15;
  11. MaxActDepth = 7;
  12. MaxActN = 63;
  13. (* opcodes, see mc64-spec.md §11 *)
  14. OPdup = 20H; OPswap = 21H;
  15. OPloadGlb = 2DH; OPstoreGlb = 3DH;
  16. OPloadLocal = 2CH; OPstoreLocal = 3CH;
  17. OPloadStk = 2EH;
  18. OPloadIndir0 = 60H; OPstoreIndir0 = 70H;
  19. OPloadOuterN = 11H;
  20. OPloadIndir = 41H; OPstoreIndir = 51H;
  21. OPlocalAddr = 80H; OPglobalAddr = 81H; OPstkAddr = 82H;
  22. OPext = 40H; SUBdrop = 00H;
  23. OPenter = 0D4H; OPprocLeave = 84H; OPfctLeave = 85H;
  24. OPprocCall = 0EDH; OPnestedCall = 0ECH; OPcallFrame = 0EEH;
  25. OPimmB = 8DH; OPimmW = 8EH; OPimm0 = 90H;
  26. OPadd = 0A6H; OPsub = 0A7H; OPumul = 0A8H;
  27. OPudiv = 0A9H; OPumod = 0AAH;
  28. OPaeq0 = 0ABH; OPinc = 0ACH; OPdec = 0ADH;
  29. OPeq = 0A0H; OPne = 0A1H;
  30. OPult = 0A2H; OPugt = 0A3H; OPule = 0A4H; OPuge = 0A5H;
  31. OPilt = 0B2H; OPigt = 0B3H; OPile = 0B4H; OPige = 0B5H;
  32. OPnot = 0B6H;
  33. OPimul = 0B8H; OPidiv = 0B9H;
  34. OPintToLong = 0BDH; OPlongToReal = 0BEH;
  35. OPrCmp = 0D5H; OPrAdd = 0D6H; OPrSub = 0D7H;
  36. OPrMul = 0D8H; OPrDiv = 0D9H;
  37. OPor = 0E6H; OPand = 0E8H;
  38. OPpower2 = 0EAH; OPbitIn = 0E7H;
  39. OPjp = 0E0H; OPjz = 0E1H;
  40. OPsys = 0C3H; OPend = 50H;
  41. (* image layout *)
  42. HeadSize = 64;
  43. DName = 264; DChecksum = 288; DFlags = 292;
  44. DVarCount = 293; DDepCount = 294; DProcs = 296;
  45. DVarSizes = 304;
  46. TYPE
  47. FixRec = RECORD
  48. pos : CARDINAL;
  49. lab : INTEGER;
  50. END;
  51. InitRec = RECORD
  52. idx : CARDINAL;
  53. kind : INTEGER; (* 0 = INTEGER value, 1 = raw 64-bit pattern *)
  54. ival : INTEGER;
  55. bits : LONGCARD;
  56. END;
  57. RealView = RECORD CASE : BOOLEAN OF
  58. | TRUE : r : REAL;
  59. | FALSE : w : LONGCARD;
  60. END;
  61. END;
  62. ActFrame = RECORD
  63. n : CARDINAL;
  64. tmps : ARRAY [0 .. MaxActN] OF INTEGER;
  65. known : BOOLEAN;
  66. nf : CARDINAL;
  67. pn : ARRAY [0 .. 63] OF CHAR;
  68. END;
  69. VAR
  70. code : ARRAY [0 .. MaxCode] OF CHAR;
  71. nCode : CARDINAL;
  72. img : ARRAY [0 .. MaxImg] OF CHAR;
  73. modName : ARRAY [0 .. 63] OF CHAR;
  74. gNames : ARRAY [0 .. MaxGlb] OF ARRAY [0 .. 63] OF CHAR;
  75. nGlb : CARDINAL;
  76. inits : ARRAY [0 .. MaxInit] OF InitRec;
  77. nInit : CARDINAL;
  78. inBody : BOOLEAN;
  79. labs : ARRAY [0 .. MaxLab] OF INTEGER;
  80. nLab : CARDINAL;
  81. fixs : ARRAY [0 .. MaxFix] OF FixRec;
  82. nFix : CARDINAL;
  83. loopSt : ARRAY [0 .. MaxLoop] OF INTEGER;
  84. loopTop : CARDINAL;
  85. noSup : CARDINAL;
  86. noEmit : CARDINAL;
  87. actSt : ARRAY [0 .. MaxActDepth] OF ActFrame;
  88. actTop : CARDINAL;
  89. procAddr : ARRAY [0 .. 64] OF INTEGER;
  90. maxNum : CARDINAL;
  91. mainAddr : CARDINAL;
  92. (* ---------------- byte helpers ---------------- *)
  93. PROCEDURE StrLen (s: ARRAY OF CHAR): CARDINAL;
  94. VAR i : CARDINAL;
  95. BEGIN
  96. i := 0;
  97. WHILE (i < HIGH(s)) & (s[i] # 0C) DO INC(i) END;
  98. RETURN i
  99. END StrLen;
  100. PROCEDURE StrCpy (VAR d: ARRAY OF CHAR; s: ARRAY OF CHAR);
  101. VAR i : CARDINAL;
  102. BEGIN
  103. i := 0;
  104. WHILE (i < HIGH(d)) & (i < HIGH(s)) & (s[i] # 0C) DO
  105. d[i] := s[i]; INC(i)
  106. END;
  107. IF i <= HIGH(d) THEN d[i] := 0C END
  108. END StrCpy;
  109. PROCEDURE EmitByte (b: CARDINAL);
  110. BEGIN
  111. IF noEmit > 0 THEN RETURN END;
  112. IF nCode <= MaxCode THEN
  113. code[nCode] := CHR(b MOD 256); INC(nCode)
  114. END
  115. END EmitByte;
  116. PROCEDURE EmitOp (o: CARDINAL);
  117. BEGIN
  118. EmitByte(o)
  119. END EmitOp;
  120. PROCEDURE EmitOpB (o, b: CARDINAL);
  121. BEGIN
  122. EmitByte(o); EmitByte(b)
  123. END EmitOpB;
  124. PROCEDURE EmitW64 (v: LONGCARD);
  125. VAR j : CARDINAL;
  126. BEGIN
  127. FOR j := 0 TO 7 DO
  128. EmitByte(VAL(CARDINAL, v MOD 256)); v := v DIV 256
  129. END
  130. END EmitW64;
  131. PROCEDURE EmitS64 (rel: INTEGER);
  132. (* Appends a signed 64-bit little-endian offset. *)
  133. VAR mag : CARDINAL;
  134. BEGIN
  135. IF rel >= 0 THEN EmitW64(VAL(LONGCARD, VAL(CARDINAL, rel)))
  136. ELSE
  137. IF rel = -2147483647 - 1 THEN mag := 80000000H
  138. ELSE mag := VAL(CARDINAL, -rel)
  139. END;
  140. EmitW64(0FFFFFFFFFFFFFFFFH - VAL(LONGCARD, mag) + 1H)
  141. END
  142. END EmitS64;
  143. PROCEDURE WriteS64At (off: CARDINAL; rel: INTEGER);
  144. (* Backpatches a signed offset into already-emitted code. *)
  145. VAR mag : CARDINAL;
  146. bits : LONGCARD;
  147. j : CARDINAL;
  148. BEGIN
  149. IF rel >= 0 THEN bits := VAL(LONGCARD, VAL(CARDINAL, rel))
  150. ELSE
  151. IF rel = -2147483647 - 1 THEN mag := 80000000H
  152. ELSE mag := VAL(CARDINAL, -rel)
  153. END;
  154. bits := 0FFFFFFFFFFFFFFFFH - VAL(LONGCARD, mag) + 1H
  155. END;
  156. FOR j := 0 TO 7 DO
  157. code[off + j] := CHR(VAL(CARDINAL, bits MOD 256));
  158. bits := bits DIV 256
  159. END
  160. END WriteS64At;
  161. PROCEDURE FindVar (name: ARRAY OF CHAR): INTEGER;
  162. VAR i : CARDINAL;
  163. BEGIN
  164. i := 0;
  165. WHILE i < nGlb DO
  166. IF SymTab.Equal(gNames[i], name) THEN RETURN VAL(INTEGER, i) END;
  167. INC(i)
  168. END;
  169. RETURN -1
  170. END FindVar;
  171. PROCEDURE AssignSlot (name: ARRAY OF CHAR): INTEGER;
  172. BEGIN
  173. IF nGlb > MaxGlb THEN RETURN -1 END;
  174. StrCpy(gNames[nGlb], name);
  175. INC(nGlb);
  176. RETURN VAL(INTEGER, nGlb - 1)
  177. END AssignSlot;
  178. (* ---------------- module / data section ---------------- *)
  179. PROCEDURE OpenModule (name: ARRAY OF CHAR);
  180. VAR i : CARDINAL;
  181. dummy : INTEGER;
  182. BEGIN
  183. StrCpy(modName, name);
  184. nCode := 0; nGlb := 0; nInit := 0;
  185. nLab := 0; nFix := 0; loopTop := 0; noSup := 0; noEmit := 0;
  186. actTop := 0;
  187. maxNum := 0; mainAddr := 0;
  188. i := 0;
  189. WHILE i <= 64 DO procAddr[i] := -1; INC(i) END;
  190. inBody := FALSE;
  191. i := 0;
  192. WHILE i <= MaxGlb DO gNames[i][0] := 0C; INC(i) END;
  193. (* slots 0..3 belong to the print helper *)
  194. dummy := AssignSlot(""); dummy := AssignSlot("");
  195. dummy := AssignSlot(""); dummy := AssignSlot("")
  196. END OpenModule;
  197. PROCEDURE DeclVar (name: ARRAY OF CHAR);
  198. VAR idx : INTEGER;
  199. BEGIN
  200. idx := AssignSlot(name);
  201. IF idx < 0 THEN RETURN END
  202. END DeclVar;
  203. PROCEDURE BufInit (idx: INTEGER; kind: INTEGER; ival: INTEGER;
  204. bits: LONGCARD);
  205. BEGIN
  206. IF nInit > MaxInit THEN RETURN END;
  207. inits[nInit].idx := VAL(CARDINAL, idx);
  208. inits[nInit].kind := kind;
  209. inits[nInit].ival := ival;
  210. inits[nInit].bits := bits;
  211. INC(nInit)
  212. END BufInit;
  213. PROCEDURE DeclConst (name: ARRAY OF CHAR; lit: LitStr; t: INTEGER);
  214. VAR idx : INTEGER;
  215. cls : INTEGER;
  216. v : INTEGER;
  217. c : CARDINAL;
  218. b : LONGCARD;
  219. BEGIN
  220. idx := AssignSlot(name);
  221. IF idx < 0 THEN RETURN END;
  222. cls := SymTab.ClassOf(t);
  223. IF ~IsLit(lit) OR (cls = SymTab.ClStr) THEN
  224. BufInit(idx, 0, 0, 0H); RETURN
  225. END;
  226. IF cls = SymTab.ClReal THEN
  227. IF ParseReal(lit, b) THEN BufInit(idx, 1, 0, b)
  228. ELSE BufInit(idx, 1, 0, 0H)
  229. END
  230. ELSIF SymTab.Equal(lit, "TRUE") THEN BufInit(idx, 0, 1, 0H)
  231. ELSIF SymTab.Equal(lit, "FALSE") THEN BufInit(idx, 0, 0, 0H)
  232. ELSIF ParseInt(lit, v) THEN BufInit(idx, 0, v, 0H)
  233. ELSIF ParseCard(lit, c) THEN
  234. BufInit(idx, 1, 0, VAL(LONGCARD, c))
  235. ELSE BufInit(idx, 0, 0, 0H)
  236. END
  237. END DeclConst;
  238. PROCEDURE DeclConstInt (name: ARRAY OF CHAR; v: INTEGER);
  239. VAR idx : INTEGER;
  240. BEGIN
  241. idx := AssignSlot(name);
  242. IF idx < 0 THEN RETURN END;
  243. BufInit(idx, 0, v, 0H)
  244. END DeclConstInt;
  245. PROCEDURE PushValue (kind: INTEGER; ival: INTEGER; bits: LONGCARD);
  246. BEGIN
  247. IF kind = 0 THEN PushInt(ival) ELSE PushBits(bits) END
  248. END PushValue;
  249. PROCEDURE BeginBody;
  250. VAR i : CARDINAL;
  251. BEGIN
  252. IF inBody THEN RETURN END;
  253. inBody := TRUE;
  254. mainAddr := nCode;
  255. i := 0;
  256. WHILE i < nInit DO
  257. PushValue(inits[i].kind, inits[i].ival, inits[i].bits);
  258. EmitOpB(OPstoreGlb, inits[i].idx);
  259. INC(i)
  260. END
  261. END BeginBody;
  262. (* ---------------- loads, stores, pushes ---------------- *)
  263. PROCEDURE LoadVar (name: ARRAY OF CHAR);
  264. VAR idx : INTEGER;
  265. BEGIN
  266. idx := FindVar(name);
  267. IF idx < 0 THEN EmitOp(OPimm0)
  268. ELSE EmitOpB(OPloadGlb, VAL(CARDINAL, idx))
  269. END
  270. END LoadVar;
  271. PROCEDURE StoreVar (name: ARRAY OF CHAR);
  272. VAR idx : INTEGER;
  273. BEGIN
  274. idx := FindVar(name);
  275. IF idx < 0 THEN EmitOp(OPext); EmitOp(SUBdrop)
  276. ELSE EmitOpB(OPstoreGlb, VAL(CARDINAL, idx))
  277. END
  278. END StoreVar;
  279. PROCEDURE LoadTemp (t: INTEGER);
  280. BEGIN
  281. EmitOpB(OPloadGlb, VAL(CARDINAL, t))
  282. END LoadTemp;
  283. PROCEDURE StoreTemp (t: INTEGER);
  284. BEGIN
  285. EmitOpB(OPstoreGlb, VAL(CARDINAL, t))
  286. END StoreTemp;
  287. PROCEDURE TempGlobal (): INTEGER;
  288. VAR idx : INTEGER;
  289. BEGIN
  290. idx := AssignSlot("");
  291. IF idx < 0 THEN RETURN 4 END;
  292. RETURN idx
  293. END TempGlobal;
  294. (* ---------------- frames and procedures ---------------- *)
  295. PROCEDURE EmitSlotB (op: CARDINAL; sl: INTEGER);
  296. (* Byte operand for a (possibly negative) frame slot. *)
  297. BEGIN
  298. IF sl >= 0 THEN EmitOpB(op, VAL(CARDINAL, sl))
  299. ELSE EmitOpB(op, 256 - VAL(CARDINAL, -sl))
  300. END
  301. END EmitSlotB;
  302. PROCEDURE LoadLocal (sl: INTEGER);
  303. BEGIN
  304. EmitSlotB(OPloadLocal, sl)
  305. END LoadLocal;
  306. PROCEDURE StoreLocal (sl: INTEGER);
  307. BEGIN
  308. EmitSlotB(OPstoreLocal, sl)
  309. END StoreLocal;
  310. PROCEDURE LoadIndir0;
  311. BEGIN
  312. EmitOp(OPloadIndir0)
  313. END LoadIndir0;
  314. PROCEDURE StoreIndir0;
  315. BEGIN
  316. EmitOp(OPstoreIndir0)
  317. END StoreIndir0;
  318. PROCEDURE FrameAddr (sl: INTEGER; np: CARDINAL);
  319. (* Pushes (display-frame(np) + slot*8): 11H np, then the offset. *)
  320. BEGIN
  321. EmitOpB(OPloadOuterN, np);
  322. IF sl >= 0 THEN EmitOpB(OPstkAddr, VAL(CARDINAL, sl))
  323. ELSE
  324. PushInt(sl * 8);
  325. EmitOp(OPadd)
  326. END
  327. END FrameAddr;
  328. PROCEDURE LoadIndir;
  329. BEGIN
  330. EmitOp(OPloadIndir)
  331. END LoadIndir;
  332. PROCEDURE StoreIndir;
  333. BEGIN
  334. EmitOp(OPstoreIndir)
  335. END StoreIndir;
  336. PROCEDURE LocalAddr (sl: INTEGER);
  337. BEGIN
  338. EmitSlotB(OPlocalAddr, sl)
  339. END LocalAddr;
  340. PROCEDURE GlobalAddr (name: ARRAY OF CHAR);
  341. VAR idx : INTEGER;
  342. BEGIN
  343. idx := FindVar(name);
  344. IF idx < 0 THEN EmitOp(OPimm0)
  345. ELSE EmitOpB(OPglobalAddr, VAL(CARDINAL, idx))
  346. END
  347. END GlobalAddr;
  348. PROCEDURE PushAddr (name: ARRAY OF CHAR);
  349. (* VAR-actual address: slot contents for VAR params, slot address
  350. for plain variables; display-aware. *)
  351. VAR k, d, D, sl : INTEGER;
  352. np : CARDINAL;
  353. BEGIN
  354. k := SymTab.SymKind(name);
  355. d := SymTab.SymDepth(name);
  356. D := SymTab.CurDepth();
  357. sl := SymTab.SymSlot(name);
  358. IF (k # SymTab.KindVar) & (k # SymTab.KindParam)
  359. & (k # SymTab.KindVarPar) THEN
  360. EmitOp(OPimm0); RETURN
  361. END;
  362. IF k = SymTab.KindVarPar THEN
  363. IF D = d THEN LoadLocal(sl)
  364. ELSE
  365. np := VAL(CARDINAL, D - 1 - d);
  366. FrameAddr(sl, np);
  367. LoadIndir
  368. END
  369. ELSE
  370. IF d = 0 THEN GlobalAddr(name)
  371. ELSIF D = d THEN LocalAddr(sl)
  372. ELSE
  373. np := VAL(CARDINAL, D - 1 - d);
  374. FrameAddr(sl, np)
  375. END
  376. END
  377. END PushAddr;
  378. PROCEDURE StoreSetup (name: ARRAY OF CHAR);
  379. (* Early address for indirect stores; call before the value code. *)
  380. VAR k, d, D, sl : INTEGER;
  381. np : CARDINAL;
  382. BEGIN
  383. k := SymTab.SymKind(name);
  384. IF (k # SymTab.KindVar) & (k # SymTab.KindParam)
  385. & (k # SymTab.KindVarPar) THEN
  386. RETURN
  387. END;
  388. d := SymTab.SymDepth(name);
  389. D := SymTab.CurDepth();
  390. sl := SymTab.SymSlot(name);
  391. IF k = SymTab.KindVarPar THEN
  392. IF D = d THEN LoadLocal(sl)
  393. ELSE
  394. np := VAL(CARDINAL, D - 1 - d);
  395. FrameAddr(sl, np);
  396. LoadIndir
  397. END
  398. ELSIF (d # 0) & (D # d) THEN
  399. np := VAL(CARDINAL, D - 1 - d);
  400. FrameAddr(sl, np)
  401. END
  402. END StoreSetup;
  403. PROCEDURE StoreFinish (name: ARRAY OF CHAR);
  404. (* Completes the store; call after the value code. *)
  405. VAR k, d, D, sl : INTEGER;
  406. BEGIN
  407. k := SymTab.SymKind(name);
  408. IF (k # SymTab.KindVar) & (k # SymTab.KindParam)
  409. & (k # SymTab.KindVarPar) THEN
  410. RETURN
  411. END;
  412. d := SymTab.SymDepth(name);
  413. D := SymTab.CurDepth();
  414. sl := SymTab.SymSlot(name);
  415. IF d = 0 THEN StoreVar(name)
  416. ELSIF D = d THEN
  417. IF k = SymTab.KindVarPar THEN StoreIndir0
  418. ELSE StoreLocal(sl)
  419. END
  420. ELSE
  421. IF k = SymTab.KindVarPar THEN StoreIndir0
  422. ELSE StoreIndir
  423. END
  424. END
  425. END StoreFinish;
  426. PROCEDURE PushVar (name: ARRAY OF CHAR);
  427. (* Frame-aware value load (see PushAddr for the address twin). *)
  428. VAR k, d, D, sl : INTEGER;
  429. np : CARDINAL;
  430. BEGIN
  431. k := SymTab.SymKind(name);
  432. d := SymTab.SymDepth(name);
  433. D := SymTab.CurDepth();
  434. sl := SymTab.SymSlot(name);
  435. IF (k # SymTab.KindVar) & (k # SymTab.KindParam)
  436. & (k # SymTab.KindVarPar) THEN
  437. EmitOp(OPimm0); RETURN
  438. END;
  439. IF d = 0 THEN LoadVar(name)
  440. ELSIF D = d THEN
  441. IF k = SymTab.KindVarPar THEN
  442. LoadLocal(sl); LoadIndir0
  443. ELSE LoadLocal(sl)
  444. END
  445. ELSE
  446. np := VAL(CARDINAL, D - 1 - d);
  447. FrameAddr(sl, np);
  448. LoadIndir;
  449. IF k = SymTab.KindVarPar THEN LoadIndir0 END
  450. END
  451. END PushVar;
  452. PROCEDURE ProcEntry (num: INTEGER; nLoc: CARDINAL);
  453. VAR k : CARDINAL;
  454. BEGIN
  455. IF (num >= 0) & (num <= 64) THEN
  456. procAddr[num] := VAL(INTEGER, nCode);
  457. IF VAL(CARDINAL, num) > maxNum THEN
  458. maxNum := VAL(CARDINAL, num)
  459. END
  460. END;
  461. IF nLoc > 255 THEN k := 255 ELSE k := nLoc END;
  462. EmitOpB(OPenter, 255 - k)
  463. END ProcEntry;
  464. PROCEDURE CallProc (num: INTEGER);
  465. BEGIN
  466. EmitOpB(OPprocCall, VAL(CARDINAL, num))
  467. END CallProc;
  468. PROCEDURE CallNested (num: INTEGER);
  469. BEGIN
  470. EmitOpB(OPnestedCall, VAL(CARDINAL, num))
  471. END CallNested;
  472. PROCEDURE CallDisplay (num: INTEGER; np: CARDINAL);
  473. BEGIN
  474. EmitOpB(OPloadOuterN, np);
  475. EmitOpB(OPcallFrame, VAL(CARDINAL, num))
  476. END CallDisplay;
  477. PROCEDURE Leave (nPar: CARDINAL; func: BOOLEAN);
  478. BEGIN
  479. IF nPar > 255 THEN nPar := 255 END;
  480. IF func THEN EmitOpB(OPfctLeave, nPar)
  481. ELSE EmitOpB(OPprocLeave, nPar)
  482. END
  483. END Leave;
  484. (* ---------------- actual parameters ---------------- *)
  485. PROCEDURE ActFrameIdx (): CARDINAL;
  486. (* Active frame, capped (nesting past the cap reuses the top). *)
  487. BEGIN
  488. IF actTop = 0 THEN RETURN 0 END;
  489. IF actTop - 1 > MaxActDepth THEN RETURN MaxActDepth END;
  490. RETURN actTop - 1
  491. END ActFrameIdx;
  492. PROCEDURE ActBegin (pn: ARRAY OF CHAR);
  493. VAR fr : CARDINAL;
  494. BEGIN
  495. fr := actTop;
  496. IF fr > MaxActDepth THEN fr := MaxActDepth
  497. ELSE INC(actTop)
  498. END;
  499. StrCpy(actSt[fr].pn, pn);
  500. actSt[fr].n := 0;
  501. actSt[fr].known := SymTab.Lookup(pn)
  502. & (SymTab.SymKind(pn) = SymTab.KindProc);
  503. IF actSt[fr].known THEN actSt[fr].nf := SymTab.ProcNPar(pn)
  504. ELSE actSt[fr].nf := 0
  505. END
  506. END ActBegin;
  507. PROCEDURE ActValue (t: INTEGER; v: BOOLEAN;
  508. vn: ARRAY OF CHAR): INTEGER;
  509. VAR fr : CARDINAL;
  510. i : CARDINAL;
  511. ftyp : INTEGER;
  512. fv : BOOLEAN;
  513. err : INTEGER;
  514. BEGIN
  515. err := 0;
  516. fr := ActFrameIdx();
  517. i := actSt[fr].n;
  518. IF i > MaxActN THEN
  519. EmitOp(OPext); EmitOp(SUBdrop);
  520. actSt[fr].n := i + 1;
  521. RETURN 1
  522. END;
  523. IF actSt[fr].known & (i < actSt[fr].nf) THEN
  524. ftyp := SymTab.ParamType(actSt[fr].pn, i);
  525. fv := SymTab.ParamIsVar(actSt[fr].pn, i);
  526. IF fv THEN
  527. IF ~v THEN err := 1
  528. ELSIF ~SymTab.SameType(t, ftyp) THEN err := 1
  529. END;
  530. EmitOp(OPext); EmitOp(SUBdrop);
  531. PushAddr(vn)
  532. ELSE
  533. IF ~SymTab.Assignable(t, ftyp) THEN err := 1
  534. ELSIF SymTab.IsIntFamily(t)
  535. & (SymTab.ClassOf(ftyp) = SymTab.ClReal) THEN
  536. IntToReal
  537. END
  538. END
  539. END;
  540. actSt[fr].tmps[i] := TempGlobal();
  541. StoreTemp(actSt[fr].tmps[i]);
  542. actSt[fr].n := i + 1;
  543. RETURN err
  544. END ActValue;
  545. PROCEDURE ActEnd (pn: ARRAY OF CHAR; sfx, inExpr: BOOLEAN): INTEGER;
  546. VAR fr : CARDINAL;
  547. i : CARDINAL;
  548. n, num, F, d : INTEGER;
  549. BEGIN
  550. fr := ActFrameIdx();
  551. IF actTop > 0 THEN DEC(actTop) END;
  552. n := VAL(INTEGER, actSt[fr].n);
  553. IF ~SymTab.Lookup(pn) THEN
  554. IF inExpr THEN EmitOp(OPimm0) END;
  555. RETURN 0
  556. END;
  557. IF (SymTab.SymKind(pn) # SymTab.KindProc)
  558. OR sfx
  559. OR (n # VAL(INTEGER, SymTab.ProcNPar(pn))) THEN
  560. IF inExpr THEN EmitOp(OPimm0) END;
  561. RETURN 1
  562. END;
  563. IF inExpr & (SymTab.ProcRet(pn) = SymTab.InvalidType) THEN
  564. EmitOp(OPimm0);
  565. RETURN 1
  566. END;
  567. i := actSt[fr].n;
  568. WHILE i > 0 DO
  569. DEC(i);
  570. IF i <= MaxActN THEN LoadTemp(actSt[fr].tmps[i]) END
  571. END;
  572. num := SymTab.ProcNum(pn);
  573. F := SymTab.CurDepth();
  574. d := SymTab.SymDepth(pn);
  575. IF d = 0 THEN CallProc(num)
  576. ELSIF F = d THEN CallNested(num)
  577. ELSE CallDisplay(num, VAL(CARDINAL, F - 1 - d))
  578. END;
  579. IF ~inExpr & (SymTab.ProcRet(pn) # SymTab.InvalidType) THEN
  580. EmitOp(OPext); EmitOp(SUBdrop)
  581. END;
  582. RETURN 0
  583. END ActEnd;
  584. PROCEDURE EmitMag (c: CARDINAL);
  585. BEGIN
  586. IF c <= 255 THEN EmitOpB(OPimmB, c)
  587. ELSE EmitOp(OPimmW); EmitW64(VAL(LONGCARD, c))
  588. END
  589. END EmitMag;
  590. PROCEDURE PushInt (v: INTEGER);
  591. VAR mag : CARDINAL;
  592. BEGIN
  593. IF (v >= 0) & (v <= 15) THEN EmitOp(OPimm0 + VAL(CARDINAL, v))
  594. ELSIF v < 0 THEN
  595. IF v = -2147483647 - 1 THEN mag := 80000000H
  596. ELSE mag := VAL(CARDINAL, -v)
  597. END;
  598. EmitOp(OPimm0); EmitMag(mag); EmitOp(OPsub)
  599. ELSE EmitMag(VAL(CARDINAL, v))
  600. END
  601. END PushInt;
  602. PROCEDURE PushBits (b: LONGCARD);
  603. BEGIN
  604. EmitOp(OPimmW); EmitW64(b)
  605. END PushBits;
  606. (* ---------------- literal parsing ---------------- *)
  607. PROCEDURE DigVal (ch: CHAR): INTEGER;
  608. BEGIN
  609. IF (ch >= "0") & (ch <= "9") THEN RETURN ORD(ch) - ORD("0") END;
  610. IF (ch >= "A") & (ch <= "F") THEN RETURN ORD(ch) - ORD("A") + 10 END;
  611. IF (ch >= "a") & (ch <= "f") THEN RETURN ORD(ch) - ORD("a") + 10 END;
  612. RETURN -1
  613. END DigVal;
  614. PROCEDURE ParseCard (s: ARRAY OF CHAR; VAR v: CARDINAL): BOOLEAN;
  615. VAR i, n : CARDINAL;
  616. hex : BOOLEAN;
  617. d : INTEGER;
  618. acc : LONGCARD;
  619. BEGIN
  620. v := 0;
  621. n := StrLen(s);
  622. IF n = 0 THEN RETURN FALSE END;
  623. hex := (s[n - 1] = "H") OR (s[n - 1] = "h");
  624. IF hex THEN DEC(n) END;
  625. IF n = 0 THEN RETURN FALSE END;
  626. acc := 0H; i := 0;
  627. WHILE i < n DO
  628. d := DigVal(s[i]);
  629. IF hex THEN
  630. IF d < 0 THEN RETURN FALSE END;
  631. acc := acc * 16 + VAL(LONGCARD, VAL(CARDINAL, d))
  632. ELSE
  633. IF (d < 0) OR (d > 9) THEN RETURN FALSE END;
  634. acc := acc * 10 + VAL(LONGCARD, VAL(CARDINAL, d))
  635. END;
  636. IF acc > 0FFFFFFFFH THEN RETURN FALSE END;
  637. INC(i)
  638. END;
  639. v := VAL(CARDINAL, acc);
  640. RETURN TRUE
  641. END ParseCard;
  642. PROCEDURE ParseInt (s: ARRAY OF CHAR; VAR v: INTEGER): BOOLEAN;
  643. VAR i : CARDINAL;
  644. neg : BOOLEAN;
  645. t : ARRAY [0 .. 63] OF CHAR;
  646. c : CARDINAL;
  647. lim : LONGCARD;
  648. BEGIN
  649. v := 0;
  650. IF (StrLen(s) = 0) THEN RETURN FALSE END;
  651. neg := s[0] = "-";
  652. IF neg THEN
  653. i := 1;
  654. WHILE s[i] # 0C DO
  655. IF i - 1 > HIGH(t) THEN RETURN FALSE END;
  656. t[i - 1] := s[i]; INC(i)
  657. END;
  658. IF i - 1 > HIGH(t) THEN RETURN FALSE END;
  659. t[i - 1] := 0C
  660. ELSE StrCpy(t, s)
  661. END;
  662. IF ~ParseCard(t, c) THEN RETURN FALSE END;
  663. IF neg THEN lim := 80000000H ELSE lim := 7FFFFFFFH END;
  664. IF VAL(LONGCARD, c) > lim THEN RETURN FALSE END;
  665. IF neg THEN
  666. IF VAL(LONGCARD, c) = 80000000H THEN v := -2147483647 - 1
  667. ELSE v := -VAL(INTEGER, c)
  668. END
  669. ELSE v := VAL(INTEGER, c)
  670. END;
  671. RETURN TRUE
  672. END ParseInt;
  673. PROCEDURE ParseReal (s: ARRAY OF CHAR; VAR b: LONGCARD): BOOLEAN;
  674. VAR i : CARDINAL;
  675. neg, esign : BOOLEAN;
  676. m, scale : REAL;
  677. e, d : CARDINAL;
  678. rv : RealView;
  679. BEGIN
  680. b := 0H;
  681. i := 0; neg := FALSE;
  682. IF s[0] = "-" THEN neg := TRUE; INC(i) END;
  683. IF (s[i] < "0") OR (s[i] > "9") THEN RETURN FALSE END;
  684. m := 0.0;
  685. WHILE (s[i] >= "0") & (s[i] <= "9") DO
  686. m := m * 10.0 + VAL(REAL, VAL(CARDINAL, ORD(s[i]) - ORD("0")));
  687. INC(i)
  688. END;
  689. IF s[i] = "." THEN
  690. INC(i);
  691. IF (s[i] < "0") OR (s[i] > "9") THEN RETURN FALSE END;
  692. scale := 10.0;
  693. WHILE (s[i] >= "0") & (s[i] <= "9") DO
  694. m := m + VAL(REAL, VAL(CARDINAL, ORD(s[i]) - ORD("0"))) / scale;
  695. scale := scale * 10.0;
  696. INC(i)
  697. END
  698. END;
  699. IF (s[i] = "E") OR (s[i] = "e") THEN
  700. INC(i); esign := FALSE;
  701. IF s[i] = "+" THEN INC(i)
  702. ELSIF s[i] = "-" THEN esign := TRUE; INC(i)
  703. END;
  704. IF (s[i] < "0") OR (s[i] > "9") THEN RETURN FALSE END;
  705. e := 0;
  706. WHILE (s[i] >= "0") & (s[i] <= "9") DO
  707. d := VAL(CARDINAL, ORD(s[i]) - ORD("0"));
  708. IF e <= 9999 THEN e := e * 10 + d END;
  709. INC(i)
  710. END;
  711. WHILE e > 0 DO
  712. IF esign THEN m := m / 10.0 ELSE m := m * 10.0 END;
  713. DEC(e)
  714. END
  715. END;
  716. IF s[i] # 0C THEN RETURN FALSE END;
  717. IF neg THEN m := -m END;
  718. rv.r := m;
  719. b := rv.w;
  720. RETURN TRUE
  721. END ParseReal;
  722. PROCEDURE CharOrd (s: ARRAY OF CHAR): INTEGER;
  723. BEGIN
  724. IF StrLen(s) >= 2 THEN RETURN ORD(s[1]) END;
  725. RETURN 0
  726. END CharOrd;
  727. PROCEDURE NegFold (a: ARRAY OF CHAR; VAR q: LitStr);
  728. (* Safe for a and q being the same variable. *)
  729. VAR tmp : LitStr;
  730. i, j : CARDINAL;
  731. BEGIN
  732. StrCpy(tmp, a);
  733. IF StrLen(tmp) = 0 THEN StrCpy(q, ""); RETURN END;
  734. IF tmp[0] = "-" THEN
  735. i := 1; j := 0;
  736. WHILE (tmp[i] # 0C) & (j < HIGH(q)) DO
  737. q[j] := tmp[i]; INC(i); INC(j)
  738. END;
  739. IF j <= HIGH(q) THEN q[j] := 0C END
  740. ELSE
  741. StrCpy(q, "-");
  742. i := 0; j := StrLen(q);
  743. WHILE (tmp[i] # 0C) & (j < HIGH(q)) DO
  744. q[j] := tmp[i]; INC(i); INC(j)
  745. END;
  746. IF j <= HIGH(q) THEN q[j] := 0C END
  747. END
  748. END NegFold;
  749. PROCEDURE IsLit (s: ARRAY OF CHAR): BOOLEAN;
  750. BEGIN
  751. RETURN StrLen(s) > 0
  752. END IsLit;
  753. (* ---------------- operators ---------------- *)
  754. PROCEDURE Add;
  755. BEGIN EmitOp(OPadd) END Add;
  756. PROCEDURE Sub;
  757. BEGIN EmitOp(OPsub) END Sub;
  758. PROCEDURE MulU;
  759. BEGIN EmitOp(OPumul) END MulU;
  760. PROCEDURE DivU;
  761. BEGIN EmitOp(OPudiv) END DivU;
  762. PROCEDURE ModU;
  763. BEGIN EmitOp(OPumod) END ModU;
  764. PROCEDURE MulI;
  765. BEGIN EmitOp(OPimul) END MulI;
  766. PROCEDURE DivI;
  767. BEGIN EmitOp(OPidiv) END DivI;
  768. PROCEDURE ModI (t: INTEGER);
  769. (* [a b] -> a MOD b (truncation) via temp t. *)
  770. BEGIN
  771. StoreTemp(t);
  772. EmitOp(OPdup);
  773. LoadTemp(t);
  774. EmitOp(OPidiv);
  775. LoadTemp(t);
  776. EmitOp(OPimul);
  777. EmitOp(OPsub)
  778. END ModI;
  779. PROCEDURE RealAdd;
  780. BEGIN EmitOp(OPrAdd) END RealAdd;
  781. PROCEDURE RealSub;
  782. BEGIN EmitOp(OPrSub) END RealSub;
  783. PROCEDURE RealMul;
  784. BEGIN EmitOp(OPrMul) END RealMul;
  785. PROCEDURE RealDiv;
  786. BEGIN EmitOp(OPrDiv) END RealDiv;
  787. PROCEDURE And;
  788. BEGIN EmitOp(OPand) END And;
  789. PROCEDURE Or;
  790. BEGIN EmitOp(OPor) END Or;
  791. PROCEDURE Not;
  792. BEGIN EmitOp(OPnot) END Not;
  793. PROCEDURE Power2;
  794. BEGIN EmitOp(OPpower2) END Power2;
  795. PROCEDURE FieldMask;
  796. BEGIN EmitOp(OPext); EmitOp(04H) END FieldMask;
  797. PROCEDURE BitIn;
  798. BEGIN EmitOp(OPbitIn) END BitIn;
  799. PROCEDURE Eq;
  800. BEGIN EmitOp(OPeq) END Eq;
  801. PROCEDURE Neq;
  802. BEGIN EmitOp(OPne) END Neq;
  803. PROCEDURE ULt;
  804. BEGIN EmitOp(OPult) END ULt;
  805. PROCEDURE ULe;
  806. BEGIN EmitOp(OPule) END ULe;
  807. PROCEDURE UGt;
  808. BEGIN EmitOp(OPugt) END UGt;
  809. PROCEDURE UGe;
  810. BEGIN EmitOp(OPuge) END UGe;
  811. PROCEDURE ILt;
  812. BEGIN EmitOp(OPilt) END ILt;
  813. PROCEDURE ILe;
  814. BEGIN EmitOp(OPile) END ILe;
  815. PROCEDURE IGt;
  816. BEGIN EmitOp(OPigt) END IGt;
  817. PROCEDURE IGe;
  818. BEGIN EmitOp(OPige) END IGe;
  819. PROCEDURE RealEq;
  820. (* [r1 r2] -> (r1 = r2): cmp, or, not. *)
  821. BEGIN EmitOp(OPrCmp); EmitOp(OPor); EmitOp(OPnot) END RealEq;
  822. PROCEDURE RealNe;
  823. (* [r1 r2] -> (r1 # r2): cmp, or. *)
  824. BEGIN EmitOp(OPrCmp); EmitOp(OPor) END RealNe;
  825. PROCEDURE RealLt;
  826. (* [gt lt] -> lt: swap, drop. *)
  827. BEGIN EmitOp(OPswap); EmitOp(OPext); EmitOp(SUBdrop) END RealLt;
  828. PROCEDURE RealLe;
  829. (* [gt lt] -> NOT gt: drop, not. *)
  830. BEGIN EmitOp(OPext); EmitOp(SUBdrop); EmitOp(OPnot) END RealLe;
  831. PROCEDURE RealGt;
  832. (* [gt lt] -> gt: drop. *)
  833. BEGIN EmitOp(OPext); EmitOp(SUBdrop) END RealGt;
  834. PROCEDURE RealGe;
  835. (* [gt lt] -> NOT lt: swap, drop, not. *)
  836. BEGIN
  837. EmitOp(OPswap); EmitOp(OPext); EmitOp(SUBdrop); EmitOp(OPnot)
  838. END RealGe;
  839. PROCEDURE NegInt;
  840. BEGIN EmitOp(OPimm0); EmitOp(OPswap); EmitOp(OPsub) END NegInt;
  841. PROCEDURE NegReal;
  842. BEGIN
  843. EmitOp(OPimmW); EmitW64(0H);
  844. EmitOp(OPswap); EmitOp(OPrSub)
  845. END NegReal;
  846. PROCEDURE IntToReal;
  847. BEGIN EmitOp(OPintToLong); EmitOp(OPlongToReal) END IntToReal;
  848. PROCEDURE Dup;
  849. BEGIN EmitOp(OPdup) END Dup;
  850. PROCEDURE Drop;
  851. BEGIN EmitOp(OPext); EmitOp(SUBdrop) END Drop;
  852. (* ---------------- control flow ---------------- *)
  853. PROCEDURE NewLabel (): INTEGER;
  854. BEGIN
  855. IF nLab > MaxLab THEN RETURN 0 END;
  856. labs[nLab] := -1;
  857. INC(nLab);
  858. RETURN VAL(INTEGER, nLab - 1)
  859. END NewLabel;
  860. PROCEDURE DefLabel (id: INTEGER);
  861. VAR i : CARDINAL;
  862. rel : INTEGER;
  863. BEGIN
  864. IF (id < 0) OR (id >= VAL(INTEGER, nLab)) THEN RETURN END;
  865. labs[id] := VAL(INTEGER, nCode);
  866. i := 0;
  867. WHILE i < nFix DO
  868. IF fixs[i].lab = id THEN
  869. rel := labs[id] - VAL(INTEGER, fixs[i].pos + 9);
  870. WriteS64At(fixs[i].pos + 1, rel);
  871. fixs[i].lab := -1
  872. END;
  873. INC(i)
  874. END
  875. END DefLabel;
  876. PROCEDURE Jump (op: CARDINAL; id: INTEGER);
  877. VAR pos : CARDINAL;
  878. j : CARDINAL;
  879. BEGIN
  880. pos := nCode;
  881. EmitOp(op);
  882. IF (id >= 0) & (id < VAL(INTEGER, nLab)) & (labs[id] >= 0) THEN
  883. EmitS64(labs[id] - VAL(INTEGER, pos + 9))
  884. ELSE
  885. FOR j := 0 TO 7 DO EmitByte(0) END;
  886. IF (nFix <= MaxFix) & (id >= 0) & (id < VAL(INTEGER, nLab)) THEN
  887. fixs[nFix].pos := pos; fixs[nFix].lab := id; INC(nFix)
  888. END
  889. END
  890. END Jump;
  891. PROCEDURE Jmp (id: INTEGER);
  892. BEGIN
  893. Jump(OPjp, id)
  894. END Jmp;
  895. PROCEDURE Jz (id: INTEGER);
  896. BEGIN
  897. Jump(OPjz, id)
  898. END Jz;
  899. PROCEDURE PushLoop (exit: INTEGER);
  900. BEGIN
  901. IF loopTop <= MaxLoop THEN
  902. loopSt[loopTop] := exit; INC(loopTop)
  903. END
  904. END PushLoop;
  905. PROCEDURE PopLoop;
  906. BEGIN
  907. IF loopTop > 0 THEN DEC(loopTop) END
  908. END PopLoop;
  909. PROCEDURE TopLoop (VAR exit: INTEGER): BOOLEAN;
  910. BEGIN
  911. IF loopTop = 0 THEN RETURN FALSE END;
  912. exit := loopSt[loopTop - 1];
  913. RETURN TRUE
  914. END TopLoop;
  915. PROCEDURE NoSupEnter;
  916. BEGIN
  917. INC(noSup)
  918. END NoSupEnter;
  919. PROCEDURE NoSupExit;
  920. BEGIN
  921. IF noSup > 0 THEN DEC(noSup) END
  922. END NoSupExit;
  923. PROCEDURE NoSup (): BOOLEAN;
  924. BEGIN
  925. RETURN noSup > 0
  926. END NoSup;
  927. PROCEDURE CopyName (s: ARRAY OF CHAR; VAR d: ARRAY OF CHAR);
  928. VAR i : CARDINAL;
  929. BEGIN
  930. i := 0;
  931. WHILE (i < HIGH(d)) & (i < HIGH(s)) & (s[i] # 0C) DO
  932. d[i] := s[i]; INC(i)
  933. END;
  934. IF i <= HIGH(d) THEN d[i] := 0C END
  935. END CopyName;
  936. PROCEDURE NoEmitEnter;
  937. BEGIN
  938. INC(noEmit)
  939. END NoEmitEnter;
  940. PROCEDURE NoEmitExit;
  941. BEGIN
  942. IF noEmit > 0 THEN DEC(noEmit) END
  943. END NoEmitExit;
  944. (* ---------------- image assembly ---------------- *)
  945. PROCEDURE Put32At (off: CARDINAL; v: CARDINAL);
  946. BEGIN
  947. img[off] := CHR(v MOD 256);
  948. img[off + 1] := CHR((v DIV 256) MOD 256);
  949. img[off + 2] := CHR((v DIV 65536) MOD 256);
  950. img[off + 3] := CHR(v DIV 16777216)
  951. END Put32At;
  952. PROCEDURE Put64At (off: CARDINAL; v: LONGCARD);
  953. VAR j : CARDINAL;
  954. BEGIN
  955. FOR j := 0 TO 7 DO
  956. img[off + j] := CHR(VAL(CARDINAL, v MOD 256));
  957. v := v DIV 256
  958. END
  959. END Put64At;
  960. PROCEDURE EmitPrint;
  961. (* proc1: prints the CARDINAL parameter as decimal + CRLF.
  962. Uses global temps 0..3 (buffer, count, index, char). *)
  963. VAR l1, l2 : INTEGER;
  964. BEGIN
  965. EmitOpB(OPenter, 250);
  966. EmitOpB(OPimmB, 16); EmitOp(0D2H); EmitOpB(OPstoreGlb, 0);
  967. EmitOp(OPimm0); EmitOp(OPimm0);
  968. EmitOpB(OPstoreGlb, 1); EmitOpB(OPstoreGlb, 2);
  969. EmitOp(03H);
  970. l1 := NewLabel(); DefLabel(l1);
  971. EmitOpB(OPloadGlb, 1); EmitOp(OPinc); EmitOpB(OPstoreGlb, 1);
  972. EmitOp(OPdup); EmitOpB(OPimmB, 10); EmitOp(OPumod);
  973. EmitOp(OPswap); EmitOpB(OPimmB, 10); EmitOp(OPudiv);
  974. EmitOp(OPdup); EmitOp(OPaeq0);
  975. Jz(l1);
  976. EmitOp(OPext); EmitOp(SUBdrop);
  977. l2 := NewLabel(); DefLabel(l2);
  978. EmitOpB(OPimmB, 48); EmitOp(OPadd); EmitOpB(OPstoreGlb, 3);
  979. EmitOpB(OPloadGlb, 0); EmitOpB(OPloadGlb, 2); EmitOp(OPadd);
  980. EmitOp(OPimm0); EmitOpB(OPloadGlb, 3); EmitOp(1DH);
  981. EmitOpB(OPloadGlb, 2); EmitOp(OPinc); EmitOpB(OPstoreGlb, 2);
  982. EmitOpB(OPloadGlb, 1); EmitOp(OPdec); EmitOpB(OPstoreGlb, 1);
  983. EmitOpB(OPloadGlb, 1); EmitOp(OPaeq0);
  984. Jz(l2);
  985. EmitOpB(OPloadGlb, 0); EmitOpB(OPloadGlb, 2); EmitOp(OPadd);
  986. EmitOp(OPimm0); EmitOp(OPimm0); EmitOp(1DH);
  987. EmitOpB(OPloadGlb, 0);
  988. EmitOpB(OPimmB, 1); EmitOp(OPsys);
  989. EmitOpB(OPimmB, 3); EmitOp(0D2H);
  990. EmitOp(OPdup); EmitOp(OPimm0); EmitOpB(OPimmB, 13); EmitOp(1DH);
  991. EmitOp(OPdup); EmitOpB(OPimmB, 1); EmitOpB(OPimmB, 10); EmitOp(1DH);
  992. EmitOp(OPdup); EmitOpB(OPimmB, 2); EmitOp(OPimm0); EmitOp(1DH);
  993. EmitOpB(OPimmB, 1); EmitOp(OPsys);
  994. EmitOpB(OPfctLeave, 0)
  995. END EmitPrint;
  996. PROCEDURE PutS64At (off, addr, slot: CARDINAL);
  997. (* Procedure-table cell: signed (addr - slot). *)
  998. VAR mag : LONGCARD;
  999. bits : LONGCARD;
  1000. j : CARDINAL;
  1001. BEGIN
  1002. IF addr >= slot THEN bits := VAL(LONGCARD, addr - slot)
  1003. ELSE
  1004. mag := VAL(LONGCARD, slot - addr);
  1005. bits := 0FFFFFFFFFFFFFFFFH - mag + 1H
  1006. END;
  1007. FOR j := 0 TO 7 DO
  1008. img[off + j] := CHR(VAL(CARDINAL, bits MOD 256));
  1009. bits := bits DIV 256
  1010. END
  1011. END PutS64At;
  1012. PROCEDURE EndModule;
  1013. VAR i : CARDINAL;
  1014. codeOff, p1, pt, prNum, tabBytes : CARDINAL;
  1015. k : CARDINAL;
  1016. addr : CARDINAL;
  1017. exitIdx : INTEGER;
  1018. sum : CARDINAL;
  1019. fname : ARRAY [0 .. 127] OF CHAR;
  1020. f : FileIO.File;
  1021. ch : CHAR;
  1022. BEGIN
  1023. IF ~inBody THEN mainAddr := nCode END;
  1024. prNum := maxNum + 1;
  1025. (* epilogue: print ExitCode when the convention applies *)
  1026. exitIdx := -1;
  1027. IF SymTab.Lookup("ExitCode")
  1028. & (SymTab.SymKind("ExitCode") = SymTab.KindVar)
  1029. & SymTab.IsIntFamily(SymTab.SymType("ExitCode")) THEN
  1030. exitIdx := FindVar("ExitCode")
  1031. END;
  1032. IF exitIdx >= 0 THEN
  1033. EmitOpB(OPloadGlb, VAL(CARDINAL, exitIdx));
  1034. EmitOpB(OPprocCall, prNum);
  1035. EmitOp(OPext); EmitOp(SUBdrop)
  1036. END;
  1037. EmitOp(OPend);
  1038. p1 := nCode;
  1039. EmitPrint;
  1040. (* assemble the image *)
  1041. i := 0;
  1042. WHILE i <= MaxImg DO img[i] := 0C; INC(i) END;
  1043. img[0] := "M"; img[1] := "C"; img[2] := "6"; img[3] := "4";
  1044. i := 0;
  1045. WHILE (i < 16) & (modName[i] # 0C) DO
  1046. img[HeadSize + DName + i] := modName[i]; INC(i)
  1047. END;
  1048. img[HeadSize + DFlags] := CHR(4);
  1049. img[HeadSize + DVarCount] := CHR(nGlb MOD 256);
  1050. img[HeadSize + DDepCount] := 0C;
  1051. codeOff := DVarSizes + nGlb * 8;
  1052. i := 0;
  1053. WHILE i < nCode DO
  1054. img[HeadSize + codeOff + i] := code[i]; INC(i)
  1055. END;
  1056. pt := codeOff + nCode;
  1057. tabBytes := (maxNum + 2) * 8;
  1058. Put64At(HeadSize + DProcs, VAL(LONGCARD, pt));
  1059. k := 0;
  1060. WHILE k <= maxNum + 1 DO
  1061. IF k = 0 THEN addr := codeOff + mainAddr
  1062. ELSIF k <= maxNum THEN
  1063. IF procAddr[k] < 0 THEN addr := pt + k * 8
  1064. ELSE addr := VAL(CARDINAL, procAddr[k]) + codeOff
  1065. END
  1066. ELSE addr := codeOff + p1
  1067. END;
  1068. PutS64At(HeadSize + pt + k * 8, addr, pt + k * 8);
  1069. INC(k)
  1070. END;
  1071. i := 0;
  1072. WHILE i < nGlb DO
  1073. Put64At(HeadSize + DVarSizes + i * 8, 8H);
  1074. INC(i)
  1075. END;
  1076. sum := 0;
  1077. i := HeadSize;
  1078. WHILE i < HeadSize + pt + tabBytes DO
  1079. IF ~((i >= 352) & (i <= 355)) THEN
  1080. sum := sum + ORD(img[i])
  1081. END;
  1082. INC(i)
  1083. END;
  1084. Put32At(HeadSize + DChecksum, sum);
  1085. fname[0] := 0C;
  1086. StrCpy(fname, modName);
  1087. i := StrLen(fname);
  1088. fname[i] := "."; fname[i + 1] := "M"; fname[i + 2] := "C";
  1089. fname[i + 3] := "4"; fname[i + 4] := 0C;
  1090. FileIO.Open(f, fname, TRUE);
  1091. IF FileIO.Okay THEN
  1092. i := 0;
  1093. WHILE i < HeadSize + pt + tabBytes DO
  1094. ch := img[i];
  1095. FileIO.Write(f, ch);
  1096. INC(i)
  1097. END;
  1098. FileIO.Close(f)
  1099. END
  1100. END EndModule;
  1101. BEGIN
  1102. nCode := 0; nGlb := 0; nInit := 0;
  1103. nLab := 0; nFix := 0; loopTop := 0; noSup := 0; noEmit := 0;
  1104. actTop := 0;
  1105. maxNum := 0; mainAddr := 0;
  1106. inBody := FALSE;
  1107. modName[0] := 0C
  1108. END MGen.