MGen.mod 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666
  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. lens : ARRAY [0 .. MaxActN] OF INTEGER;
  66. addrs : ARRAY [0 .. MaxActN] OF INTEGER;
  67. sfxs : ARRAY [0 .. MaxActN] OF BOOLEAN;
  68. idxs : ARRAY [0 .. MaxActN] OF BOOLEAN;
  69. known : BOOLEAN;
  70. nf : CARDINAL;
  71. pn : ARRAY [0 .. 63] OF CHAR;
  72. byNum : BOOLEAN;
  73. num : INTEGER;
  74. END;
  75. VAR
  76. code : ARRAY [0 .. MaxCode] OF CHAR;
  77. nCode : CARDINAL;
  78. img : ARRAY [0 .. MaxImg] OF CHAR;
  79. modName : ARRAY [0 .. 63] OF CHAR;
  80. gNames : ARRAY [0 .. MaxGlb] OF ARRAY [0 .. 63] OF CHAR;
  81. vBase : ARRAY [0 .. MaxGlb] OF CARDINAL;
  82. vSize : ARRAY [0 .. MaxGlb] OF CARDINAL;
  83. nVars : CARDINAL;
  84. nGlb : CARDINAL;
  85. inits : ARRAY [0 .. MaxInit] OF InitRec;
  86. nInit : CARDINAL;
  87. inBody : BOOLEAN;
  88. labs : ARRAY [0 .. MaxLab] OF INTEGER;
  89. nLab : CARDINAL;
  90. fixs : ARRAY [0 .. MaxFix] OF FixRec;
  91. nFix : CARDINAL;
  92. loopSt : ARRAY [0 .. MaxLoop] OF INTEGER;
  93. loopTop : CARDINAL;
  94. noSup : CARDINAL;
  95. noEmit : CARDINAL;
  96. actSt : ARRAY [0 .. MaxActDepth] OF ActFrame;
  97. actTop : CARDINAL;
  98. withTmps : ARRAY [0 .. 7] OF INTEGER;
  99. withTyps : ARRAY [0 .. 7] OF INTEGER;
  100. withTop : CARDINAL;
  101. procAddr : ARRAY [0 .. 64] OF INTEGER;
  102. maxNum : CARDINAL;
  103. mainAddr : CARDINAL;
  104. initNums : ARRAY [0 .. 7] OF INTEGER;
  105. nInits : CARDINAL;
  106. (* ---------------- byte helpers ---------------- *)
  107. PROCEDURE StrLen (s: ARRAY OF CHAR): CARDINAL;
  108. VAR i : CARDINAL;
  109. BEGIN
  110. i := 0;
  111. WHILE (i < HIGH(s)) & (s[i] # 0C) DO INC(i) END;
  112. RETURN i
  113. END StrLen;
  114. PROCEDURE StrCpy (VAR d: ARRAY OF CHAR; s: ARRAY OF CHAR);
  115. VAR i : CARDINAL;
  116. BEGIN
  117. i := 0;
  118. WHILE (i < HIGH(d)) & (i < HIGH(s)) & (s[i] # 0C) DO
  119. d[i] := s[i]; INC(i)
  120. END;
  121. IF i <= HIGH(d) THEN d[i] := 0C END
  122. END StrCpy;
  123. PROCEDURE EmitByte (b: CARDINAL);
  124. BEGIN
  125. IF noEmit > 0 THEN RETURN END;
  126. IF nCode <= MaxCode THEN
  127. code[nCode] := CHR(b MOD 256); INC(nCode)
  128. END
  129. END EmitByte;
  130. PROCEDURE EmitOp (o: CARDINAL);
  131. BEGIN
  132. EmitByte(o)
  133. END EmitOp;
  134. PROCEDURE EmitOpB (o, b: CARDINAL);
  135. BEGIN
  136. EmitByte(o); EmitByte(b)
  137. END EmitOpB;
  138. PROCEDURE EmitW64 (v: LONGCARD);
  139. VAR j : CARDINAL;
  140. BEGIN
  141. FOR j := 0 TO 7 DO
  142. EmitByte(VAL(CARDINAL, v MOD 256)); v := v DIV 256
  143. END
  144. END EmitW64;
  145. PROCEDURE EmitS64 (rel: INTEGER);
  146. (* Appends a signed 64-bit little-endian offset. *)
  147. VAR mag : CARDINAL;
  148. BEGIN
  149. IF rel >= 0 THEN EmitW64(VAL(LONGCARD, VAL(CARDINAL, rel)))
  150. ELSE
  151. IF rel = -2147483647 - 1 THEN mag := 80000000H
  152. ELSE mag := VAL(CARDINAL, -rel)
  153. END;
  154. EmitW64(0FFFFFFFFFFFFFFFFH - VAL(LONGCARD, mag) + 1H)
  155. END
  156. END EmitS64;
  157. PROCEDURE WriteS64At (off: CARDINAL; rel: INTEGER);
  158. (* Backpatches a signed offset into already-emitted code. *)
  159. VAR mag : CARDINAL;
  160. bits : LONGCARD;
  161. j : CARDINAL;
  162. BEGIN
  163. IF rel >= 0 THEN bits := VAL(LONGCARD, VAL(CARDINAL, rel))
  164. ELSE
  165. IF rel = -2147483647 - 1 THEN mag := 80000000H
  166. ELSE mag := VAL(CARDINAL, -rel)
  167. END;
  168. bits := 0FFFFFFFFFFFFFFFFH - VAL(LONGCARD, mag) + 1H
  169. END;
  170. FOR j := 0 TO 7 DO
  171. code[off + j] := CHR(VAL(CARDINAL, bits MOD 256));
  172. bits := bits DIV 256
  173. END
  174. END WriteS64At;
  175. PROCEDURE FindVar (name: ARRAY OF CHAR): INTEGER;
  176. VAR i : CARDINAL;
  177. BEGIN
  178. i := 0;
  179. WHILE i < nVars DO
  180. IF SymTab.Equal(gNames[i], name) THEN
  181. RETURN VAL(INTEGER, vBase[i])
  182. END;
  183. INC(i)
  184. END;
  185. RETURN -1
  186. END FindVar;
  187. PROCEDURE QualGlob (name: ARRAY OF CHAR; VAR q: ARRAY OF CHAR);
  188. VAR m: SymTab.Name;
  189. i, k: CARDINAL;
  190. BEGIN
  191. IF SymTab.GlobAlias(name, m) THEN
  192. StrCpy(q, m);
  193. RETURN
  194. END;
  195. IF SymTab.InModule() & (SymTab.SymLev(name) > 0) THEN
  196. SymTab.CurModName(m);
  197. i := 0; k := 0;
  198. WHILE (k < HIGH(q)) & (m[i] # 0C) DO
  199. q[k] := m[i]; INC(k); INC(i)
  200. END;
  201. IF k <= HIGH(q) THEN q[k] := "."; INC(k) END;
  202. i := 0;
  203. WHILE (k < HIGH(q)) & (name[i] # 0C) DO
  204. q[k] := name[i]; INC(k); INC(i)
  205. END;
  206. IF k <= HIGH(q) THEN q[k] := 0C END
  207. ELSE
  208. StrCpy(q, name)
  209. END
  210. END QualGlob;
  211. PROCEDURE AssignSlots (name: ARRAY OF CHAR; n: CARDINAL): INTEGER;
  212. VAR base : CARDINAL;
  213. BEGIN
  214. IF nVars > MaxGlb THEN RETURN -1 END;
  215. IF n = 0 THEN
  216. StrCpy(gNames[nVars], name);
  217. vBase[nVars] := nGlb;
  218. vSize[nVars] := 0;
  219. INC(nVars);
  220. RETURN VAL(INTEGER, nGlb)
  221. END;
  222. IF nGlb + n - 1 > MaxGlb THEN RETURN -1 END;
  223. StrCpy(gNames[nVars], name);
  224. base := nGlb;
  225. vBase[nVars] := base;
  226. vSize[nVars] := n;
  227. INC(nVars);
  228. nGlb := nGlb + n;
  229. RETURN VAL(INTEGER, base)
  230. END AssignSlots;
  231. PROCEDURE AssignSlot (name: ARRAY OF CHAR): INTEGER;
  232. BEGIN
  233. RETURN AssignSlots(name, 1)
  234. END AssignSlot;
  235. (* ---------------- module / data section ---------------- *)
  236. PROCEDURE OpenModule (name: ARRAY OF CHAR);
  237. VAR i : CARDINAL;
  238. dummy : INTEGER;
  239. BEGIN
  240. StrCpy(modName, name);
  241. nCode := 0; nGlb := 0; nVars := 0; nInit := 0;
  242. nLab := 0; nFix := 0; loopTop := 0; noSup := 0; noEmit := 0;
  243. actTop := 0; withTop := 0;
  244. maxNum := 0; mainAddr := 0;
  245. nInits := 0;
  246. i := 0;
  247. WHILE i <= 64 DO procAddr[i] := -1; INC(i) END;
  248. inBody := FALSE;
  249. i := 0;
  250. WHILE i <= MaxGlb DO gNames[i][0] := 0C; INC(i) END;
  251. (* slots 0..3 belong to the print helper *)
  252. dummy := AssignSlot(""); dummy := AssignSlot("");
  253. dummy := AssignSlot(""); dummy := AssignSlot("")
  254. END OpenModule;
  255. PROCEDURE SetModName (name: ARRAY OF CHAR);
  256. BEGIN
  257. StrCpy(modName, name)
  258. END SetModName;
  259. PROCEDURE DeclVar (name: ARRAY OF CHAR);
  260. VAR idx : INTEGER;
  261. BEGIN
  262. idx := AssignSlot(name);
  263. IF idx < 0 THEN RETURN END
  264. END DeclVar;
  265. PROCEDURE DeclVarSized (name: ARRAY OF CHAR; slots: CARDINAL);
  266. VAR idx : INTEGER;
  267. q: ARRAY [0 .. 63] OF CHAR;
  268. BEGIN
  269. QualGlob(name, q);
  270. idx := AssignSlots(q, slots);
  271. IF idx < 0 THEN RETURN END
  272. END DeclVarSized;
  273. PROCEDURE BufInit (idx: INTEGER; kind: INTEGER; ival: INTEGER;
  274. bits: LONGCARD);
  275. BEGIN
  276. IF nInit > MaxInit THEN RETURN END;
  277. inits[nInit].idx := VAL(CARDINAL, idx);
  278. inits[nInit].kind := kind;
  279. inits[nInit].ival := ival;
  280. inits[nInit].bits := bits;
  281. INC(nInit)
  282. END BufInit;
  283. PROCEDURE DeclConst (name: ARRAY OF CHAR; lit: LitStr; t: INTEGER);
  284. VAR idx : INTEGER;
  285. cls : INTEGER;
  286. v : INTEGER;
  287. c : CARDINAL;
  288. b : LONGCARD;
  289. q: ARRAY [0 .. 63] OF CHAR;
  290. BEGIN
  291. QualGlob(name, q);
  292. idx := AssignSlot(q);
  293. IF idx < 0 THEN RETURN END;
  294. cls := SymTab.ClassOf(t);
  295. IF ~IsLit(lit) OR (cls = SymTab.ClStr) THEN
  296. BufInit(idx, 0, 0, 0H); RETURN
  297. END;
  298. IF cls = SymTab.ClReal THEN
  299. IF ParseReal(lit, b) THEN BufInit(idx, 1, 0, b)
  300. ELSE BufInit(idx, 1, 0, 0H)
  301. END
  302. ELSIF SymTab.Equal(lit, "TRUE") THEN BufInit(idx, 0, 1, 0H)
  303. ELSIF SymTab.Equal(lit, "FALSE") THEN BufInit(idx, 0, 0, 0H)
  304. ELSIF ParseInt(lit, v) THEN BufInit(idx, 0, v, 0H)
  305. ELSIF ParseCard(lit, c) THEN
  306. BufInit(idx, 1, 0, VAL(LONGCARD, c))
  307. ELSE BufInit(idx, 0, 0, 0H)
  308. END
  309. END DeclConst;
  310. PROCEDURE DeclConstInt (name: ARRAY OF CHAR; v: INTEGER);
  311. VAR idx : INTEGER;
  312. q: ARRAY [0 .. 63] OF CHAR;
  313. BEGIN
  314. QualGlob(name, q);
  315. idx := AssignSlot(q);
  316. IF idx < 0 THEN RETURN END;
  317. BufInit(idx, 0, v, 0H)
  318. END DeclConstInt;
  319. PROCEDURE PushValue (kind: INTEGER; ival: INTEGER; bits: LONGCARD);
  320. BEGIN
  321. IF kind = 0 THEN PushInt(ival) ELSE PushBits(bits) END
  322. END PushValue;
  323. PROCEDURE BeginBody;
  324. VAR i : CARDINAL;
  325. BEGIN
  326. IF inBody THEN RETURN END;
  327. inBody := TRUE;
  328. mainAddr := nCode;
  329. i := 0;
  330. WHILE i < nInit DO
  331. PushValue(inits[i].kind, inits[i].ival, inits[i].bits);
  332. EmitOpB(OPstoreGlb, inits[i].idx);
  333. INC(i)
  334. END;
  335. i := 0;
  336. WHILE i < nInits DO
  337. CallProc(initNums[i]);
  338. INC(i)
  339. END
  340. END BeginBody;
  341. (* ---------------- loads, stores, pushes ---------------- *)
  342. PROCEDURE LoadVar (name: ARRAY OF CHAR);
  343. VAR idx : INTEGER;
  344. q: ARRAY [0 .. 63] OF CHAR;
  345. BEGIN
  346. QualGlob(name, q);
  347. idx := FindVar(q);
  348. IF idx < 0 THEN EmitOp(OPimm0)
  349. ELSE EmitOpB(OPloadGlb, VAL(CARDINAL, idx))
  350. END
  351. END LoadVar;
  352. PROCEDURE StoreVar (name: ARRAY OF CHAR);
  353. VAR idx : INTEGER;
  354. q: ARRAY [0 .. 63] OF CHAR;
  355. BEGIN
  356. QualGlob(name, q);
  357. idx := FindVar(q);
  358. IF idx < 0 THEN EmitOp(OPext); EmitOp(SUBdrop)
  359. ELSE EmitOpB(OPstoreGlb, VAL(CARDINAL, idx))
  360. END
  361. END StoreVar;
  362. PROCEDURE LoadTemp (t: INTEGER);
  363. BEGIN
  364. EmitOpB(OPloadGlb, VAL(CARDINAL, t))
  365. END LoadTemp;
  366. PROCEDURE StoreTemp (t: INTEGER);
  367. BEGIN
  368. EmitOpB(OPstoreGlb, VAL(CARDINAL, t))
  369. END StoreTemp;
  370. PROCEDURE TempGlobal (): INTEGER;
  371. VAR idx : INTEGER;
  372. BEGIN
  373. idx := AssignSlot("");
  374. IF idx < 0 THEN RETURN 4 END;
  375. RETURN idx
  376. END TempGlobal;
  377. (* ---------------- frames and procedures ---------------- *)
  378. PROCEDURE EmitSlotB (op: CARDINAL; sl: INTEGER);
  379. (* Byte operand for a (possibly negative) frame slot. *)
  380. BEGIN
  381. IF sl >= 0 THEN EmitOpB(op, VAL(CARDINAL, sl))
  382. ELSE EmitOpB(op, 256 - VAL(CARDINAL, -sl))
  383. END
  384. END EmitSlotB;
  385. PROCEDURE LoadLocal (sl: INTEGER);
  386. BEGIN
  387. EmitSlotB(OPloadLocal, sl)
  388. END LoadLocal;
  389. PROCEDURE StoreLocal (sl: INTEGER);
  390. BEGIN
  391. EmitSlotB(OPstoreLocal, sl)
  392. END StoreLocal;
  393. PROCEDURE LoadIndir0;
  394. BEGIN
  395. EmitOp(OPloadIndir0)
  396. END LoadIndir0;
  397. PROCEDURE StoreIndir0;
  398. BEGIN
  399. EmitOp(OPstoreIndir0)
  400. END StoreIndir0;
  401. PROCEDURE FrameAddr (sl: INTEGER; np: CARDINAL);
  402. (* Pushes (display-frame(np) + slot*8): 11H np, then the offset. *)
  403. BEGIN
  404. EmitOpB(OPloadOuterN, np);
  405. IF sl >= 0 THEN EmitOpB(OPstkAddr, VAL(CARDINAL, sl))
  406. ELSE
  407. PushInt(sl * 8);
  408. EmitOp(OPadd)
  409. END
  410. END FrameAddr;
  411. PROCEDURE LoadIndir;
  412. BEGIN
  413. EmitOp(OPloadIndir)
  414. END LoadIndir;
  415. PROCEDURE StoreIndir;
  416. BEGIN
  417. EmitOp(OPstoreIndir)
  418. END StoreIndir;
  419. PROCEDURE LocalAddr (sl: INTEGER);
  420. BEGIN
  421. EmitSlotB(OPlocalAddr, sl)
  422. END LocalAddr;
  423. PROCEDURE GlobalAddr (name: ARRAY OF CHAR);
  424. VAR idx : INTEGER;
  425. q: ARRAY [0 .. 63] OF CHAR;
  426. BEGIN
  427. QualGlob(name, q);
  428. idx := FindVar(q);
  429. IF idx < 0 THEN EmitOp(OPimm0)
  430. ELSE EmitOpB(OPglobalAddr, VAL(CARDINAL, idx))
  431. END
  432. END GlobalAddr;
  433. PROCEDURE PushAddr (name: ARRAY OF CHAR);
  434. (* VAR-actual address: slot contents for VAR params, slot address
  435. for plain variables; display-aware. *)
  436. VAR k, d, D, sl : INTEGER;
  437. np : CARDINAL;
  438. BEGIN
  439. k := SymTab.SymKind(name);
  440. d := SymTab.SymDepth(name);
  441. D := SymTab.CurDepth();
  442. sl := SymTab.SymSlot(name);
  443. IF (k # SymTab.KindVar) & (k # SymTab.KindParam)
  444. & (k # SymTab.KindVarPar) THEN
  445. EmitOp(OPimm0); RETURN
  446. END;
  447. IF (k = SymTab.KindVarPar)
  448. OR ((k = SymTab.KindParam)
  449. & SymTab.IsOpen(SymTab.SymType(name))) THEN
  450. IF D = d THEN LoadLocal(sl)
  451. ELSE
  452. np := VAL(CARDINAL, D - 1 - d);
  453. FrameAddr(sl, np);
  454. LoadIndir
  455. END
  456. ELSE
  457. IF d = 0 THEN GlobalAddr(name)
  458. ELSIF D = d THEN LocalAddr(sl)
  459. ELSE
  460. np := VAL(CARDINAL, D - 1 - d);
  461. FrameAddr(sl, np)
  462. END
  463. END
  464. END PushAddr;
  465. PROCEDURE StoreSetup (name: ARRAY OF CHAR);
  466. (* Early address for indirect stores; call before the value code. *)
  467. VAR k, d, D, sl : INTEGER;
  468. np : CARDINAL;
  469. BEGIN
  470. k := SymTab.SymKind(name);
  471. IF (k # SymTab.KindVar) & (k # SymTab.KindParam)
  472. & (k # SymTab.KindVarPar) THEN
  473. RETURN
  474. END;
  475. d := SymTab.SymDepth(name);
  476. D := SymTab.CurDepth();
  477. sl := SymTab.SymSlot(name);
  478. IF k = SymTab.KindVarPar THEN
  479. IF D = d THEN LoadLocal(sl)
  480. ELSE
  481. np := VAL(CARDINAL, D - 1 - d);
  482. FrameAddr(sl, np);
  483. LoadIndir
  484. END
  485. ELSIF (d # 0) & (D # d) THEN
  486. np := VAL(CARDINAL, D - 1 - d);
  487. FrameAddr(sl, np)
  488. END
  489. END StoreSetup;
  490. PROCEDURE StoreFinish (name: ARRAY OF CHAR);
  491. (* Completes the store; call after the value code. *)
  492. VAR k, d, D, sl : INTEGER;
  493. BEGIN
  494. k := SymTab.SymKind(name);
  495. IF (k # SymTab.KindVar) & (k # SymTab.KindParam)
  496. & (k # SymTab.KindVarPar) THEN
  497. RETURN
  498. END;
  499. d := SymTab.SymDepth(name);
  500. D := SymTab.CurDepth();
  501. sl := SymTab.SymSlot(name);
  502. IF d = 0 THEN StoreVar(name)
  503. ELSIF D = d THEN
  504. IF k = SymTab.KindVarPar THEN StoreIndir0
  505. ELSE StoreLocal(sl)
  506. END
  507. ELSE
  508. IF k = SymTab.KindVarPar THEN StoreIndir0
  509. ELSE StoreIndir
  510. END
  511. END
  512. END StoreFinish;
  513. PROCEDURE PushVar (name: ARRAY OF CHAR);
  514. (* Frame-aware value load (see PushAddr for the address twin). *)
  515. VAR k, d, D, sl : INTEGER;
  516. np : CARDINAL;
  517. BEGIN
  518. k := SymTab.SymKind(name);
  519. d := SymTab.SymDepth(name);
  520. D := SymTab.CurDepth();
  521. sl := SymTab.SymSlot(name);
  522. IF (k # SymTab.KindVar) & (k # SymTab.KindParam)
  523. & (k # SymTab.KindVarPar) THEN
  524. EmitOp(OPimm0); RETURN
  525. END;
  526. IF d = 0 THEN LoadVar(name)
  527. ELSIF D = d THEN
  528. IF k = SymTab.KindVarPar THEN
  529. LoadLocal(sl); LoadIndir0
  530. ELSE LoadLocal(sl)
  531. END
  532. ELSE
  533. np := VAL(CARDINAL, D - 1 - d);
  534. FrameAddr(sl, np);
  535. LoadIndir;
  536. IF k = SymTab.KindVarPar THEN LoadIndir0 END
  537. END
  538. END PushVar;
  539. PROCEDURE ProcEntry (num: INTEGER; nLoc: CARDINAL);
  540. VAR k : CARDINAL;
  541. BEGIN
  542. IF (num >= 0) & (num <= 64) THEN
  543. procAddr[num] := VAL(INTEGER, nCode);
  544. IF VAL(CARDINAL, num) > maxNum THEN
  545. maxNum := VAL(CARDINAL, num)
  546. END
  547. END;
  548. IF nLoc > 255 THEN k := 255 ELSE k := nLoc END;
  549. EmitOpB(OPenter, 255 - k)
  550. END ProcEntry;
  551. PROCEDURE CallProc (num: INTEGER);
  552. BEGIN
  553. EmitOpB(OPprocCall, VAL(CARDINAL, num))
  554. END CallProc;
  555. PROCEDURE CallNested (num: INTEGER);
  556. BEGIN
  557. EmitOpB(OPnestedCall, VAL(CARDINAL, num))
  558. END CallNested;
  559. PROCEDURE CallDisplay (num: INTEGER; np: CARDINAL);
  560. BEGIN
  561. EmitOpB(OPloadOuterN, np);
  562. EmitOpB(OPcallFrame, VAL(CARDINAL, num))
  563. END CallDisplay;
  564. PROCEDURE ModInitBegin (): INTEGER;
  565. (* Opens a module init body as a parameterless proper procedure
  566. (module bodies declare no locals; globals are used directly).
  567. Records its number for the startup calls in BeginBody.
  568. The number comes from SymTab's shared proc pool (never
  569. maxNum+1: a later procedure body would otherwise overwrite
  570. this init's table slot on emission). -1 when full. *)
  571. VAR num : INTEGER;
  572. BEGIN
  573. IF nInits > 7 THEN RETURN -1 END;
  574. num := SymTab.AllocInitNum();
  575. IF (num < 1) OR (num > 64) THEN RETURN -1 END;
  576. initNums[nInits] := num;
  577. INC(nInits);
  578. ProcEntry(num, 0);
  579. RETURN num
  580. END ModInitBegin;
  581. PROCEDURE ModInitEnd (num: INTEGER);
  582. (* Closes a module init body (no-op for num < 0). *)
  583. BEGIN
  584. IF num >= 0 THEN Leave(0, FALSE) END
  585. END ModInitEnd;
  586. PROCEDURE Leave (nPar: CARDINAL; func: BOOLEAN);
  587. BEGIN
  588. IF nPar > 255 THEN nPar := 255 END;
  589. IF func THEN EmitOpB(OPfctLeave, nPar)
  590. ELSE EmitOpB(OPprocLeave, nPar)
  591. END
  592. END Leave;
  593. (* ---------------- actual parameters ---------------- *)
  594. PROCEDURE ActFrameIdx (): CARDINAL;
  595. (* Active frame, capped (nesting past the cap reuses the top). *)
  596. BEGIN
  597. IF actTop = 0 THEN RETURN 0 END;
  598. IF actTop - 1 > MaxActDepth THEN RETURN MaxActDepth END;
  599. RETURN actTop - 1
  600. END ActFrameIdx;
  601. PROCEDURE ActIsVarNext (): BOOLEAN;
  602. VAR fr, i: CARDINAL;
  603. BEGIN
  604. IF actTop = 0 THEN RETURN FALSE END;
  605. fr := ActFrameIdx();
  606. IF ~actSt[fr].known THEN RETURN FALSE END;
  607. i := actSt[fr].n;
  608. IF i >= actSt[fr].nf THEN RETURN FALSE END;
  609. RETURN SymTab.ParamIsVar(actSt[fr].pn, i)
  610. END ActIsVarNext;
  611. PROCEDURE NoteSfx (b: BOOLEAN);
  612. VAR fr, i: CARDINAL;
  613. BEGIN
  614. IF actTop = 0 THEN RETURN END;
  615. fr := ActFrameIdx();
  616. i := actSt[fr].n;
  617. IF i <= MaxActN THEN actSt[fr].sfxs[i] := b END
  618. END NoteSfx;
  619. PROCEDURE NoteIdx (b: BOOLEAN);
  620. VAR fr, i: CARDINAL;
  621. BEGIN
  622. IF actTop = 0 THEN RETURN END;
  623. fr := ActFrameIdx();
  624. i := actSt[fr].n;
  625. IF i <= MaxActN THEN actSt[fr].idxs[i] := b END
  626. END NoteIdx;
  627. PROCEDURE ActBegin (pn: ARRAY OF CHAR);
  628. VAR fr : CARDINAL;
  629. k : CARDINAL;
  630. BEGIN
  631. fr := actTop;
  632. IF fr > MaxActDepth THEN fr := MaxActDepth
  633. ELSE INC(actTop)
  634. END;
  635. StrCpy(actSt[fr].pn, pn);
  636. actSt[fr].n := 0;
  637. k := 0;
  638. WHILE k <= MaxActN DO
  639. actSt[fr].lens[k] := -1;
  640. actSt[fr].addrs[k] := -1;
  641. actSt[fr].sfxs[k] := FALSE;
  642. actSt[fr].idxs[k] := TRUE;
  643. INC(k)
  644. END;
  645. actSt[fr].known := SymTab.Lookup(pn)
  646. & (SymTab.SymKind(pn) = SymTab.KindProc);
  647. IF actSt[fr].known THEN actSt[fr].nf := SymTab.ProcNPar(pn)
  648. ELSE actSt[fr].nf := 0
  649. END;
  650. actSt[fr].byNum := FALSE;
  651. actSt[fr].num := -1
  652. END ActBegin;
  653. PROCEDURE ActBeginNum (num: INTEGER);
  654. (* Actuals for a procedure known by number (exported module procs,
  655. whose names vanish with the module body scope). *)
  656. VAR fr : CARDINAL;
  657. k : CARDINAL;
  658. BEGIN
  659. fr := actTop;
  660. IF fr > MaxActDepth THEN fr := MaxActDepth
  661. ELSE INC(actTop)
  662. END;
  663. actSt[fr].pn[0] := 0C;
  664. actSt[fr].n := 0;
  665. k := 0;
  666. WHILE k <= MaxActN DO
  667. actSt[fr].lens[k] := -1;
  668. actSt[fr].addrs[k] := -1;
  669. actSt[fr].sfxs[k] := FALSE;
  670. actSt[fr].idxs[k] := TRUE;
  671. INC(k)
  672. END;
  673. actSt[fr].known := SymTab.ProcValid(num);
  674. IF actSt[fr].known THEN actSt[fr].nf := SymTab.ProcNParByNum(num)
  675. ELSE actSt[fr].nf := 0
  676. END;
  677. actSt[fr].byNum := TRUE;
  678. actSt[fr].num := num
  679. END ActBeginNum;
  680. PROCEDURE ActFormalType (fr, i: CARDINAL): INTEGER;
  681. (* i-th formal type of the frame's callee, by number or by name. *)
  682. BEGIN
  683. IF actSt[fr].byNum THEN
  684. RETURN SymTab.ParamTypeByNum(actSt[fr].num, i)
  685. ELSE
  686. RETURN SymTab.ParamType(actSt[fr].pn, i)
  687. END
  688. END ActFormalType;
  689. PROCEDURE ActFormalIsVar (fr, i: CARDINAL): BOOLEAN;
  690. BEGIN
  691. IF actSt[fr].byNum THEN
  692. RETURN SymTab.ParamIsVarByNum(actSt[fr].num, i)
  693. ELSE
  694. RETURN SymTab.ParamIsVar(actSt[fr].pn, i)
  695. END
  696. END ActFormalIsVar;
  697. PROCEDURE StashAddr;
  698. (* Duplicates the address on top of stack into a per-actual temp of
  699. the current call frame (for VAR actuals with tails: a[i], p^,
  700. fields). The ATG calls this at the Fact tail, when the address is
  701. complete but not yet loaded. Recorded as -1 when unused. *)
  702. VAR fr, i : CARDINAL;
  703. tmp : INTEGER;
  704. BEGIN
  705. IF actTop = 0 THEN RETURN END;
  706. fr := ActFrameIdx();
  707. i := actSt[fr].n;
  708. IF i > MaxActN THEN RETURN END;
  709. tmp := TempGlobal();
  710. actSt[fr].addrs[i] := tmp;
  711. EmitOp(OPdup);
  712. StoreTemp(tmp)
  713. END StashAddr;
  714. PROCEDURE ClrStash;
  715. (* Invalidates the stashed address of the current actual: a
  716. value-combining operator followed, so the address no longer
  717. denotes the actual. Conservative no-op outside calls. *)
  718. VAR fr, i : CARDINAL;
  719. BEGIN
  720. IF actTop = 0 THEN RETURN END;
  721. fr := ActFrameIdx();
  722. i := actSt[fr].n;
  723. IF i <= MaxActN THEN actSt[fr].addrs[i] := -1 END
  724. END ClrStash;
  725. PROCEDURE ActValue (t: INTEGER; v: BOOLEAN;
  726. vn: ARRAY OF CHAR): INTEGER;
  727. VAR fr : CARDINAL;
  728. i : CARDINAL;
  729. ftyp : INTEGER;
  730. fv : BOOLEAN;
  731. err : INTEGER;
  732. BEGIN
  733. err := 0;
  734. fr := ActFrameIdx();
  735. i := actSt[fr].n;
  736. IF i > MaxActN THEN
  737. EmitOp(OPext); EmitOp(SUBdrop);
  738. actSt[fr].n := i + 1;
  739. RETURN 1
  740. END;
  741. IF actSt[fr].known & (i < actSt[fr].nf) THEN
  742. ftyp := ActFormalType(fr, i);
  743. fv := ActFormalIsVar(fr, i);
  744. IF SymTab.IsOpen(ftyp) THEN
  745. IF (t = SymTab.InvalidType)
  746. OR SymTab.IsOpen(t)
  747. OR (SymTab.ClassOf(t) # SymTab.ClArray) THEN
  748. err := 1
  749. ELSIF ~SymTab.SameType(SymTab.ArrayElem(t),
  750. SymTab.ArrayElem(ftyp)) THEN
  751. err := 1
  752. ELSIF fv & ~v & (actSt[fr].addrs[i] < 0) THEN
  753. err := 1
  754. END;
  755. IF (t # SymTab.InvalidType)
  756. & (SymTab.ClassOf(t) = SymTab.ClArray)
  757. & ~SymTab.IsOpen(t) THEN
  758. PushInt(VAL(INTEGER, SymTab.ArrayLen(t)))
  759. ELSE
  760. PushInt(0)
  761. END;
  762. actSt[fr].lens[i] := TempGlobal();
  763. StoreTemp(actSt[fr].lens[i]);
  764. IF fv THEN
  765. IF (err = 0) & (actSt[fr].addrs[i] >= 0) THEN
  766. (* tailed array actual: its address is already on top *)
  767. ELSE
  768. EmitOp(OPext); EmitOp(SUBdrop);
  769. PushAddr(vn)
  770. END
  771. END
  772. ELSIF fv THEN
  773. IF actSt[fr].addrs[i] >= 0 THEN
  774. IF (t # SymTab.InvalidType)
  775. & ((SymTab.ClassOf(t) = SymTab.ClArray)
  776. OR (SymTab.ClassOf(t) = SymTab.ClRecord)) THEN
  777. (* tailed composite actual: address already on top *)
  778. ELSIF SymTab.SameType(t, ftyp) THEN
  779. EmitOp(OPext); EmitOp(SUBdrop);
  780. LoadTemp(actSt[fr].addrs[i])
  781. ELSE
  782. err := 1;
  783. EmitOp(OPext); EmitOp(SUBdrop);
  784. PushAddr(vn)
  785. END
  786. ELSE
  787. IF ~v THEN err := 1
  788. ELSIF ~SymTab.SameType(t, ftyp) THEN err := 1
  789. END;
  790. EmitOp(OPext); EmitOp(SUBdrop);
  791. PushAddr(vn)
  792. END
  793. ELSE
  794. IF ~SymTab.Assignable(t, ftyp) THEN err := 1
  795. ELSIF SymTab.IsIntFamily(t)
  796. & (SymTab.ClassOf(ftyp) = SymTab.ClReal) THEN
  797. IntToReal
  798. END
  799. END
  800. END;
  801. actSt[fr].tmps[i] := TempGlobal();
  802. StoreTemp(actSt[fr].tmps[i]);
  803. actSt[fr].n := i + 1;
  804. RETURN err
  805. END ActValue;
  806. PROCEDURE ActEnd (pn: ARRAY OF CHAR; sfx, inExpr: BOOLEAN): INTEGER;
  807. VAR fr : CARDINAL;
  808. i : CARDINAL;
  809. n, num, F, d : INTEGER;
  810. BEGIN
  811. fr := ActFrameIdx();
  812. IF actTop > 0 THEN DEC(actTop) END;
  813. n := VAL(INTEGER, actSt[fr].n);
  814. IF ~SymTab.Lookup(pn) THEN
  815. IF inExpr THEN EmitOp(OPimm0) END;
  816. RETURN 0
  817. END;
  818. IF (SymTab.SymKind(pn) # SymTab.KindProc)
  819. OR sfx
  820. OR (n # VAL(INTEGER, SymTab.ProcNPar(pn))) THEN
  821. IF inExpr THEN EmitOp(OPimm0) END;
  822. RETURN 1
  823. END;
  824. IF inExpr & (SymTab.ProcRet(pn) = SymTab.InvalidType) THEN
  825. EmitOp(OPimm0);
  826. RETURN 1
  827. END;
  828. i := actSt[fr].n;
  829. WHILE i > 0 DO
  830. DEC(i);
  831. IF i <= MaxActN THEN
  832. IF (actSt[fr].lens[i] >= 0)
  833. & SymTab.IsOpen(SymTab.ParamType(pn, i)) THEN
  834. LoadTemp(actSt[fr].lens[i]);
  835. LoadTemp(actSt[fr].tmps[i])
  836. ELSE
  837. LoadTemp(actSt[fr].tmps[i])
  838. END
  839. END
  840. END;
  841. num := SymTab.ProcNum(pn);
  842. F := SymTab.CurDepth();
  843. d := SymTab.SymDepth(pn);
  844. IF d = 0 THEN CallProc(num)
  845. ELSIF F = d THEN CallNested(num)
  846. ELSE CallDisplay(num, VAL(CARDINAL, F - 1 - d))
  847. END;
  848. IF ~inExpr & (SymTab.ProcRet(pn) # SymTab.InvalidType) THEN
  849. EmitOp(OPext); EmitOp(SUBdrop)
  850. END;
  851. RETURN 0
  852. END ActEnd;
  853. PROCEDURE ActEndNum (num: INTEGER; inExpr: BOOLEAN): INTEGER;
  854. (* Ends a by-number call (module procedures are always global-level,
  855. so a plain global call is correct; the M. prefix is qualification,
  856. not a tail, hence no sfx check). *)
  857. VAR fr : CARDINAL;
  858. i : CARDINAL;
  859. n : INTEGER;
  860. BEGIN
  861. fr := ActFrameIdx();
  862. IF actTop > 0 THEN DEC(actTop) END;
  863. n := VAL(INTEGER, actSt[fr].n);
  864. IF ~SymTab.ProcValid(num)
  865. OR (n # VAL(INTEGER, SymTab.ProcNParByNum(num))) THEN
  866. IF inExpr THEN EmitOp(OPimm0) END;
  867. RETURN 1
  868. END;
  869. IF inExpr & (SymTab.ProcRetByNum(num) = SymTab.InvalidType) THEN
  870. EmitOp(OPimm0);
  871. RETURN 1
  872. END;
  873. i := actSt[fr].n;
  874. WHILE i > 0 DO
  875. DEC(i);
  876. IF i <= MaxActN THEN
  877. IF (actSt[fr].lens[i] >= 0)
  878. & SymTab.IsOpen(SymTab.ParamTypeByNum(num, i)) THEN
  879. LoadTemp(actSt[fr].lens[i]);
  880. LoadTemp(actSt[fr].tmps[i])
  881. ELSE
  882. LoadTemp(actSt[fr].tmps[i])
  883. END
  884. END
  885. END;
  886. CallProc(num);
  887. IF ~inExpr & (SymTab.ProcRetByNum(num) # SymTab.InvalidType) THEN
  888. EmitOp(OPext); EmitOp(SUBdrop)
  889. END;
  890. RETURN 0
  891. END ActEndNum;
  892. PROCEDURE EmitMag (c: CARDINAL);
  893. BEGIN
  894. IF c <= 255 THEN EmitOpB(OPimmB, c)
  895. ELSE EmitOp(OPimmW); EmitW64(VAL(LONGCARD, c))
  896. END
  897. END EmitMag;
  898. PROCEDURE PushInt (v: INTEGER);
  899. VAR mag : CARDINAL;
  900. BEGIN
  901. IF (v >= 0) & (v <= 15) THEN EmitOp(OPimm0 + VAL(CARDINAL, v))
  902. ELSIF v < 0 THEN
  903. IF v = -2147483647 - 1 THEN mag := 80000000H
  904. ELSE mag := VAL(CARDINAL, -v)
  905. END;
  906. EmitOp(OPimm0); EmitMag(mag); EmitOp(OPsub)
  907. ELSE EmitMag(VAL(CARDINAL, v))
  908. END
  909. END PushInt;
  910. PROCEDURE PushBits (b: LONGCARD);
  911. BEGIN
  912. EmitOp(OPimmW); EmitW64(b)
  913. END PushBits;
  914. (* ---------------- literal parsing ---------------- *)
  915. PROCEDURE DigVal (ch: CHAR): INTEGER;
  916. BEGIN
  917. IF (ch >= "0") & (ch <= "9") THEN RETURN ORD(ch) - ORD("0") END;
  918. IF (ch >= "A") & (ch <= "F") THEN RETURN ORD(ch) - ORD("A") + 10 END;
  919. IF (ch >= "a") & (ch <= "f") THEN RETURN ORD(ch) - ORD("a") + 10 END;
  920. RETURN -1
  921. END DigVal;
  922. PROCEDURE ParseCard (s: ARRAY OF CHAR; VAR v: CARDINAL): BOOLEAN;
  923. VAR i, n : CARDINAL;
  924. hex : BOOLEAN;
  925. d : INTEGER;
  926. acc : LONGCARD;
  927. BEGIN
  928. v := 0;
  929. n := StrLen(s);
  930. IF n = 0 THEN RETURN FALSE END;
  931. hex := (s[n - 1] = "H") OR (s[n - 1] = "h");
  932. IF hex THEN DEC(n) END;
  933. IF n = 0 THEN RETURN FALSE END;
  934. acc := 0H; i := 0;
  935. WHILE i < n DO
  936. d := DigVal(s[i]);
  937. IF hex THEN
  938. IF d < 0 THEN RETURN FALSE END;
  939. acc := acc * 16 + VAL(LONGCARD, VAL(CARDINAL, d))
  940. ELSE
  941. IF (d < 0) OR (d > 9) THEN RETURN FALSE END;
  942. acc := acc * 10 + VAL(LONGCARD, VAL(CARDINAL, d))
  943. END;
  944. IF acc > 0FFFFFFFFH THEN RETURN FALSE END;
  945. INC(i)
  946. END;
  947. v := VAL(CARDINAL, acc);
  948. RETURN TRUE
  949. END ParseCard;
  950. PROCEDURE ParseInt (s: ARRAY OF CHAR; VAR v: INTEGER): BOOLEAN;
  951. VAR i : CARDINAL;
  952. neg : BOOLEAN;
  953. t : ARRAY [0 .. 63] OF CHAR;
  954. c : CARDINAL;
  955. lim : LONGCARD;
  956. BEGIN
  957. v := 0;
  958. IF (StrLen(s) = 0) THEN RETURN FALSE END;
  959. neg := s[0] = "-";
  960. IF neg THEN
  961. i := 1;
  962. WHILE s[i] # 0C DO
  963. IF i - 1 > HIGH(t) THEN RETURN FALSE END;
  964. t[i - 1] := s[i]; INC(i)
  965. END;
  966. IF i - 1 > HIGH(t) THEN RETURN FALSE END;
  967. t[i - 1] := 0C
  968. ELSE StrCpy(t, s)
  969. END;
  970. IF ~ParseCard(t, c) THEN RETURN FALSE END;
  971. IF neg THEN lim := 80000000H ELSE lim := 7FFFFFFFH END;
  972. IF VAL(LONGCARD, c) > lim THEN RETURN FALSE END;
  973. IF neg THEN
  974. IF VAL(LONGCARD, c) = 80000000H THEN v := -2147483647 - 1
  975. ELSE v := -VAL(INTEGER, c)
  976. END
  977. ELSE v := VAL(INTEGER, c)
  978. END;
  979. RETURN TRUE
  980. END ParseInt;
  981. PROCEDURE ParseReal (s: ARRAY OF CHAR; VAR b: LONGCARD): BOOLEAN;
  982. VAR i : CARDINAL;
  983. neg, esign : BOOLEAN;
  984. m, scale : REAL;
  985. e, d : CARDINAL;
  986. rv : RealView;
  987. BEGIN
  988. b := 0H;
  989. i := 0; neg := FALSE;
  990. IF s[0] = "-" THEN neg := TRUE; INC(i) END;
  991. IF (s[i] < "0") OR (s[i] > "9") THEN RETURN FALSE END;
  992. m := 0.0;
  993. WHILE (s[i] >= "0") & (s[i] <= "9") DO
  994. m := m * 10.0 + VAL(REAL, VAL(CARDINAL, ORD(s[i]) - ORD("0")));
  995. INC(i)
  996. END;
  997. IF s[i] = "." THEN
  998. INC(i);
  999. IF (s[i] < "0") OR (s[i] > "9") THEN RETURN FALSE END;
  1000. scale := 10.0;
  1001. WHILE (s[i] >= "0") & (s[i] <= "9") DO
  1002. m := m + VAL(REAL, VAL(CARDINAL, ORD(s[i]) - ORD("0"))) / scale;
  1003. scale := scale * 10.0;
  1004. INC(i)
  1005. END
  1006. END;
  1007. IF (s[i] = "E") OR (s[i] = "e") THEN
  1008. INC(i); esign := FALSE;
  1009. IF s[i] = "+" THEN INC(i)
  1010. ELSIF s[i] = "-" THEN esign := TRUE; INC(i)
  1011. END;
  1012. IF (s[i] < "0") OR (s[i] > "9") THEN RETURN FALSE END;
  1013. e := 0;
  1014. WHILE (s[i] >= "0") & (s[i] <= "9") DO
  1015. d := VAL(CARDINAL, ORD(s[i]) - ORD("0"));
  1016. IF e <= 9999 THEN e := e * 10 + d END;
  1017. INC(i)
  1018. END;
  1019. WHILE e > 0 DO
  1020. IF esign THEN m := m / 10.0 ELSE m := m * 10.0 END;
  1021. DEC(e)
  1022. END
  1023. END;
  1024. IF s[i] # 0C THEN RETURN FALSE END;
  1025. IF neg THEN m := -m END;
  1026. rv.r := m;
  1027. b := rv.w;
  1028. RETURN TRUE
  1029. END ParseReal;
  1030. PROCEDURE CharOrd (s: ARRAY OF CHAR): INTEGER;
  1031. BEGIN
  1032. IF StrLen(s) >= 2 THEN RETURN ORD(s[1]) END;
  1033. RETURN 0
  1034. END CharOrd;
  1035. PROCEDURE NegFold (a: ARRAY OF CHAR; VAR q: LitStr);
  1036. (* Safe for a and q being the same variable. *)
  1037. VAR tmp : LitStr;
  1038. i, j : CARDINAL;
  1039. BEGIN
  1040. StrCpy(tmp, a);
  1041. IF StrLen(tmp) = 0 THEN StrCpy(q, ""); RETURN END;
  1042. IF tmp[0] = "-" THEN
  1043. i := 1; j := 0;
  1044. WHILE (tmp[i] # 0C) & (j < HIGH(q)) DO
  1045. q[j] := tmp[i]; INC(i); INC(j)
  1046. END;
  1047. IF j <= HIGH(q) THEN q[j] := 0C END
  1048. ELSE
  1049. StrCpy(q, "-");
  1050. i := 0; j := StrLen(q);
  1051. WHILE (tmp[i] # 0C) & (j < HIGH(q)) DO
  1052. q[j] := tmp[i]; INC(i); INC(j)
  1053. END;
  1054. IF j <= HIGH(q) THEN q[j] := 0C END
  1055. END
  1056. END NegFold;
  1057. PROCEDURE IsLit (s: ARRAY OF CHAR): BOOLEAN;
  1058. BEGIN
  1059. RETURN StrLen(s) > 0
  1060. END IsLit;
  1061. (* ---------------- operators ---------------- *)
  1062. PROCEDURE Add;
  1063. BEGIN EmitOp(OPadd) END Add;
  1064. PROCEDURE Sub;
  1065. BEGIN EmitOp(OPsub) END Sub;
  1066. PROCEDURE MulU;
  1067. BEGIN EmitOp(OPumul) END MulU;
  1068. PROCEDURE DivU;
  1069. BEGIN EmitOp(OPudiv) END DivU;
  1070. PROCEDURE ModU;
  1071. BEGIN EmitOp(OPumod) END ModU;
  1072. PROCEDURE MulI;
  1073. BEGIN EmitOp(OPimul) END MulI;
  1074. PROCEDURE DivI;
  1075. BEGIN EmitOp(OPidiv) END DivI;
  1076. PROCEDURE ModI (t: INTEGER);
  1077. (* [a b] -> a MOD b (truncation) via temp t. *)
  1078. BEGIN
  1079. StoreTemp(t);
  1080. EmitOp(OPdup);
  1081. LoadTemp(t);
  1082. EmitOp(OPidiv);
  1083. LoadTemp(t);
  1084. EmitOp(OPimul);
  1085. EmitOp(OPsub)
  1086. END ModI;
  1087. PROCEDURE RealAdd;
  1088. BEGIN EmitOp(OPrAdd) END RealAdd;
  1089. PROCEDURE RealSub;
  1090. BEGIN EmitOp(OPrSub) END RealSub;
  1091. PROCEDURE RealMul;
  1092. BEGIN EmitOp(OPrMul) END RealMul;
  1093. PROCEDURE RealDiv;
  1094. BEGIN EmitOp(OPrDiv) END RealDiv;
  1095. PROCEDURE And;
  1096. BEGIN EmitOp(OPand) END And;
  1097. PROCEDURE Or;
  1098. BEGIN EmitOp(OPor) END Or;
  1099. PROCEDURE Not;
  1100. BEGIN EmitOp(OPnot) END Not;
  1101. PROCEDURE Power2;
  1102. BEGIN EmitOp(OPpower2) END Power2;
  1103. PROCEDURE FieldMask;
  1104. BEGIN EmitOp(OPext); EmitOp(04H) END FieldMask;
  1105. PROCEDURE BitIn;
  1106. BEGIN EmitOp(OPbitIn) END BitIn;
  1107. PROCEDURE Eq;
  1108. BEGIN EmitOp(OPeq) END Eq;
  1109. PROCEDURE Neq;
  1110. BEGIN EmitOp(OPne) END Neq;
  1111. PROCEDURE ULt;
  1112. BEGIN EmitOp(OPult) END ULt;
  1113. PROCEDURE ULe;
  1114. BEGIN EmitOp(OPule) END ULe;
  1115. PROCEDURE UGt;
  1116. BEGIN EmitOp(OPugt) END UGt;
  1117. PROCEDURE UGe;
  1118. BEGIN EmitOp(OPuge) END UGe;
  1119. PROCEDURE ILt;
  1120. BEGIN EmitOp(OPilt) END ILt;
  1121. PROCEDURE ILe;
  1122. BEGIN EmitOp(OPile) END ILe;
  1123. PROCEDURE IGt;
  1124. BEGIN EmitOp(OPigt) END IGt;
  1125. PROCEDURE IGe;
  1126. BEGIN EmitOp(OPige) END IGe;
  1127. PROCEDURE RealEq;
  1128. (* [r1 r2] -> (r1 = r2): cmp, or, not. *)
  1129. BEGIN EmitOp(OPrCmp); EmitOp(OPor); EmitOp(OPnot) END RealEq;
  1130. PROCEDURE RealNe;
  1131. (* [r1 r2] -> (r1 # r2): cmp, or. *)
  1132. BEGIN EmitOp(OPrCmp); EmitOp(OPor) END RealNe;
  1133. PROCEDURE RealLt;
  1134. (* [gt lt] -> lt: swap, drop. *)
  1135. BEGIN EmitOp(OPswap); EmitOp(OPext); EmitOp(SUBdrop) END RealLt;
  1136. PROCEDURE RealLe;
  1137. (* [gt lt] -> NOT gt: drop, not. *)
  1138. BEGIN EmitOp(OPext); EmitOp(SUBdrop); EmitOp(OPnot) END RealLe;
  1139. PROCEDURE RealGt;
  1140. (* [gt lt] -> gt: drop. *)
  1141. BEGIN EmitOp(OPext); EmitOp(SUBdrop) END RealGt;
  1142. PROCEDURE RealGe;
  1143. (* [gt lt] -> NOT lt: swap, drop, not. *)
  1144. BEGIN
  1145. EmitOp(OPswap); EmitOp(OPext); EmitOp(SUBdrop); EmitOp(OPnot)
  1146. END RealGe;
  1147. PROCEDURE NegInt;
  1148. BEGIN EmitOp(OPimm0); EmitOp(OPswap); EmitOp(OPsub) END NegInt;
  1149. PROCEDURE NegReal;
  1150. BEGIN
  1151. EmitOp(OPimmW); EmitW64(0H);
  1152. EmitOp(OPswap); EmitOp(OPrSub)
  1153. END NegReal;
  1154. PROCEDURE IntToReal;
  1155. BEGIN EmitOp(OPintToLong); EmitOp(OPlongToReal) END IntToReal;
  1156. PROCEDURE Dup;
  1157. BEGIN EmitOp(OPdup) END Dup;
  1158. PROCEDURE Drop;
  1159. BEGIN EmitOp(OPext); EmitOp(SUBdrop) END Drop;
  1160. PROCEDURE Swap;
  1161. BEGIN EmitOp(OPswap) END Swap;
  1162. (* ---------------- composites ---------------- *)
  1163. PROCEDURE IdxScale (lo: INTEGER; elemBytes: CARDINAL);
  1164. BEGIN
  1165. PushInt(lo);
  1166. EmitOp(OPsub);
  1167. PushInt(VAL(INTEGER, elemBytes));
  1168. EmitOp(OPumul);
  1169. EmitOp(OPadd)
  1170. END IdxScale;
  1171. PROCEDURE FieldAdd (offSlots: CARDINAL);
  1172. BEGIN
  1173. IF offSlots = 0 THEN RETURN END;
  1174. PushInt(VAL(INTEGER, offSlots * 8));
  1175. EmitOp(OPadd)
  1176. END FieldAdd;
  1177. PROCEDURE CopyBlock;
  1178. BEGIN EmitOp(30H) END CopyBlock;
  1179. PROCEDURE LoadByte;
  1180. BEGIN
  1181. PushInt(0);
  1182. EmitOp(0DH)
  1183. END LoadByte;
  1184. PROCEDURE StoreByte;
  1185. BEGIN
  1186. PushInt(0);
  1187. EmitOp(OPswap);
  1188. EmitOp(1DH)
  1189. END StoreByte;
  1190. PROCEDURE PushBytes (n: CARDINAL);
  1191. BEGIN PushInt(VAL(INTEGER, n)) END PushBytes;
  1192. PROCEDURE AllocOp;
  1193. BEGIN EmitOp(OPext); EmitOp(05H) END AllocOp;
  1194. PROCEDURE DeallocOp;
  1195. BEGIN EmitOp(OPext); EmitOp(06H) END DeallocOp;
  1196. PROCEDURE BitXor;
  1197. BEGIN EmitOp(0E9H) END BitXor;
  1198. PROCEDURE StrLenOf (s: ARRAY OF CHAR): CARDINAL;
  1199. VAR n: CARDINAL;
  1200. BEGIN
  1201. n := StrLen(s);
  1202. IF n < 2 THEN RETURN 0 END;
  1203. RETURN n - 2
  1204. END StrLenOf;
  1205. PROCEDURE EmitString (s: ARRAY OF CHAR);
  1206. VAR len, i: CARDINAL;
  1207. BEGIN
  1208. len := StrLenOf(s);
  1209. IF len + 1 > 255 THEN
  1210. PushInt(0); RETURN
  1211. END;
  1212. EmitOp(8CH);
  1213. EmitByte(len + 1);
  1214. i := 1;
  1215. WHILE i <= len DO
  1216. EmitByte(ORD(s[i])); INC(i)
  1217. END;
  1218. EmitByte(0)
  1219. END EmitString;
  1220. PROCEDURE StrComp;
  1221. BEGIN EmitOp(0C4H) END StrComp;
  1222. (* ---------------- WITH ---------------- *)
  1223. PROCEDURE WithEnter (typ: INTEGER);
  1224. VAR tmp: INTEGER;
  1225. BEGIN
  1226. tmp := TempGlobal();
  1227. StoreTemp(tmp);
  1228. IF withTop <= 7 THEN
  1229. withTmps[withTop] := tmp;
  1230. withTyps[withTop] := typ;
  1231. INC(withTop)
  1232. END
  1233. END WithEnter;
  1234. PROCEDURE WithExit;
  1235. BEGIN
  1236. IF withTop > 0 THEN DEC(withTop) END
  1237. END WithExit;
  1238. PROCEDURE WithDepth (): CARDINAL;
  1239. BEGIN RETURN withTop END WithDepth;
  1240. PROCEDURE WithAddr (name: ARRAY OF CHAR);
  1241. VAR i: CARDINAL;
  1242. off: INTEGER;
  1243. found: BOOLEAN;
  1244. BEGIN
  1245. found := FALSE;
  1246. i := withTop;
  1247. WHILE (i > 0) & ~found DO
  1248. DEC(i);
  1249. IF SymTab.FieldExists(withTyps[i], name) THEN
  1250. off := SymTab.FieldOffset(withTyps[i], name);
  1251. LoadTemp(withTmps[i]);
  1252. IF off > 0 THEN
  1253. PushInt(VAL(INTEGER, VAL(CARDINAL, off) * 8));
  1254. EmitOp(OPadd)
  1255. ELSIF off < 0 THEN
  1256. PushInt(0)
  1257. END;
  1258. found := TRUE
  1259. END
  1260. END;
  1261. IF ~found THEN PushInt(0) END
  1262. END WithAddr;
  1263. PROCEDURE PrintNum (): CARDINAL;
  1264. BEGIN RETURN maxNum + 1 END PrintNum;
  1265. PROCEDURE CallPrint;
  1266. BEGIN
  1267. EmitOpB(OPprocCall, maxNum + 1);
  1268. EmitOp(OPext); EmitOp(SUBdrop)
  1269. END CallPrint;
  1270. PROCEDURE SysCall;
  1271. BEGIN EmitOp(OPsys) END SysCall;
  1272. (* ---------------- control flow ---------------- *)
  1273. PROCEDURE NewLabel (): INTEGER;
  1274. BEGIN
  1275. IF nLab > MaxLab THEN RETURN 0 END;
  1276. labs[nLab] := -1;
  1277. INC(nLab);
  1278. RETURN VAL(INTEGER, nLab - 1)
  1279. END NewLabel;
  1280. PROCEDURE DefLabel (id: INTEGER);
  1281. VAR i : CARDINAL;
  1282. rel : INTEGER;
  1283. BEGIN
  1284. IF (id < 0) OR (id >= VAL(INTEGER, nLab)) THEN RETURN END;
  1285. labs[id] := VAL(INTEGER, nCode);
  1286. i := 0;
  1287. WHILE i < nFix DO
  1288. IF fixs[i].lab = id THEN
  1289. rel := labs[id] - VAL(INTEGER, fixs[i].pos + 9);
  1290. WriteS64At(fixs[i].pos + 1, rel);
  1291. fixs[i].lab := -1
  1292. END;
  1293. INC(i)
  1294. END
  1295. END DefLabel;
  1296. PROCEDURE Jump (op: CARDINAL; id: INTEGER);
  1297. VAR pos : CARDINAL;
  1298. j : CARDINAL;
  1299. BEGIN
  1300. pos := nCode;
  1301. EmitOp(op);
  1302. IF (id >= 0) & (id < VAL(INTEGER, nLab)) & (labs[id] >= 0) THEN
  1303. EmitS64(labs[id] - VAL(INTEGER, pos + 9))
  1304. ELSE
  1305. FOR j := 0 TO 7 DO EmitByte(0) END;
  1306. IF (nFix <= MaxFix) & (id >= 0) & (id < VAL(INTEGER, nLab)) THEN
  1307. fixs[nFix].pos := pos; fixs[nFix].lab := id; INC(nFix)
  1308. END
  1309. END
  1310. END Jump;
  1311. PROCEDURE Jmp (id: INTEGER);
  1312. BEGIN
  1313. Jump(OPjp, id)
  1314. END Jmp;
  1315. PROCEDURE Jz (id: INTEGER);
  1316. BEGIN
  1317. Jump(OPjz, id)
  1318. END Jz;
  1319. PROCEDURE PushLoop (exit: INTEGER);
  1320. BEGIN
  1321. IF loopTop <= MaxLoop THEN
  1322. loopSt[loopTop] := exit; INC(loopTop)
  1323. END
  1324. END PushLoop;
  1325. PROCEDURE PopLoop;
  1326. BEGIN
  1327. IF loopTop > 0 THEN DEC(loopTop) END
  1328. END PopLoop;
  1329. PROCEDURE TopLoop (VAR exit: INTEGER): BOOLEAN;
  1330. BEGIN
  1331. IF loopTop = 0 THEN RETURN FALSE END;
  1332. exit := loopSt[loopTop - 1];
  1333. RETURN TRUE
  1334. END TopLoop;
  1335. PROCEDURE NoSupEnter;
  1336. BEGIN
  1337. INC(noSup)
  1338. END NoSupEnter;
  1339. PROCEDURE NoSupExit;
  1340. BEGIN
  1341. IF noSup > 0 THEN DEC(noSup) END
  1342. END NoSupExit;
  1343. PROCEDURE NoSup (): BOOLEAN;
  1344. BEGIN
  1345. RETURN noSup > 0
  1346. END NoSup;
  1347. PROCEDURE CopyName (s: ARRAY OF CHAR; VAR d: ARRAY OF CHAR);
  1348. VAR i : CARDINAL;
  1349. BEGIN
  1350. i := 0;
  1351. WHILE (i < HIGH(d)) & (i < HIGH(s)) & (s[i] # 0C) DO
  1352. d[i] := s[i]; INC(i)
  1353. END;
  1354. IF i <= HIGH(d) THEN d[i] := 0C END
  1355. END CopyName;
  1356. PROCEDURE NoEmitEnter;
  1357. BEGIN
  1358. INC(noEmit)
  1359. END NoEmitEnter;
  1360. PROCEDURE NoEmitExit;
  1361. BEGIN
  1362. IF noEmit > 0 THEN DEC(noEmit) END
  1363. END NoEmitExit;
  1364. (* ---------------- image assembly ---------------- *)
  1365. PROCEDURE Put32At (off: CARDINAL; v: CARDINAL);
  1366. BEGIN
  1367. img[off] := CHR(v MOD 256);
  1368. img[off + 1] := CHR((v DIV 256) MOD 256);
  1369. img[off + 2] := CHR((v DIV 65536) MOD 256);
  1370. img[off + 3] := CHR(v DIV 16777216)
  1371. END Put32At;
  1372. PROCEDURE Put64At (off: CARDINAL; v: LONGCARD);
  1373. VAR j : CARDINAL;
  1374. BEGIN
  1375. FOR j := 0 TO 7 DO
  1376. img[off + j] := CHR(VAL(CARDINAL, v MOD 256));
  1377. v := v DIV 256
  1378. END
  1379. END Put64At;
  1380. PROCEDURE EmitPrint;
  1381. (* proc1: prints the CARDINAL parameter as decimal + CRLF.
  1382. Uses global temps 0..3 (buffer, count, index, char). *)
  1383. VAR l1, l2 : INTEGER;
  1384. BEGIN
  1385. EmitOpB(OPenter, 250);
  1386. EmitOpB(OPimmB, 16); EmitOp(0D2H); EmitOpB(OPstoreGlb, 0);
  1387. EmitOp(OPimm0); EmitOp(OPimm0);
  1388. EmitOpB(OPstoreGlb, 1); EmitOpB(OPstoreGlb, 2);
  1389. EmitOp(03H);
  1390. l1 := NewLabel(); DefLabel(l1);
  1391. EmitOpB(OPloadGlb, 1); EmitOp(OPinc); EmitOpB(OPstoreGlb, 1);
  1392. EmitOp(OPdup); EmitOpB(OPimmB, 10); EmitOp(OPumod);
  1393. EmitOp(OPswap); EmitOpB(OPimmB, 10); EmitOp(OPudiv);
  1394. EmitOp(OPdup); EmitOp(OPaeq0);
  1395. Jz(l1);
  1396. EmitOp(OPext); EmitOp(SUBdrop);
  1397. l2 := NewLabel(); DefLabel(l2);
  1398. EmitOpB(OPimmB, 48); EmitOp(OPadd); EmitOpB(OPstoreGlb, 3);
  1399. EmitOpB(OPloadGlb, 0); EmitOpB(OPloadGlb, 2); EmitOp(OPadd);
  1400. EmitOp(OPimm0); EmitOpB(OPloadGlb, 3); EmitOp(1DH);
  1401. EmitOpB(OPloadGlb, 2); EmitOp(OPinc); EmitOpB(OPstoreGlb, 2);
  1402. EmitOpB(OPloadGlb, 1); EmitOp(OPdec); EmitOpB(OPstoreGlb, 1);
  1403. EmitOpB(OPloadGlb, 1); EmitOp(OPaeq0);
  1404. Jz(l2);
  1405. EmitOpB(OPloadGlb, 0); EmitOpB(OPloadGlb, 2); EmitOp(OPadd);
  1406. EmitOp(OPimm0); EmitOp(OPimm0); EmitOp(1DH);
  1407. EmitOpB(OPloadGlb, 0);
  1408. EmitOpB(OPimmB, 1); EmitOp(OPsys);
  1409. EmitOpB(OPimmB, 3); EmitOp(0D2H);
  1410. EmitOp(OPdup); EmitOp(OPimm0); EmitOpB(OPimmB, 13); EmitOp(1DH);
  1411. EmitOp(OPdup); EmitOpB(OPimmB, 1); EmitOpB(OPimmB, 10); EmitOp(1DH);
  1412. EmitOp(OPdup); EmitOpB(OPimmB, 2); EmitOp(OPimm0); EmitOp(1DH);
  1413. EmitOpB(OPimmB, 1); EmitOp(OPsys);
  1414. EmitOpB(OPfctLeave, 0)
  1415. END EmitPrint;
  1416. PROCEDURE PutS64At (off, addr, slot: CARDINAL);
  1417. (* Procedure-table cell: signed (addr - slot). *)
  1418. VAR mag : LONGCARD;
  1419. bits : LONGCARD;
  1420. j : CARDINAL;
  1421. BEGIN
  1422. IF addr >= slot THEN bits := VAL(LONGCARD, addr - slot)
  1423. ELSE
  1424. mag := VAL(LONGCARD, slot - addr);
  1425. bits := 0FFFFFFFFFFFFFFFFH - mag + 1H
  1426. END;
  1427. FOR j := 0 TO 7 DO
  1428. img[off + j] := CHR(VAL(CARDINAL, bits MOD 256));
  1429. bits := bits DIV 256
  1430. END
  1431. END PutS64At;
  1432. PROCEDURE EndModule;
  1433. VAR i : CARDINAL;
  1434. codeOff, p1, pt, prNum, tabBytes : CARDINAL;
  1435. k : CARDINAL;
  1436. addr : CARDINAL;
  1437. exitIdx : INTEGER;
  1438. sum : CARDINAL;
  1439. fname : ARRAY [0 .. 127] OF CHAR;
  1440. f : FileIO.File;
  1441. ch : CHAR;
  1442. BEGIN
  1443. IF ~inBody THEN mainAddr := nCode END;
  1444. prNum := maxNum + 1;
  1445. (* epilogue: print ExitCode when the convention applies *)
  1446. exitIdx := -1;
  1447. IF SymTab.Lookup("ExitCode")
  1448. & (SymTab.SymKind("ExitCode") = SymTab.KindVar)
  1449. & SymTab.IsIntFamily(SymTab.SymType("ExitCode")) THEN
  1450. exitIdx := FindVar("ExitCode")
  1451. END;
  1452. IF exitIdx >= 0 THEN
  1453. EmitOpB(OPloadGlb, VAL(CARDINAL, exitIdx));
  1454. EmitOpB(OPprocCall, prNum);
  1455. EmitOp(OPext); EmitOp(SUBdrop)
  1456. END;
  1457. EmitOp(OPend);
  1458. p1 := nCode;
  1459. EmitPrint;
  1460. (* assemble the image *)
  1461. i := 0;
  1462. WHILE i <= MaxImg DO img[i] := 0C; INC(i) END;
  1463. img[0] := "M"; img[1] := "C"; img[2] := "6"; img[3] := "4";
  1464. i := 0;
  1465. WHILE (i < 16) & (modName[i] # 0C) DO
  1466. img[HeadSize + DName + i] := modName[i]; INC(i)
  1467. END;
  1468. img[HeadSize + DFlags] := CHR(4);
  1469. img[HeadSize + DVarCount] := CHR(nVars MOD 256);
  1470. img[HeadSize + DDepCount] := 0C;
  1471. codeOff := DVarSizes + nVars * 8;
  1472. i := 0;
  1473. WHILE i < nCode DO
  1474. img[HeadSize + codeOff + i] := code[i]; INC(i)
  1475. END;
  1476. pt := codeOff + nCode;
  1477. tabBytes := (maxNum + 2) * 8;
  1478. Put64At(HeadSize + DProcs, VAL(LONGCARD, pt));
  1479. k := 0;
  1480. WHILE k <= maxNum + 1 DO
  1481. IF k = 0 THEN addr := codeOff + mainAddr
  1482. ELSIF k <= maxNum THEN
  1483. IF procAddr[k] < 0 THEN addr := pt + k * 8
  1484. ELSE addr := VAL(CARDINAL, procAddr[k]) + codeOff
  1485. END
  1486. ELSE addr := codeOff + p1
  1487. END;
  1488. PutS64At(HeadSize + pt + k * 8, addr, pt + k * 8);
  1489. INC(k)
  1490. END;
  1491. i := 0;
  1492. WHILE i < nVars DO
  1493. Put64At(HeadSize + DVarSizes + i * 8,
  1494. VAL(LONGCARD, vSize[i] * 8));
  1495. INC(i)
  1496. END;
  1497. sum := 0;
  1498. i := HeadSize;
  1499. WHILE i < HeadSize + pt + tabBytes DO
  1500. IF ~((i >= 352) & (i <= 355)) THEN
  1501. sum := sum + ORD(img[i])
  1502. END;
  1503. INC(i)
  1504. END;
  1505. Put32At(HeadSize + DChecksum, sum);
  1506. fname[0] := 0C;
  1507. StrCpy(fname, modName);
  1508. i := StrLen(fname);
  1509. fname[i] := "."; fname[i + 1] := "M"; fname[i + 2] := "C";
  1510. fname[i + 3] := "4"; fname[i + 4] := 0C;
  1511. FileIO.Open(f, fname, TRUE);
  1512. IF FileIO.Okay THEN
  1513. i := 0;
  1514. WHILE i < HeadSize + pt + tabBytes DO
  1515. ch := img[i];
  1516. FileIO.Write(f, ch);
  1517. INC(i)
  1518. END;
  1519. FileIO.Close(f)
  1520. END
  1521. END EndModule;
  1522. BEGIN
  1523. nCode := 0; nGlb := 0; nVars := 0; nInit := 0;
  1524. nLab := 0; nFix := 0; loopTop := 0; noSup := 0; noEmit := 0;
  1525. actTop := 0; withTop := 0;
  1526. maxNum := 0; mainAddr := 0;
  1527. nInits := 0;
  1528. inBody := FALSE;
  1529. modName[0] := 0C
  1530. END MGen.