MGen.mod 43 KB

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