MGen.mod 40 KB

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