Compiler.mod 75 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830
  1. IMPLEMENTATION MODULE Compiler ;
  2. (* Turbo Pascal 3-style single-pass Pascal -> 8086 compiler in
  3. GNU Modula-2 (-fiso), following the structure of the original
  4. TPSRC6 'turbo' entry / TPSRC7-10:
  5. Inittur reset state, pre-defined types, scratch temporaries
  6. Skip lexer: blanks, comments { } and (* *), directives {$ }
  7. GetWord/WddTok/MatchKey word lexing with a keyword table (kName/kTk)
  8. PeekKw lookahead keyword check WITHOUT consuming (via saved
  9. srcPos) - needed because declarations and compound
  10. statements peek at END/ELSE/etc
  11. RdIntConst/RdConst integer, hex and char constants
  12. Search symbol table lookup filtered by lexical level
  13. ParseExpr -> ParseCmp -> ParseAdd -> ParseMul -> ParseNeg
  14. -> ParseAtom precedence climb (TPSRC9)
  15. Statmnt statements: if/while/repeat/for/case/goto/exit/begin
  16. assignment and calls (TPSRC8)
  17. ParseType/Decls ARRAY, STRING, scalar/subrange types; variable,
  18. constant, label and procedure/function definitions
  19. Compile driver: optional PROGRAM header, DefPart, progpart,
  20. final '.', header size patch, patch resolution.
  21. Ebyte/Eword/Ecall/Ejmp + patch list code emission (TPSRC10).
  22. The emitted image is a byte array (mode word, CS/DS, size words,
  23. CALL initmem, MOV BP,SP, then generated code). Forward labels and
  24. forward procedure calls resolve through a patch list (ptc records).
  25. Working subset (v0.4): integer/char/boolean/byte scalars, constants
  26. with folding, globals, locals, value parameters, procedures and
  27. scalar-result functions, ARRAY[const..const] with constant indexing,
  28. control flow, GOTO/EXIT, and the standard procedures WRITE, WRITELN,
  29. READ, READLN, HALT (DefBuiltins + IoCall).
  30. The standard procedures are dispatched per argument, as the original
  31. does (TPSRC8 pwriteln/pwrloop inspects each argument's class and emits
  32. a different call per type), so the runtime is handed a value and never
  33. a descriptor.
  34. Still not implemented: real/set/record/file and the string runtime
  35. raise Err (ENoLib) - the original's "not implemented" path. The
  36. runtime blob itself, the linker that rebases the TU_* entry offsets
  37. by the runtime's size, and CmdRun (the interpreter) are still pending,
  38. so a compiled image cannot be executed yet. *)
  39. FROM TextBuf IMPORT Length, CharAt ;
  40. FROM SYSTEM IMPORT BYTE ;
  41. (* ---------------------------------------------------------------- *)
  42. (* constants *)
  43. (* ---------------------------------------------------------------- *)
  44. CONST
  45. MaxLine = 128 ;
  46. MaxName = 31 ;
  47. MaxCode = 24000 ;
  48. MaxSym = 3000 ;
  49. MaxPatch = 2000 ;
  50. MaxPend = 400 ;
  51. (* type codes (TP3 vartp) *)
  52. TNone = 0 ; TArray = 1 ; TRecord = 2 ; TSet = 3 ;
  53. TPtr = 4 ; TFile = 5 ; TText = 6 ; TUntyp = 7 ;
  54. TString = 8 ; TReal = 9 ; TScalar = 10 ; TBool = 11 ;
  55. (* symbol kinds *)
  56. KLabel = 100H ; KConst = 200H ; KType = 300H ;
  57. KVar = 400H ; KProc = 500H ; KFunc = 600H ;
  58. KBuiltin = 700H ; (* standard procedure, see BI_* below *)
  59. (* which standard procedure a KBuiltin symbol denotes *)
  60. BI_Write = 0 ; BI_WriteLn = 1 ; BI_Read = 2 ;
  61. BI_ReadLn = 3 ; BI_Halt = 4 ;
  62. (* keyword tokens *)
  63. TkNone = 0 ; TkProgram = 1 ; TkBegin = 2 ; TkEnd = 3 ;
  64. TkIf = 4 ; TkThen = 5 ; TkElse = 6 ; TkWhile = 7 ;
  65. TkDo = 8 ; TkRepeat = 9 ; TkUntil = 10 ; TkFor = 11 ;
  66. TkTo = 12 ; TkDownto = 13 ; TkCase = 14 ; TkOf = 15 ;
  67. TkGoto = 16 ; TkExit = 17 ; TkWith = 18 ; TkVar = 19 ;
  68. TkConst= 20 ; TkType = 21 ; TkLabel = 22 ; TkProcedure = 23 ;
  69. TkFunction = 24 ; TkNil = 25 ; TkAnd = 26 ; TkOr = 27 ;
  70. TkNot = 28 ; TkDiv = 29 ; TkMod = 30 ; TkIn = 31 ;
  71. TkFile = 32 ; TkText = 33 ; TkRecord = 34 ; TkArray = 35 ;
  72. TkSet = 36 ; TkPacked = 37 ; TkForward = 38 ; TkExternal = 39 ;
  73. TkAbsolute = 40 ; TkOverlay = 41 ; TkString = 42 ;
  74. (* runtime entry offsets in the emitted image (TU_InitMem etc.) *)
  75. TU_InitMem = 8H ;
  76. TU_ProgEnd = 10H ;
  77. TU_StackChk = 18H ;
  78. (* Standard-procedure runtime entries. TP3 does NOT pass a descriptor:
  79. TPSRC8 pwriteln/pwrloop inspects each argument's class in CL and emits
  80. a *different* call per type, so the type is fixed at compile time and
  81. the runtime needs only the value. Mirrored here. *)
  82. TU_WrInt = 20H ; TU_WrChar = 28H ; TU_WrBool = 30H ;
  83. TU_WrReal = 38H ; TU_WrLn = 40H ;
  84. TU_RdInt = 48H ; TU_RdChar = 50H ; TU_RdBool = 58H ;
  85. TU_RdLn = 60H ; TU_Halt = 68H ;
  86. (* TP3 error numbers *)
  87. ENoSemi = 1 ; EPointExp = 10 ; ESimpType = 30 ;
  88. EUnknown = 41 ; EConstRange = 45 ; EMemOvf = 98 ;
  89. ECompOvf = 99 ; ENoLib = 102 ; ETypeErr = 56 ;
  90. AposC = 39 ; (* ORD ("'") - avoids quote-in-quote *)
  91. (* ---------------------------------------------------------------- *)
  92. (* types *)
  93. (* ---------------------------------------------------------------- *)
  94. TYPE
  95. SymEntry =
  96. RECORD
  97. name : ARRAY [0..MaxName] OF CHAR ;
  98. tag : CARDINAL ;
  99. cls : CARDINAL ;
  100. size : CARDINAL ;
  101. elem : CARDINAL ;
  102. off : CARDINAL ;
  103. lval : LONGINT ;
  104. level : CARDINAL ;
  105. local : BOOLEAN ;
  106. resvar : CARDINAL ;
  107. goPos : CARDINAL ;
  108. defnd : BOOLEAN ;
  109. fwd : BOOLEAN ;
  110. END ;
  111. PatchRec =
  112. RECORD
  113. place : CARDINAL ;
  114. target : CARDINAL ;
  115. filled : BOOLEAN ;
  116. END ;
  117. PendRec =
  118. RECORD
  119. kind : CARDINAL ; (* 0 goto, 1 call *)
  120. who : CARDINAL ;
  121. place : CARDINAL ; (* patch slot index *)
  122. END ;
  123. ERes =
  124. RECORD
  125. cls : CARDINAL ;
  126. kind : CARDINAL ; (* 0 const, 1 var, 2 value in AX *)
  127. imm : LONGINT ;
  128. idx : CARDINAL ;
  129. boff : CARDINAL ; (* constant fold-in for subscripts *)
  130. chr : BOOLEAN ; (* single-quoted literal, e.g. 'a' *)
  131. END ;
  132. DirRec = RECORD rng, chk : BOOLEAN END ;
  133. (* ---------------------------------------------------------------- *)
  134. (* state *)
  135. (* ---------------------------------------------------------------- *)
  136. VAR
  137. srcPos, srcLen : CARDINAL ;
  138. wrd : ARRAY [0..MaxName] OF CHAR ;
  139. symtab : ARRAY [0..MaxSym - 1] OF SymEntry ;
  140. symTop : CARDINAL ;
  141. patches : ARRAY [0..MaxPatch - 1] OF PatchRec ;
  142. nPatch : CARDINAL ;
  143. pend : ARRAY [0..MaxPend - 1] OF PendRec ;
  144. nPend : CARDINAL ;
  145. exitPatch : ARRAY [0..63] OF CARDINAL ;
  146. exitCnt : CARDINAL ;
  147. brkSave : ARRAY [0..15] OF CARDINAL ;
  148. loopTy : ARRAY [0..15] OF CARDINAL ; (* 1 while/repeat, 2 for *)
  149. brkN : CARDINAL ;
  150. caseJmp : ARRAY [0..63] OF CARDINAL ;
  151. caseN : CARDINAL ;
  152. pc, dc : CARDINAL ;
  153. varspc : CARDINAL ;
  154. cbuf : ARRAY [0..MaxCode - 1] OF BYTE ;
  155. codeSz, dataSz : CARDINAL ;
  156. abortFac : BOOLEAN ;
  157. errNum : CARDINAL ; (* NOT "errNo": Compile's formal of that
  158. name would shadow it, and the caller's
  159. errNo would never be filled in *)
  160. txerrPos : CARDINAL ;
  161. lexnest : CARDINAL ;
  162. curIsFunc : BOOLEAN ;
  163. resultVar : CARDINAL ;
  164. locFree : CARDINAL ; (* next local slot (BP-relative, 8-bit) *)
  165. locBytes : CARDINAL ; (* frame size for SUB SP *)
  166. parmOff : CARDINAL ; (* next parameter slot (BP-relative) *)
  167. dirs : DirRec ;
  168. tmpA, tmpB : CARDINAL ; (* global scratch word addresses *)
  169. hdrFlag, hdrCS, hdrDS, hdrHeap, hdrMax : CARDINAL ;
  170. kName : ARRAY [0..42] OF ARRAY [0..15] OF CHAR ;
  171. kTk : ARRAY [0..42] OF CARDINAL ;
  172. (* ---------------------------------------------------------------- *)
  173. (* small char helpers *)
  174. (* ---------------------------------------------------------------- *)
  175. PROCEDURE CurCh () : CHAR ;
  176. BEGIN
  177. IF srcPos >= srcLen THEN
  178. RETURN 0C
  179. END ;
  180. RETURN CharAt (srcPos)
  181. END CurCh ;
  182. PROCEDURE GetCh () : CHAR ;
  183. VAR ch : CHAR ;
  184. BEGIN
  185. ch := CurCh () ;
  186. IF srcPos < srcLen THEN
  187. INC (srcPos)
  188. END ;
  189. RETURN ch
  190. END GetCh ;
  191. PROCEDURE PeekAhead (k : CARDINAL) : CHAR ;
  192. BEGIN
  193. IF srcPos + k >= srcLen THEN
  194. RETURN 0C
  195. END ;
  196. RETURN CharAt (srcPos + k)
  197. END PeekAhead ;
  198. PROCEDURE Digit (ch : CHAR) : BOOLEAN ;
  199. BEGIN
  200. RETURN (ch >= '0') AND (ch <= '9')
  201. END Digit ;
  202. PROCEDURE Alpha (ch : CHAR) : BOOLEAN ;
  203. BEGIN
  204. RETURN ((ch >= 'A') AND (ch <= 'Z')) OR ((ch >= 'a') AND (ch <= 'z'))
  205. OR (ch = '_')
  206. END Alpha ;
  207. PROCEDURE AlphaNum (ch : CHAR) : BOOLEAN ;
  208. BEGIN
  209. RETURN (Alpha (ch)) OR (Digit (ch))
  210. END AlphaNum ;
  211. PROCEDURE IsHexCh (ch : CHAR) : BOOLEAN ;
  212. BEGIN
  213. RETURN (Digit (ch)) OR ((ch >= 'A') AND (ch <= 'F'))
  214. OR ((ch >= 'a') AND (ch <= 'f'))
  215. END IsHexCh ;
  216. PROCEDURE Upper (ch : CHAR) : CHAR ;
  217. BEGIN
  218. IF (ch >= 'a') AND (ch <= 'z') THEN
  219. RETURN CHR (ORD (ch) - ORD ('a') + ORD ('A'))
  220. END ;
  221. RETURN ch
  222. END Upper ;
  223. PROCEDURE W16 (x : LONGINT) : CARDINAL ;
  224. (* fold x modulo 10000H, handling negatives (no negative MOD) *)
  225. VAR m : CARDINAL ;
  226. BEGIN
  227. IF x >= 0 THEN
  228. RETURN VAL (CARDINAL, x MOD 10000H)
  229. END ;
  230. m := VAL (CARDINAL, (0 - x) MOD 10000H) ;
  231. RETURN (10000H - m) MOD 10000H
  232. END W16 ;
  233. PROCEDURE DropCh (v : CHAR) ;
  234. BEGIN
  235. END DropCh ;
  236. PROCEDURE DropB (v : BOOLEAN) ;
  237. BEGIN
  238. END DropB ;
  239. PROCEDURE DropC (v : CARDINAL) ;
  240. BEGIN
  241. END DropC ;
  242. PROCEDURE BitAnd (a, b : LONGINT) : LONGINT ;
  243. BEGIN
  244. RETURN VAL (LONGINT, CARDINAL (VAL (BITSET, W16 (a))
  245. * VAL (BITSET, W16 (b))))
  246. END BitAnd ;
  247. PROCEDURE BitOr (a, b : LONGINT) : LONGINT ;
  248. BEGIN
  249. RETURN VAL (LONGINT, CARDINAL (VAL (BITSET, W16 (a))
  250. + VAL (BITSET, W16 (b))))
  251. END BitOr ;
  252. PROCEDURE BitNot (a : LONGINT) : LONGINT ;
  253. BEGIN
  254. RETURN VAL (LONGINT, CARDINAL (VAL (BITSET, 0FFFFH)
  255. - VAL (BITSET, W16 (a))))
  256. END BitNot ;
  257. (* ---------------------------------------------------------------- *)
  258. (* errors *)
  259. (* ---------------------------------------------------------------- *)
  260. PROCEDURE Err (n : CARDINAL) ;
  261. BEGIN
  262. IF NOT abortFac THEN
  263. abortFac := TRUE ;
  264. errNum := n ;
  265. txerrPos := srcPos
  266. END
  267. END Err ;
  268. PROCEDURE OK () : BOOLEAN ;
  269. BEGIN
  270. RETURN NOT abortFac
  271. END OK ;
  272. (* ---------------------------------------------------------------- *)
  273. (* emission : ebyte / eword / ecall / ejump *)
  274. (* ---------------------------------------------------------------- *)
  275. PROCEDURE Ebyte (b : BYTE) ;
  276. BEGIN
  277. IF pc >= MaxCode THEN
  278. Err (EMemOvf)
  279. ELSE
  280. cbuf [pc] := b ;
  281. INC (pc)
  282. END
  283. END Ebyte ;
  284. PROCEDURE Eword (w : CARDINAL) ;
  285. BEGIN
  286. Ebyte (VAL (BYTE, w MOD 100H)) ;
  287. Ebyte (VAL (BYTE, (w DIV 100H) MOD 100H))
  288. END Eword ;
  289. PROCEDURE AddPatch (place, target : CARDINAL) ;
  290. BEGIN
  291. IF nPatch < MaxPatch THEN
  292. patches [nPatch].place := place ;
  293. patches [nPatch].target := target ;
  294. patches [nPatch].filled := FALSE ;
  295. INC (nPatch)
  296. ELSE
  297. Err (ECompOvf)
  298. END
  299. END AddPatch ;
  300. PROCEDURE SetPatTgt (idx, t : CARDINAL) ;
  301. BEGIN
  302. IF idx < nPatch THEN
  303. patches [idx].target := t
  304. END
  305. END SetPatTgt ;
  306. PROCEDURE EmCall (target : CARDINAL) : CARDINAL ;
  307. (* E8 rel16 near call; target = 0 => forward (patched later).
  308. Returns the patch slot, or 0 when resolved directly. *)
  309. VAR rel, p : CARDINAL ;
  310. BEGIN
  311. Ebyte (0E8H) ;
  312. IF target = 0 THEN
  313. Eword (0) ;
  314. p := nPatch ;
  315. AddPatch (pc - 2, 0) ;
  316. RETURN p
  317. END ;
  318. (* rel16 is measured from the END of the instruction. Here pc already
  319. points past the opcode(s) and at the displacement field, so the
  320. instruction ends at pc+2 - the same convention ResolvePatches uses
  321. with "place + 2". Omitting the +2 lands every direct call/jump 2 bytes
  322. past its target. *)
  323. rel := (target + 10000H - (pc + 2)) MOD 10000H ;
  324. Eword (rel) ;
  325. RETURN 0
  326. END EmCall ;
  327. PROCEDURE EmJmpNear (target : CARDINAL) : CARDINAL ;
  328. (* E9 rel16; target = 0 => forward. Returns patch slot or 0. *)
  329. VAR rel, p : CARDINAL ;
  330. BEGIN
  331. Ebyte (0E9H) ;
  332. IF target = 0 THEN
  333. Eword (0) ;
  334. p := nPatch ;
  335. AddPatch (pc - 2, 0) ;
  336. RETURN p
  337. END ;
  338. rel := (target + 10000H - (pc + 2)) MOD 10000H ; (* see EmCall *)
  339. Eword (rel) ;
  340. RETURN 0
  341. END EmJmpNear ;
  342. PROCEDURE EmJcc (cc : BYTE ; target : CARDINAL) : CARDINAL ;
  343. (* 0F 8x rel16 near conditional; target = 0 => forward. *)
  344. VAR rel, p : CARDINAL ;
  345. BEGIN
  346. Ebyte (0FH) ;
  347. Ebyte (cc) ;
  348. IF target = 0 THEN
  349. Eword (0) ;
  350. p := nPatch ;
  351. AddPatch (pc - 2, 0) ;
  352. RETURN p
  353. END ;
  354. rel := (target + 10000H - (pc + 2)) MOD 10000H ; (* see EmCall *)
  355. Eword (rel) ;
  356. RETURN 0
  357. END EmJcc ;
  358. PROCEDURE ResolvePatches () ;
  359. VAR i : CARDINAL ;
  360. rel : CARDINAL ;
  361. BEGIN
  362. i := 0 ;
  363. WHILE i < nPatch DO
  364. IF NOT patches [i].filled THEN
  365. rel := (patches [i].target + 10000H - (patches [i].place + 2))
  366. MOD 10000H ;
  367. cbuf [patches [i].place] := VAL (BYTE, rel MOD 100H) ;
  368. cbuf [patches [i].place + 1] := VAL (BYTE, (rel DIV 100H) MOD 100H) ;
  369. patches [i].filled := TRUE
  370. END ;
  371. INC (i)
  372. END
  373. END ResolvePatches ;
  374. (* 1-byte const emitters *)
  375. PROCEDURE EmMovAxi (imm : CARDINAL) ;
  376. BEGIN
  377. Ebyte (0B8H) ; Eword (imm)
  378. END EmMovAxi ;
  379. PROCEDURE EmMovBpSp () ;
  380. BEGIN
  381. Ebyte (8BH) ; Ebyte (0ECH)
  382. END EmMovBpSp ;
  383. PROCEDURE EmMovAh0 () ;
  384. BEGIN
  385. Ebyte (0B4H) ; Ebyte (0H)
  386. END EmMovAh0 ;
  387. PROCEDURE EmMovAxSp () ;
  388. (* MOV AX,[SP]. Needs a SIB byte, and [SP] cannot be encoded with mod=00
  389. (that would compute BP+SP), so it is mod=01 / SIB=24h / disp8=0. Emitting
  390. just "8B 04" left the SIB slot unfilled, which silently ate the *next*
  391. instruction - the case-label CMP - and turned every case comparison into
  392. a load from a garbage address. *)
  393. BEGIN
  394. Ebyte (8BH) ; Ebyte (44H) ; Ebyte (24H) ; Ebyte (0)
  395. END EmMovAxSp ;
  396. PROCEDURE EmMovCxSp () ;
  397. BEGIN
  398. Ebyte (8BH) ; Ebyte (0CH)
  399. END EmMovCxSp ;
  400. PROCEDURE EmPushAx () ;
  401. BEGIN
  402. Ebyte (50H)
  403. END EmPushAx ;
  404. PROCEDURE EmPopCx () ;
  405. BEGIN
  406. Ebyte (59H)
  407. END EmPopCx ;
  408. PROCEDURE EmPopDx () ;
  409. BEGIN
  410. Ebyte (5AH)
  411. END EmPopDx ;
  412. PROCEDURE EmXchgAxCx () ;
  413. BEGIN
  414. Ebyte (93H)
  415. END EmXchgAxCx ;
  416. PROCEDURE EmXorAxAx () ;
  417. BEGIN
  418. Ebyte (33H) ; Ebyte (0C0H)
  419. END EmXorAxAx ;
  420. PROCEDURE EmAddAxCx () ;
  421. BEGIN
  422. Ebyte (3H) ; Ebyte (0C1H)
  423. END EmAddAxCx ;
  424. PROCEDURE EmSubAxCx () ;
  425. BEGIN
  426. Ebyte (2BH) ; Ebyte (0C1H)
  427. END EmSubAxCx ;
  428. PROCEDURE EmMulAxCx () ;
  429. BEGIN
  430. Ebyte (0F7H) ; Ebyte (0E9H)
  431. END EmMulAxCx ;
  432. PROCEDURE EmIDivAxCx () ;
  433. BEGIN
  434. Ebyte (99H) ; Ebyte (0F7H) ; Ebyte (0F9H)
  435. END EmIDivAxCx ;
  436. PROCEDURE EmAndAxCx () ;
  437. BEGIN
  438. Ebyte (23H) ; Ebyte (0C1H)
  439. END EmAndAxCx ;
  440. PROCEDURE EmOrAxCx () ;
  441. BEGIN
  442. Ebyte (0BH) ; Ebyte (0C1H)
  443. END EmOrAxCx ;
  444. PROCEDURE EmNegAx () ;
  445. BEGIN
  446. Ebyte (0F7H) ; Ebyte (0D8H)
  447. END EmNegAx ;
  448. PROCEDURE EmNotAx () ;
  449. BEGIN
  450. Ebyte (0F7H) ; Ebyte (0D0H)
  451. END EmNotAx ;
  452. PROCEDURE EmCmpAxCx () ;
  453. BEGIN
  454. Ebyte (3BH) ; Ebyte (0C1H)
  455. END EmCmpAxCx ;
  456. PROCEDURE EmCmpAxi (imm : CARDINAL) ;
  457. BEGIN
  458. Ebyte (03DH) ; Eword (imm)
  459. END EmCmpAxi ;
  460. PROCEDURE EmSetcc (cc : BYTE) ;
  461. BEGIN
  462. Ebyte (0FH) ; Ebyte (cc) ; Ebyte (0C0H) ;
  463. EmMovAh0 ()
  464. END EmSetcc ;
  465. PROCEDURE EmIncAx () ;
  466. BEGIN
  467. Ebyte (40H)
  468. END EmIncAx ;
  469. PROCEDURE EmDecAx () ;
  470. BEGIN
  471. Ebyte (48H)
  472. END EmDecAx ;
  473. PROCEDURE EmLoadVar (local : BOOLEAN ; off, nbytes : CARDINAL) ;
  474. VAR disp : CARDINAL ;
  475. BEGIN
  476. disp := off MOD 100H ;
  477. IF nbytes = 1 THEN
  478. IF local THEN
  479. Ebyte (8AH) ; Ebyte (46H) ; Ebyte (VAL (BYTE, disp))
  480. ELSE
  481. Ebyte (0A0H) ; Eword (off)
  482. END
  483. ELSE
  484. IF local THEN
  485. Ebyte (8BH) ; Ebyte (46H) ; Ebyte (VAL (BYTE, disp))
  486. ELSE
  487. Ebyte (0A1H) ; Eword (off)
  488. END
  489. END
  490. END EmLoadVar ;
  491. PROCEDURE EmStoreVar (local : BOOLEAN ; off, nbytes : CARDINAL) ;
  492. VAR disp : CARDINAL ;
  493. BEGIN
  494. disp := off MOD 100H ;
  495. IF nbytes = 1 THEN
  496. IF local THEN
  497. Ebyte (88H) ; Ebyte (46H) ; Ebyte (VAL (BYTE, disp))
  498. ELSE
  499. Ebyte (0A2H) ; Eword (off)
  500. END
  501. ELSE
  502. IF local THEN
  503. Ebyte (89H) ; Ebyte (46H) ; Ebyte (VAL (BYTE, disp))
  504. ELSE
  505. Ebyte (0A3H) ; Eword (off)
  506. END
  507. END
  508. END EmStoreVar ;
  509. PROCEDURE EmPushVarAddr (local : BOOLEAN ; off : CARDINAL) ;
  510. (* LEA AX,[BP+disp] / LEA AX,[off] then PUSH AX - READ passes the address of
  511. a variable, not its value. 8D 46 disp is LEA AX,[BP+disp] and 8D 06 off
  512. is LEA AX,[off] (mod=00 rm=110 = direct disp16), both 8086-legal. *)
  513. VAR disp : CARDINAL ;
  514. BEGIN
  515. disp := off MOD 100H ;
  516. IF local THEN
  517. Ebyte (8DH) ; Ebyte (46H) ; Ebyte (VAL (BYTE, disp))
  518. ELSE
  519. Ebyte (8DH) ; Ebyte (06H) ; Eword (off)
  520. END ;
  521. EmPushAx ()
  522. END EmPushVarAddr ;
  523. PROCEDURE EmSubSp (n : CARDINAL) ;
  524. BEGIN
  525. Ebyte (81H) ; Ebyte (0ECH) ; Eword (n MOD 10000H)
  526. END EmSubSp ;
  527. PROCEDURE EmAddSp (n : CARDINAL) ;
  528. BEGIN
  529. IF n <= 126 THEN
  530. Ebyte (83H) ; Ebyte (0C4H) ; Ebyte (VAL (BYTE, n))
  531. ELSE
  532. Ebyte (81H) ; Ebyte (0C4H) ; Eword (n MOD 10000H)
  533. END
  534. END EmAddSp ;
  535. PROCEDURE EmPushBp () ;
  536. BEGIN
  537. Ebyte (55H)
  538. END EmPushBp ;
  539. PROCEDURE EmLeave () ;
  540. BEGIN
  541. Ebyte (0C9H)
  542. END EmLeave ;
  543. PROCEDURE EmRet () ;
  544. BEGIN
  545. Ebyte (0C3H)
  546. END EmRet ;
  547. (* ---------------------------------------------------------------- *)
  548. (* symbol table *)
  549. (* ---------------------------------------------------------------- *)
  550. PROCEDURE NameEq (a : ARRAY OF CHAR ; b : ARRAY OF CHAR) : BOOLEAN ;
  551. VAR i : CARDINAL ;
  552. BEGIN
  553. i := 0 ;
  554. LOOP
  555. IF i > HIGH (a) THEN
  556. RETURN FALSE
  557. END ;
  558. IF i > HIGH (b) THEN
  559. RETURN FALSE
  560. END ;
  561. IF a [i] # b [i] THEN
  562. RETURN FALSE
  563. END ;
  564. IF a [i] = 0C THEN
  565. RETURN TRUE
  566. END ;
  567. INC (i)
  568. END
  569. END NameEq ;
  570. PROCEDURE CopyStr (VAR dst : ARRAY OF CHAR ; src : ARRAY OF CHAR) ;
  571. VAR i : CARDINAL ;
  572. BEGIN
  573. i := 0 ;
  574. LOOP
  575. IF i > HIGH (dst) THEN
  576. dst [HIGH (dst)] := 0C ;
  577. RETURN
  578. END ;
  579. IF i > HIGH (src) THEN
  580. dst [i] := 0C ;
  581. RETURN
  582. END ;
  583. dst [i] := src [i] ;
  584. IF src [i] = 0C THEN
  585. RETURN
  586. END ;
  587. INC (i)
  588. END
  589. END CopyStr ;
  590. PROCEDURE CopyWord (name : ARRAY OF CHAR) ;
  591. (* stash current word into global wrd (uppercased) *)
  592. VAR i : CARDINAL ;
  593. BEGIN
  594. i := 0 ;
  595. LOOP
  596. IF i > HIGH (name) THEN
  597. wrd [i] := 0C ;
  598. RETURN
  599. END ;
  600. IF i > MaxName THEN
  601. wrd [MaxName] := 0C ;
  602. RETURN
  603. END ;
  604. IF name [i] = 0C THEN
  605. wrd [i] := 0C ;
  606. RETURN
  607. END ;
  608. wrd [i] := Upper (name [i]) ;
  609. INC (i)
  610. END
  611. END CopyWord ;
  612. PROCEDURE SaveWord (VAR dst : ARRAY OF CHAR) ;
  613. (* copy wrd into dst *)
  614. VAR i : CARDINAL ;
  615. BEGIN
  616. i := 0 ;
  617. LOOP
  618. IF i > HIGH (dst) THEN
  619. dst [HIGH (dst)] := 0C ;
  620. RETURN
  621. END ;
  622. IF i > MaxName THEN
  623. dst [MaxName] := 0C ;
  624. RETURN
  625. END ;
  626. dst [i] := wrd [i] ;
  627. IF wrd [i] = 0C THEN
  628. RETURN
  629. END ;
  630. INC (i)
  631. END
  632. END SaveWord ;
  633. PROCEDURE NumToName (n : CARDINAL ; VAR dst : ARRAY OF CHAR) ;
  634. VAR buf : ARRAY [0..9] OF CHAR ;
  635. i, j : CARDINAL ;
  636. BEGIN
  637. IF n = 0 THEN
  638. dst [0] := '0' ;
  639. dst [1] := 0C ;
  640. RETURN
  641. END ;
  642. i := 0 ;
  643. WHILE n > 0 DO
  644. IF i <= 9 THEN
  645. buf [i] := CHR (ORD ('0') + (n MOD 10)) ;
  646. INC (i)
  647. END ;
  648. n := n DIV 10
  649. END ;
  650. j := 0 ;
  651. WHILE i > 0 DO
  652. DEC (i) ;
  653. IF j <= HIGH (dst) THEN
  654. dst [j] := buf [i] ;
  655. INC (j)
  656. END
  657. END ;
  658. IF j <= HIGH (dst) THEN
  659. dst [j] := 0C
  660. END
  661. END NumToName ;
  662. PROCEDURE NewSym (name : ARRAY OF CHAR ; tag : CARDINAL ;
  663. cls, size, elem, off : CARDINAL ; v : LONGINT ;
  664. local : BOOLEAN) : CARDINAL ;
  665. VAR e : SymEntry ;
  666. BEGIN
  667. IF symTop >= MaxSym THEN
  668. Err (ECompOvf) ;
  669. RETURN 0
  670. END ;
  671. CopyWord (name) ;
  672. CopyStr (e.name, wrd) ;
  673. e.tag := tag ;
  674. e.cls := cls ;
  675. e.size := size ;
  676. e.elem := elem ;
  677. e.off := off ;
  678. e.lval := v ;
  679. e.level := lexnest ;
  680. e.local := local ;
  681. e.resvar := 0 ;
  682. e.goPos := 0 ;
  683. e.defnd := FALSE ;
  684. e.fwd := FALSE ;
  685. symtab [symTop] := e ;
  686. INC (symTop) ;
  687. RETURN symTop - 1
  688. END NewSym ;
  689. PROCEDURE Search (nm : ARRAY OF CHAR ; VAR idx : CARDINAL) : BOOLEAN ;
  690. (* find nm among symbols visible at the current lexical level *)
  691. VAR p : CARDINAL ;
  692. BEGIN
  693. CopyWord (nm) ;
  694. p := symTop ;
  695. WHILE p > 0 DO
  696. DEC (p) ;
  697. IF symtab [p].level <= lexnest THEN
  698. IF NameEq (symtab [p].name, wrd) THEN
  699. idx := p ;
  700. RETURN TRUE
  701. END
  702. END
  703. END ;
  704. RETURN FALSE
  705. END Search ;
  706. PROCEDURE DupTest (nm : ARRAY OF CHAR) ;
  707. VAR i : CARDINAL ;
  708. BEGIN
  709. IF Search (nm, i) THEN
  710. Err (EUnknown)
  711. END
  712. END DupTest ;
  713. (* ---------------------------------------------------------------- *)
  714. (* lexer *)
  715. (* ---------------------------------------------------------------- *)
  716. PROCEDURE InitKeys () ;
  717. VAR i : CARDINAL ;
  718. BEGIN
  719. FOR i := 0 TO 42 DO
  720. kTk [i] := 0 ;
  721. kName [i] [0] := 0C
  722. END ;
  723. kName [1] := "PROGRAM" ; kTk [1] := TkProgram ;
  724. kName [2] := "BEGIN" ; kTk [2] := TkBegin ;
  725. kName [3] := "END" ; kTk [3] := TkEnd ;
  726. kName [4] := "IF" ; kTk [4] := TkIf ;
  727. kName [5] := "THEN" ; kTk [5] := TkThen ;
  728. kName [6] := "ELSE" ; kTk [6] := TkElse ;
  729. kName [7] := "WHILE" ; kTk [7] := TkWhile ;
  730. kName [8] := "DO" ; kTk [8] := TkDo ;
  731. kName [9] := "REPEAT" ; kTk [9] := TkRepeat ;
  732. kName [10] := "UNTIL" ; kTk [10] := TkUntil ;
  733. kName [11] := "FOR" ; kTk [11] := TkFor ;
  734. kName [12] := "TO" ; kTk [12] := TkTo ;
  735. kName [13] := "DOWNTO" ; kTk [13] := TkDownto ;
  736. kName [14] := "CASE" ; kTk [14] := TkCase ;
  737. kName [15] := "OF" ; kTk [15] := TkOf ;
  738. kName [16] := "GOTO" ; kTk [16] := TkGoto ;
  739. kName [17] := "EXIT" ; kTk [17] := TkExit ;
  740. kName [18] := "WITH" ; kTk [18] := TkWith ;
  741. kName [19] := "VAR" ; kTk [19] := TkVar ;
  742. kName [20] := "CONST" ; kTk [20] := TkConst ;
  743. kName [21] := "TYPE" ; kTk [21] := TkType ;
  744. kName [22] := "LABEL" ; kTk [22] := TkLabel ;
  745. kName [23] := "PROCEDURE" ; kTk [23] := TkProcedure ;
  746. kName [24] := "FUNCTION" ; kTk [24] := TkFunction ;
  747. kName [25] := "NIL" ; kTk [25] := TkNil ;
  748. kName [26] := "AND" ; kTk [26] := TkAnd ;
  749. kName [27] := "OR" ; kTk [27] := TkOr ;
  750. kName [28] := "NOT" ; kTk [28] := TkNot ;
  751. kName [29] := "DIV" ; kTk [29] := TkDiv ;
  752. kName [30] := "MOD" ; kTk [30] := TkMod ;
  753. kName [31] := "IN" ; kTk [31] := TkIn ;
  754. kName [32] := "FILE" ; kTk [32] := TkFile ;
  755. kName [33] := "TEXT" ; kTk [33] := TkText ;
  756. kName [34] := "RECORD" ; kTk [34] := TkRecord ;
  757. kName [35] := "ARRAY" ; kTk [35] := TkArray ;
  758. kName [36] := "SET" ; kTk [36] := TkSet ;
  759. kName [37] := "PACKED" ; kTk [37] := TkPacked ;
  760. kName [38] := "FORWARD" ; kTk [38] := TkForward ;
  761. kName [39] := "EXTERNAL" ; kTk [39] := TkExternal ;
  762. kName [40] := "ABSOLUTE" ; kTk [40] := TkAbsolute ;
  763. kName [41] := "OVERLAY" ; kTk [41] := TkOverlay ;
  764. kName [42] := "STRING" ; kTk [42] := TkString
  765. END InitKeys ;
  766. PROCEDURE IsBlank (ch : CHAR) : BOOLEAN ;
  767. BEGIN
  768. RETURN (ch = ' ') OR (ORD (ch) = 09H) OR (ORD (ch) = 0DH) OR (ORD (ch) = 0AH) OR (ORD (ch) = 0CH)
  769. END IsBlank ;
  770. PROCEDURE Skip () ;
  771. (* blanks, comments { } and (* *), compiler directives {$ } / (*$ *)
  772. letter + sign toggles rng/chk *)
  773. VAR ch : CHAR ;
  774. letter : CHAR ;
  775. BEGIN
  776. WHILE NOT abortFac DO
  777. WHILE IsBlank (CurCh ()) DO
  778. ch := GetCh ()
  779. END ;
  780. IF CurCh () = '{' THEN
  781. ch := GetCh () ;
  782. IF CurCh () = '$' THEN
  783. ch := GetCh () ;
  784. letter := GetCh () ;
  785. ch := GetCh () ;
  786. IF ch = '+' THEN
  787. IF letter = 'R' THEN dirs.rng := TRUE END ;
  788. IF letter = 'I' THEN dirs.chk := TRUE END
  789. ELSIF ch = '-' THEN
  790. IF letter = 'R' THEN dirs.rng := FALSE END ;
  791. IF letter = 'I' THEN dirs.chk := FALSE END
  792. END
  793. END ;
  794. WHILE (CurCh () # '}') AND (CurCh () # 0C) DO
  795. ch := GetCh ()
  796. END ;
  797. IF CurCh () = '}' THEN
  798. ch := GetCh ()
  799. END
  800. ELSIF (CurCh () = '(') AND (PeekAhead (1) = '*') THEN
  801. ch := GetCh () ;
  802. ch := GetCh () ;
  803. IF CurCh () = '$' THEN
  804. ch := GetCh () ;
  805. letter := GetCh () ;
  806. ch := GetCh () ;
  807. IF ch = '+' THEN
  808. IF letter = 'R' THEN dirs.rng := TRUE END
  809. ELSIF ch = '-' THEN
  810. IF letter = 'R' THEN dirs.rng := FALSE END
  811. END
  812. END ;
  813. LOOP
  814. IF (CurCh () = '*') AND (PeekAhead (1) = ')') THEN
  815. ch := GetCh () ;
  816. ch := GetCh () ;
  817. EXIT
  818. END ;
  819. IF CurCh () = 0C THEN
  820. EXIT
  821. END ;
  822. ch := GetCh ()
  823. END
  824. ELSE
  825. RETURN
  826. END
  827. END
  828. END Skip ;
  829. PROCEDURE GetWord () ;
  830. (* read identifier into wrd (uppercased); next char must be alpha *)
  831. VAR i : CARDINAL ;
  832. ch : CHAR ;
  833. BEGIN
  834. i := 0 ;
  835. ch := GetCh () ;
  836. LOOP
  837. IF i > MaxName THEN
  838. wrd [MaxName] := 0C ;
  839. RETURN
  840. END ;
  841. wrd [i] := Upper (ch) ;
  842. INC (i) ;
  843. ch := CurCh () ;
  844. IF NOT AlphaNum (ch) THEN
  845. wrd [i] := 0C ;
  846. RETURN
  847. END ;
  848. ch := GetCh ()
  849. END
  850. END GetWord ;
  851. PROCEDURE WddTok () : CARDINAL ;
  852. (* map wrd -> keyword token *)
  853. VAR i : CARDINAL ;
  854. BEGIN
  855. i := 1 ;
  856. WHILE i <= 42 DO
  857. IF kName [i] [0] # 0C THEN
  858. IF NameEq (wrd, kName [i]) THEN
  859. RETURN kTk [i]
  860. END
  861. END ;
  862. INC (i)
  863. END ;
  864. RETURN TkNone
  865. END WddTok ;
  866. PROCEDURE KwAhead (word : ARRAY OF CHAR) : BOOLEAN ;
  867. (* does the next token (past blanks/comments) equal the keyword 'word',
  868. without consuming it? srcPos is saved and restored. *)
  869. VAR save : CARDINAL ;
  870. k : BOOLEAN ;
  871. BEGIN
  872. save := srcPos ;
  873. Skip () ;
  874. k := FALSE ;
  875. IF Alpha (CurCh ()) THEN
  876. GetWord () ;
  877. k := NameEq (wrd, word)
  878. END ;
  879. srcPos := save ;
  880. RETURN k
  881. END KwAhead ;
  882. PROCEDURE PeekKw (VAR tok : CARDINAL) ;
  883. (* peek at the next keyword token without consuming it *)
  884. VAR i : CARDINAL ;
  885. BEGIN
  886. tok := TkNone ;
  887. i := 1 ;
  888. WHILE i <= 42 DO
  889. IF kName [i] [0] # 0C THEN
  890. IF KwAhead (kName [i]) THEN
  891. tok := kTk [i] ;
  892. RETURN
  893. END
  894. END ;
  895. INC (i)
  896. END
  897. END PeekKw ;
  898. PROCEDURE MatchKey (VAR tok : CARDINAL) : BOOLEAN ;
  899. (* skip; if next symbol is a word, read it into wrd and set its token.
  900. Returns TRUE when a word was read (tok = TkNone for plain ids). *)
  901. BEGIN
  902. tok := TkNone ;
  903. Skip () ;
  904. IF NOT Alpha (CurCh ()) THEN
  905. RETURN FALSE
  906. END ;
  907. GetWord () ;
  908. tok := WddTok () ;
  909. RETURN TRUE
  910. END MatchKey ;
  911. PROCEDURE MatchDelim (ch : CHAR) : BOOLEAN ;
  912. BEGIN
  913. Skip () ;
  914. IF CurCh () = ch THEN
  915. DropCh (GetCh ()) ;
  916. RETURN TRUE
  917. END ;
  918. RETURN FALSE
  919. END MatchDelim ;
  920. PROCEDURE MatchAssign () : BOOLEAN ;
  921. BEGIN
  922. Skip () ;
  923. IF (CurCh () = ':') AND (PeekAhead (1) = '=') THEN
  924. DropCh (GetCh ()) ;
  925. DropCh (GetCh ()) ;
  926. RETURN TRUE
  927. END ;
  928. RETURN FALSE
  929. END MatchAssign ;
  930. PROCEDURE MatchRange () : BOOLEAN ;
  931. BEGIN
  932. Skip () ;
  933. IF (CurCh () = '.') AND (PeekAhead (1) = '.') THEN
  934. DropCh (GetCh ()) ;
  935. DropCh (GetCh ()) ;
  936. RETURN TRUE
  937. END ;
  938. RETURN FALSE
  939. END MatchRange ;
  940. PROCEDURE ExpectDelim (ch : CHAR ; n : CARDINAL) ;
  941. BEGIN
  942. Skip () ;
  943. IF CurCh () = ch THEN
  944. DropCh (GetCh ())
  945. ELSE
  946. Err (n)
  947. END
  948. END ExpectDelim ;
  949. PROCEDURE HexVal (ch : CHAR) : CARDINAL ;
  950. BEGIN
  951. IF (ch >= '0') AND (ch <= '9') THEN
  952. RETURN ORD (ch) - ORD ('0')
  953. ELSIF (ch >= 'A') AND (ch <= 'F') THEN
  954. RETURN ORD (ch) - ORD ('A') + 10
  955. END ;
  956. RETURN ORD (ch) - ORD ('a') + 10
  957. END HexVal ;
  958. PROCEDURE RdIntConst (VAR v : LONGINT) ;
  959. (* bare integer constant; current char is digit or '$' *)
  960. VAR acc : LONGINT ;
  961. BEGIN
  962. acc := 0 ;
  963. IF CurCh () = '$' THEN
  964. DropCh (GetCh ()) ;
  965. WHILE IsHexCh (CurCh ()) DO
  966. acc := acc * 16 + VAL (LONGINT, HexVal (CurCh ())) ;
  967. DropCh (GetCh ())
  968. END
  969. ELSE
  970. WHILE Digit (CurCh ()) DO
  971. acc := acc * 10 + VAL (LONGINT, ORD (CurCh ()) - ORD ('0')) ;
  972. DropCh (GetCh ())
  973. END
  974. END ;
  975. v := acc
  976. END RdIntConst ;
  977. PROCEDURE RdConst (VAR v : LONGINT ; VAR cls : CARDINAL ;
  978. VAR isStr : BOOLEAN) ;
  979. (* scalar or string constant. String values (isStr) can only be
  980. rejected with ENoLib by the caller. *)
  981. CONST q = AposC ;
  982. BEGIN
  983. isStr := FALSE ;
  984. cls := TScalar ;
  985. v := 0 ;
  986. Skip () ;
  987. IF CurCh () = '$' THEN
  988. RdIntConst (v) ;
  989. cls := TScalar
  990. ELSIF Digit (CurCh ()) THEN
  991. RdIntConst (v) ;
  992. IF (CurCh () = '.') AND (Digit (PeekAhead (1))) THEN
  993. cls := TReal ;
  994. DropCh (GetCh ())
  995. END ;
  996. IF (CurCh () = 'E') OR (CurCh () = 'e') THEN
  997. cls := TReal ;
  998. DropCh (GetCh ())
  999. END ;
  1000. IF cls = TReal THEN
  1001. WHILE AlphaNum (CurCh ()) OR (CurCh () = '.') OR (CurCh () = '-')
  1002. OR (CurCh () = '+') DO
  1003. DropCh (GetCh ())
  1004. END
  1005. END
  1006. ELSIF ORD (CurCh ()) = q THEN
  1007. DropCh (GetCh ()) ;
  1008. IF ORD (CurCh ()) = q THEN
  1009. DropCh (GetCh ()) ;
  1010. v := VAL (LONGINT, q) ;
  1011. cls := TScalar
  1012. ELSIF (CurCh () = 0C) OR ((ORD (CurCh ()) = 0DH)) OR ((ORD (CurCh ()) = 0AH)) THEN
  1013. Err (EUnknown)
  1014. ELSE
  1015. v := VAL (LONGINT, ORD (GetCh ())) ;
  1016. cls := TScalar ;
  1017. IF ORD (CurCh ()) = q THEN
  1018. DropCh (GetCh ())
  1019. ELSE
  1020. isStr := TRUE ;
  1021. cls := TString ;
  1022. WHILE (ORD (CurCh ()) # q) AND (CurCh () # 0C) DO
  1023. IF ORD (PeekAhead (1)) = q THEN
  1024. DropCh (GetCh ()) ; DropCh (GetCh ())
  1025. ELSE
  1026. DropCh (GetCh ())
  1027. END
  1028. END ;
  1029. IF ORD (CurCh ()) = q THEN
  1030. DropCh (GetCh ())
  1031. END
  1032. END
  1033. END
  1034. ELSE
  1035. Err (EUnknown)
  1036. END
  1037. END RdConst ;
  1038. (* ---------------------------------------------------------------- *)
  1039. (* forward declarations *)
  1040. (* ---------------------------------------------------------------- *)
  1041. PROCEDURE ParseExpr (VAR r : ERes) ; FORWARD ;
  1042. PROCEDURE ParseAdd (VAR r : ERes) ; FORWARD ;
  1043. PROCEDURE ParseMul (VAR r : ERes) ; FORWARD ;
  1044. PROCEDURE ParseNeg (VAR r : ERes) ; FORWARD ;
  1045. PROCEDURE ParseAtom (VAR r : ERes) ; FORWARD ;
  1046. PROCEDURE ParseType (VAR cls, size, elem : CARDINAL) ; FORWARD ;
  1047. PROCEDURE Statmnt () ; FORWARD ;
  1048. PROCEDURE ParseCall (idx : CARDINAL) ; FORWARD ;
  1049. PROCEDURE ParseCallArgs (idx : CARDINAL) ; FORWARD ;
  1050. PROCEDURE EmCallMost (idx, nk : CARDINAL) ; FORWARD ;
  1051. (* ---------------------------------------------------------------- *)
  1052. (* expressions (TPSRC9) *)
  1053. (* ---------------------------------------------------------------- *)
  1054. PROCEDURE LoadAtom (VAR r : ERes) ;
  1055. (* load value of r into AX (folding constants) *)
  1056. BEGIN
  1057. IF r.kind = 0 THEN
  1058. EmMovAxi (W16 (r.imm)) ;
  1059. r.kind := 2
  1060. ELSIF r.kind = 1 THEN
  1061. IF symtab [r.idx].size > 2 THEN
  1062. Err (ENoLib)
  1063. ELSE
  1064. EmLoadVar (symtab [r.idx].local,
  1065. (symtab [r.idx].off + r.boff) MOD 10000H,
  1066. symtab [r.idx].size) ;
  1067. IF symtab [r.idx].size = 1 THEN
  1068. EmMovAh0 ()
  1069. END ;
  1070. r.kind := 2
  1071. END
  1072. END
  1073. END LoadAtom ;
  1074. PROCEDURE ParseSub (VAR r : ERes) ;
  1075. (* consume '[' constExpr ']' while present, folding the index into the
  1076. base offset (constant indexing only) *)
  1077. VAR t : ERes ;
  1078. BEGIN
  1079. LOOP
  1080. Skip () ;
  1081. IF CurCh () # '[' THEN
  1082. RETURN
  1083. END ;
  1084. DropCh (GetCh ()) ;
  1085. ParseExpr (t) ;
  1086. IF OK () THEN
  1087. IF t.kind # 0 THEN
  1088. Err (ENoLib) ;
  1089. RETURN
  1090. END ;
  1091. IF symtab [r.idx].cls = TArray THEN
  1092. r.boff := W16 (VAL (LONGINT, r.boff)
  1093. + t.imm * VAL (LONGINT, symtab [r.idx].elem))
  1094. ELSE
  1095. Err (ESimpType) ;
  1096. RETURN
  1097. END
  1098. END ;
  1099. ExpectDelim (']', ENoSemi)
  1100. END
  1101. END ParseSub ;
  1102. PROCEDURE ParseVar (VAR r : ERes) ;
  1103. (* name [ '[' constExpr ']' ]* ; a function name maps to its result var *)
  1104. VAR idx : CARDINAL ;
  1105. BEGIN
  1106. IF NOT Search (wrd, idx) THEN
  1107. Err (EUnknown) ;
  1108. RETURN
  1109. END ;
  1110. r.idx := idx ;
  1111. r.kind := 1 ;
  1112. r.boff := 0 ;
  1113. r.cls := symtab [idx].cls ;
  1114. IF symtab [idx].tag = KFunc THEN
  1115. idx := symtab [idx].resvar ;
  1116. r.idx := idx ;
  1117. r.cls := symtab [idx].cls
  1118. ELSIF (symtab [idx].tag # KVar) AND (symtab [idx].tag # KType) THEN
  1119. Err (EUnknown) ;
  1120. RETURN
  1121. END ;
  1122. ParseSub (r)
  1123. END ParseVar ;
  1124. PROCEDURE ConstAdd (a, b : LONGINT) : LONGINT ;
  1125. BEGIN
  1126. RETURN VAL (LONGINT, W16 (a + b))
  1127. END ConstAdd ;
  1128. PROCEDURE ConstSub (a, b : LONGINT) : LONGINT ;
  1129. BEGIN
  1130. RETURN VAL (LONGINT, W16 (a - b))
  1131. END ConstSub ;
  1132. PROCEDURE ConstMul (a, b : LONGINT) : LONGINT ;
  1133. BEGIN
  1134. RETURN VAL (LONGINT, W16 (a * b))
  1135. END ConstMul ;
  1136. PROCEDURE EmMoveAxDx () ;
  1137. BEGIN
  1138. Ebyte (92H)
  1139. END EmMoveAxDx ;
  1140. PROCEDURE BinOpEmit (op : CARDINAL ; left, right : ERes ; VAR res : ERes) ;
  1141. (* binary operation at one precedence level; folds constant operands *)
  1142. VAR f : LONGINT ;
  1143. okc : BOOLEAN ;
  1144. BEGIN
  1145. IF op = TkAnd THEN
  1146. IF (left.kind = 0) AND (right.kind = 0) THEN
  1147. res.kind := 0 ;
  1148. res.imm := BitAnd (left.imm, right.imm) ;
  1149. res.cls := TBool ;
  1150. RETURN
  1151. END ;
  1152. LoadAtom (left) ; EmPushAx () ;
  1153. LoadAtom (right) ; EmPopCx () ;
  1154. EmAndAxCx () ;
  1155. res.kind := 2 ; res.cls := TBool ;
  1156. RETURN
  1157. END ;
  1158. IF op = TkOr THEN
  1159. IF (left.kind = 0) AND (right.kind = 0) THEN
  1160. res.kind := 0 ;
  1161. res.imm := BitOr (left.imm, right.imm) ;
  1162. res.cls := TBool ;
  1163. RETURN
  1164. END ;
  1165. LoadAtom (left) ; EmPushAx () ;
  1166. LoadAtom (right) ; EmPopCx () ;
  1167. EmOrAxCx () ;
  1168. res.kind := 2 ; res.cls := TBool ;
  1169. RETURN
  1170. END ;
  1171. IF (left.kind = 0) AND (right.kind = 0) THEN
  1172. okc := FALSE ;
  1173. CASE op OF
  1174. 1 : f := ConstAdd (left.imm, right.imm) ; okc := TRUE ;
  1175. | 2 : f := ConstSub (left.imm, right.imm) ; okc := TRUE ;
  1176. | 3 : f := ConstMul (left.imm, right.imm) ; okc := TRUE ;
  1177. | TkDiv : okc := (right.imm # 0) AND (right.imm > 0)
  1178. AND (left.imm >= 0) ;
  1179. IF okc THEN f := left.imm DIV right.imm END ;
  1180. | TkMod : okc := (right.imm # 0) AND (right.imm > 0)
  1181. AND (left.imm >= 0) ;
  1182. IF okc THEN f := left.imm MOD right.imm END ;
  1183. ELSE
  1184. okc := FALSE
  1185. END ;
  1186. IF okc THEN
  1187. res.kind := 0 ;
  1188. res.imm := VAL (LONGINT, W16 (f)) ;
  1189. res.cls := left.cls ;
  1190. RETURN
  1191. ELSIF op = TkDiv THEN
  1192. Err (EConstRange) ;
  1193. RETURN
  1194. END
  1195. END ;
  1196. LoadAtom (left) ; EmPushAx () ;
  1197. LoadAtom (right) ; EmPopCx () ;
  1198. EmXchgAxCx () ;
  1199. CASE op OF
  1200. 1 : EmAddAxCx ;
  1201. | 2 : EmSubAxCx ;
  1202. | 3 : EmMulAxCx ;
  1203. | TkDiv : EmIDivAxCx ;
  1204. | TkMod : EmIDivAxCx ; EmMoveAxDx ;
  1205. ELSE
  1206. Err (ETypeErr)
  1207. END ;
  1208. res.kind := 2 ;
  1209. res.cls := left.cls
  1210. END BinOpEmit ;
  1211. PROCEDURE ConstCmp (op : CARDINAL ; a, b : LONGINT ; VAR f : LONGINT)
  1212. : BOOLEAN ;
  1213. VAR a16, b16 : CARDINAL ;
  1214. BEGIN
  1215. a16 := W16 (a) ;
  1216. b16 := W16 (b) ;
  1217. f := 0 ;
  1218. CASE op OF
  1219. 1 : f := VAL (LONGINT, ORD (a16 = b16)) ;
  1220. | 2 : f := VAL (LONGINT, ORD (a16 # b16)) ;
  1221. | 3 : f := VAL (LONGINT, ORD (a16 < b16)) ;
  1222. | 4 : f := VAL (LONGINT, ORD (a16 >= b16)) ;
  1223. | 5 : f := VAL (LONGINT, ORD (a16 > b16)) ;
  1224. | 6 : f := VAL (LONGINT, ORD (a16 <= b16)) ;
  1225. ELSE
  1226. RETURN FALSE
  1227. END ;
  1228. RETURN TRUE
  1229. END ConstCmp ;
  1230. PROCEDURE ParseCmp (VAR r : ERes) ;
  1231. (* "=" | "<>" | "<" | "<=" | ">" | ">=" *)
  1232. VAR op : CARDINAL ;
  1233. left, right : ERes ;
  1234. f : LONGINT ;
  1235. BEGIN
  1236. ParseAdd (r) ;
  1237. LOOP
  1238. op := 0 ;
  1239. Skip () ;
  1240. IF CurCh () = '=' THEN
  1241. op := 1 ; DropCh (GetCh ())
  1242. ELSIF (CurCh () = '<') AND (PeekAhead (1) = '>') THEN
  1243. op := 2 ; DropCh (GetCh ()) ; DropCh (GetCh ())
  1244. ELSIF CurCh () = '<' THEN
  1245. IF PeekAhead (1) = '=' THEN
  1246. op := 6 ; DropCh (GetCh ()) ; DropCh (GetCh ())
  1247. ELSE
  1248. op := 3 ; DropCh (GetCh ())
  1249. END
  1250. ELSIF CurCh () = '>' THEN
  1251. IF PeekAhead (1) = '=' THEN
  1252. op := 5 ; DropCh (GetCh ()) ; DropCh (GetCh ())
  1253. ELSE
  1254. op := 4 ; DropCh (GetCh ())
  1255. END
  1256. END ;
  1257. IF op = 0 THEN
  1258. RETURN
  1259. END ;
  1260. left := r ;
  1261. ParseAdd (right) ;
  1262. IF (left.kind = 0) AND (right.kind = 0) THEN
  1263. IF ConstCmp (op, left.imm, right.imm, f) THEN
  1264. r.kind := 0 ;
  1265. r.imm := f ;
  1266. r.cls := TBool
  1267. ELSE
  1268. r.kind := 0 ;
  1269. r.imm := 0 ;
  1270. r.cls := TBool
  1271. END
  1272. ELSE
  1273. LoadAtom (left) ; EmPushAx () ;
  1274. LoadAtom (right) ; EmPopCx () ;
  1275. EmXchgAxCx () ;
  1276. EmCmpAxCx () ;
  1277. CASE op OF
  1278. 1 : EmSetcc (94H) ;
  1279. | 2 : EmSetcc (95H) ;
  1280. | 3 : EmSetcc (9CH) ;
  1281. | 4 : EmSetcc (9DH) ;
  1282. | 5 : EmSetcc (9FH) ;
  1283. | 6 : EmSetcc (9EH)
  1284. END ;
  1285. r.kind := 2 ;
  1286. r.cls := TBool
  1287. END
  1288. END
  1289. END ParseCmp ;
  1290. PROCEDURE ParseAdd (VAR r : ERes) ;
  1291. VAR op : CARDINAL ;
  1292. left, right : ERes ;
  1293. BEGIN
  1294. ParseMul (r) ;
  1295. LOOP
  1296. op := 0 ;
  1297. Skip () ;
  1298. IF CurCh () = '+' THEN
  1299. op := 1 ; DropCh (GetCh ())
  1300. ELSIF CurCh () = '-' THEN
  1301. op := 2 ; DropCh (GetCh ())
  1302. ELSIF KwAhead ("OR") THEN
  1303. GetWord () ;
  1304. op := TkOr
  1305. ELSE
  1306. RETURN
  1307. END ;
  1308. left := r ;
  1309. ParseMul (right) ;
  1310. BinOpEmit (op, left, right, r)
  1311. END
  1312. END ParseAdd ;
  1313. PROCEDURE ParseMul (VAR r : ERes) ;
  1314. VAR op : CARDINAL ;
  1315. left, right : ERes ;
  1316. BEGIN
  1317. ParseNeg (r) ;
  1318. LOOP
  1319. op := 0 ;
  1320. Skip () ;
  1321. IF CurCh () = '*' THEN
  1322. op := 1 ; DropCh (GetCh ())
  1323. ELSIF CurCh () = '/' THEN
  1324. op := 2 ; DropCh (GetCh ()) ; Err (ENoLib)
  1325. ELSIF KwAhead ("DIV") THEN
  1326. GetWord () ; op := TkDiv
  1327. ELSIF KwAhead ("MOD") THEN
  1328. GetWord () ; op := TkMod
  1329. ELSIF KwAhead ("AND") THEN
  1330. GetWord () ; op := TkAnd
  1331. ELSE
  1332. RETURN
  1333. END ;
  1334. IF op = 2 THEN
  1335. RETURN
  1336. END ;
  1337. left := r ;
  1338. ParseNeg (right) ;
  1339. BinOpEmit (op, left, right, r)
  1340. END
  1341. END ParseMul ;
  1342. PROCEDURE ParseNeg (VAR r : ERes) ;
  1343. BEGIN
  1344. Skip () ;
  1345. IF CurCh () = '+' THEN
  1346. DropCh (GetCh ()) ;
  1347. ParseNeg (r) ;
  1348. RETURN
  1349. ELSIF CurCh () = '-' THEN
  1350. DropCh (GetCh ()) ;
  1351. ParseNeg (r) ;
  1352. IF r.kind = 0 THEN
  1353. r.imm := VAL (LONGINT, W16 (0 - r.imm))
  1354. ELSE
  1355. LoadAtom (r) ;
  1356. EmNegAx () ;
  1357. r.kind := 2
  1358. END ;
  1359. RETURN
  1360. ELSIF KwAhead ("NOT") THEN
  1361. GetWord () ;
  1362. ParseNeg (r) ;
  1363. IF r.kind = 0 THEN
  1364. r.imm := BitNot (r.imm)
  1365. ELSE
  1366. LoadAtom (r) ;
  1367. EmNotAx () ;
  1368. r.kind := 2
  1369. END ;
  1370. RETURN
  1371. END ;
  1372. ParseAtom (r)
  1373. END ParseNeg ;
  1374. PROCEDURE ParseAtom (VAR r : ERes) ;
  1375. (* const | variable | func(params) | '(' expr ')' *)
  1376. VAR idx : CARDINAL ;
  1377. strf : BOOLEAN ;
  1378. quoted : BOOLEAN ;
  1379. BEGIN
  1380. r.chr := FALSE ; (* default: not a quoted char literal *)
  1381. Skip () ;
  1382. IF CurCh () = '(' THEN
  1383. DropCh (GetCh ()) ;
  1384. ParseExpr (r) ;
  1385. ExpectDelim (')', ENoSemi) ;
  1386. RETURN
  1387. END ;
  1388. IF (CurCh () = '$') OR (Digit (CurCh ())) OR (ORD (CurCh ()) = AposC) THEN
  1389. (* remember that this was a quoted literal BEFORE RdConst consumes it:
  1390. RdConst reports a 1-character literal as TScalar (its char code),
  1391. which is right for "c := 'a'" but would make writeln('a') print 97.
  1392. Mark it so the writer picks the char entry, not the integer one. *)
  1393. quoted := (ORD (CurCh ()) = AposC) ;
  1394. RdConst (r.imm, r.cls, strf) ;
  1395. r.chr := quoted AND (r.cls = TScalar) AND NOT strf ;
  1396. IF r.cls = TReal THEN
  1397. Err (ENoLib) ;
  1398. r.kind := 2 ;
  1399. RETURN
  1400. END ;
  1401. IF strf THEN
  1402. Err (ENoLib) ;
  1403. r.kind := 2 ;
  1404. RETURN
  1405. END ;
  1406. r.kind := 0 ;
  1407. RETURN
  1408. END ;
  1409. IF NOT Alpha (CurCh ()) THEN
  1410. Err (EUnknown) ;
  1411. RETURN
  1412. END ;
  1413. GetWord () ;
  1414. IF NOT Search (wrd, idx) THEN
  1415. Err (EUnknown) ;
  1416. RETURN
  1417. END ;
  1418. IF symtab [idx].tag = KConst THEN
  1419. r.kind := 0 ;
  1420. r.imm := symtab [idx].lval ;
  1421. r.cls := symtab [idx].cls ;
  1422. RETURN
  1423. ELSIF symtab [idx].tag = KFunc THEN
  1424. ParseCall (idx) ;
  1425. r.kind := 2 ;
  1426. r.cls := symtab [idx].cls ;
  1427. RETURN
  1428. ELSIF (symtab [idx].tag = KVar) OR (symtab [idx].tag = KType) THEN
  1429. ParseVar (r) ;
  1430. r.boff := 0 ;
  1431. RETURN
  1432. ELSE
  1433. Err (EUnknown)
  1434. END
  1435. END ParseAtom ;
  1436. PROCEDURE AddPend (kind, who, place : CARDINAL) ;
  1437. BEGIN
  1438. IF nPend < MaxPend THEN
  1439. pend [nPend].kind := kind ;
  1440. pend [nPend].who := who ;
  1441. pend [nPend].place := place ;
  1442. INC (nPend)
  1443. ELSE
  1444. Err (ECompOvf)
  1445. END
  1446. END AddPend ;
  1447. PROCEDURE EmCallMost (idx, nk : CARDINAL) ;
  1448. (* emit the call to sym 'idx' and clean up nk value arguments *)
  1449. VAR p : CARDINAL ;
  1450. BEGIN
  1451. IF symtab [idx].defnd THEN
  1452. DropC (EmCall (symtab [idx].goPos))
  1453. ELSE
  1454. p := EmCall (0) ;
  1455. AddPend (1, idx, p)
  1456. END ;
  1457. IF nk > 0 THEN
  1458. EmAddSp (2 * nk)
  1459. END
  1460. END EmCallMost ;
  1461. PROCEDURE ParseCallArgs (idx : CARDINAL) ;
  1462. (* '(' already consumed: read args ')' then call. Arguments are pushed
  1463. right-to-left so the first-declared parameter lands at BP+4. *)
  1464. VAR args : ARRAY [0..15] OF ERes ;
  1465. nArgs, i : CARDINAL ;
  1466. BEGIN
  1467. nArgs := 0 ;
  1468. IF CurCh () = ')' THEN
  1469. DropCh (GetCh ())
  1470. ELSE
  1471. LOOP
  1472. IF nArgs >= 16 THEN
  1473. Err (ECompOvf) ;
  1474. EXIT
  1475. END ;
  1476. ParseExpr (args [nArgs]) ;
  1477. INC (nArgs) ;
  1478. IF NOT MatchDelim (',') THEN
  1479. EXIT
  1480. END
  1481. END ;
  1482. ExpectDelim (')', ENoSemi)
  1483. END ;
  1484. i := nArgs ;
  1485. WHILE i > 0 DO
  1486. DEC (i) ;
  1487. LoadAtom (args [i]) ;
  1488. EmPushAx ()
  1489. END ;
  1490. EmCallMost (idx, nArgs)
  1491. END ParseCallArgs ;
  1492. PROCEDURE ParseCall (idx : CARDINAL) ;
  1493. (* procedure/function call; '(' optional *)
  1494. VAR args : ARRAY [0..15] OF ERes ;
  1495. nArgs, i : CARDINAL ;
  1496. BEGIN
  1497. nArgs := 0 ;
  1498. IF MatchDelim ('(') THEN
  1499. IF CurCh () # ')' THEN
  1500. LOOP
  1501. IF nArgs >= 16 THEN
  1502. Err (ECompOvf) ;
  1503. EXIT
  1504. END ;
  1505. ParseExpr (args [nArgs]) ;
  1506. INC (nArgs) ;
  1507. IF NOT MatchDelim (',') THEN
  1508. EXIT
  1509. END
  1510. END ;
  1511. ExpectDelim (')', ENoSemi)
  1512. ELSE
  1513. DropCh (GetCh ())
  1514. END
  1515. END ;
  1516. i := nArgs ;
  1517. WHILE i > 0 DO
  1518. DEC (i) ;
  1519. LoadAtom (args [i]) ;
  1520. EmPushAx ()
  1521. END ;
  1522. EmCallMost (idx, nArgs)
  1523. END ParseCall ;
  1524. PROCEDURE ParseExpr (VAR r : ERes) ;
  1525. BEGIN
  1526. ParseCmp (r)
  1527. END ParseExpr ;
  1528. (* ---------------------------------------------------------------- *)
  1529. (* statements (TPSRC8) *)
  1530. (* ---------------------------------------------------------------- *)
  1531. PROCEDURE ParseLabelStmt () ;
  1532. (* numeric label definition 'n :' *)
  1533. VAR n : CARDINAL ;
  1534. nm : ARRAY [0..9] OF CHAR ;
  1535. idx : CARDINAL ;
  1536. i : CARDINAL ;
  1537. BEGIN
  1538. n := 0 ;
  1539. WHILE Digit (CurCh ()) DO
  1540. n := n * 10 + (ORD (CurCh ()) - ORD ('0')) ;
  1541. DropCh (GetCh ())
  1542. END ;
  1543. ExpectDelim (':', ENoSemi) ;
  1544. NumToName (n, nm) ;
  1545. IF Search (nm, idx) THEN
  1546. IF symtab [idx].tag = KLabel THEN
  1547. symtab [idx].defnd := TRUE ;
  1548. symtab [idx].goPos := pc ;
  1549. i := 0 ;
  1550. WHILE i < nPend DO
  1551. IF (pend [i].kind = 0) AND (pend [i].who = idx) THEN
  1552. SetPatTgt (pend [i].place, pc) ;
  1553. pend [i].kind := 99
  1554. END ;
  1555. INC (i)
  1556. END
  1557. ELSE
  1558. Err (EUnknown)
  1559. END
  1560. ELSE
  1561. idx := NewSym (nm, KLabel, TScalar, 0, 0, 0, 0, FALSE) ;
  1562. symtab [idx].defnd := TRUE ;
  1563. symtab [idx].goPos := pc
  1564. END
  1565. END ParseLabelStmt ;
  1566. PROCEDURE Assignment (r : ERes) ;
  1567. (* ':=' already consumed by the caller; store expression into r *)
  1568. VAR src : ERes ;
  1569. BEGIN
  1570. IF r.kind # 1 THEN
  1571. Err (EUnknown) ;
  1572. RETURN
  1573. END ;
  1574. IF symtab [r.idx].size > 2 THEN
  1575. Err (ENoLib) ;
  1576. RETURN
  1577. END ;
  1578. ParseExpr (src) ;
  1579. LoadAtom (src) ;
  1580. EmStoreVar (symtab [r.idx].local,
  1581. (symtab [r.idx].off + r.boff) MOD 10000H,
  1582. symtab [r.idx].size)
  1583. END Assignment ;
  1584. PROCEDURE Compound () ;
  1585. (* BEGIN statement ';' ... END; END is consumed here *)
  1586. VAR tok : CARDINAL ;
  1587. BEGIN
  1588. LOOP
  1589. PeekKw (tok) ;
  1590. IF tok = TkEnd THEN
  1591. DropB (MatchKey (tok)) ;
  1592. RETURN
  1593. END ;
  1594. Statmnt () ;
  1595. IF NOT OK () THEN
  1596. RETURN
  1597. END ;
  1598. IF NOT MatchDelim (';') THEN
  1599. PeekKw (tok) ;
  1600. IF tok = TkEnd THEN
  1601. DropB (MatchKey (tok)) ;
  1602. RETURN
  1603. END ;
  1604. Err (ENoSemi) ;
  1605. RETURN
  1606. END
  1607. END
  1608. END Compound ;
  1609. PROCEDURE IoCall (idx : CARDINAL) ;
  1610. (* WRITE / WRITELN / READ / READLN / HALT.
  1611. TP3 (TPSRC8 pwriteln, pwrloop, prdtyped) does not pass a descriptor to
  1612. the runtime: it looks at each argument's class and emits a *different*
  1613. call per type, so the formatting is fixed at compile time. Mirrored
  1614. here - one call per argument, then a final call for the line break.
  1615. WRITE/WRITELN push the value; READ/READLN push the address, so the
  1616. runtime can store. As everywhere else in this compiler the caller
  1617. cleans the argument off the stack. *)
  1618. VAR args : ARRAY [0..15] OF ERes ;
  1619. nArgs, i, ent, which, acls : CARDINAL ;
  1620. reading : BOOLEAN ;
  1621. dummy : ERes ;
  1622. BEGIN
  1623. which := symtab [idx].cls ; (* BI_* *)
  1624. IF which = BI_Halt THEN
  1625. IF MatchDelim ('(') THEN (* halt(0) - code ignored *)
  1626. ParseExpr (dummy) ;
  1627. ExpectDelim (')', ENoSemi)
  1628. END ;
  1629. DropC (EmCall (TU_Halt)) ;
  1630. RETURN
  1631. END ;
  1632. reading := (which = BI_Read) OR (which = BI_ReadLn) ;
  1633. nArgs := 0 ;
  1634. IF MatchDelim ('(') THEN
  1635. IF CurCh () # ')' THEN
  1636. LOOP
  1637. IF nArgs >= 16 THEN
  1638. Err (ECompOvf) ;
  1639. EXIT
  1640. END ;
  1641. ParseExpr (args [nArgs]) ;
  1642. INC (nArgs) ;
  1643. IF NOT MatchDelim (',') THEN
  1644. EXIT
  1645. END
  1646. END ;
  1647. IF NOT MatchDelim (')') THEN
  1648. Err (ENoSemi) ;
  1649. RETURN
  1650. END
  1651. ELSE
  1652. DropCh (GetCh ())
  1653. END
  1654. END ;
  1655. IF reading AND (nArgs = 0) THEN
  1656. (* readln with no variable: just skip to the next line *)
  1657. DropC (EmCall (TU_RdLn)) ;
  1658. RETURN
  1659. END ;
  1660. (* NB: guard the loop bound - with nArgs = 0, "nArgs - 1" would wrap round
  1661. to 65535 in CARDINAL and spin 65536 times. *)
  1662. IF nArgs > 0 THEN
  1663. FOR i := 0 TO nArgs - 1 DO
  1664. IF reading THEN
  1665. IF args [i].kind # 1 THEN
  1666. Err (ETypeErr) ; (* READ needs a variable *)
  1667. RETURN
  1668. END ;
  1669. acls := symtab [args [i].idx].cls ;
  1670. IF acls = TString THEN
  1671. Err (ENoLib) ; (* string runtime pending *)
  1672. RETURN
  1673. END ;
  1674. EmPushVarAddr (symtab [args [i].idx].local, symtab [args [i].idx].off) ;
  1675. IF acls = TReal THEN
  1676. ent := TU_RdInt (* real reads: not yet *)
  1677. ELSIF acls = TBool THEN
  1678. ent := TU_RdBool
  1679. ELSIF acls = TScalar THEN
  1680. ent := TU_RdInt
  1681. ELSE
  1682. ent := TU_RdChar
  1683. END
  1684. ELSE
  1685. acls := args [i].cls ;
  1686. IF acls = TString THEN
  1687. Err (ENoLib) ; (* string runtime pending *)
  1688. RETURN
  1689. END ;
  1690. LoadAtom (args [i]) ;
  1691. EmPushAx () ;
  1692. IF args [i].chr THEN
  1693. ent := TU_WrChar (* 'a' - one char, not 97 *)
  1694. ELSIF acls = TReal THEN
  1695. ent := TU_WrReal
  1696. ELSIF acls = TBool THEN
  1697. ent := TU_WrBool
  1698. ELSIF acls = TScalar THEN
  1699. ent := TU_WrInt
  1700. ELSE
  1701. ent := TU_WrChar
  1702. END
  1703. END ;
  1704. DropC (EmCall (ent)) ;
  1705. EmAddSp (2) (* one 16-bit argument *)
  1706. END
  1707. END ;
  1708. IF which = BI_WriteLn THEN
  1709. DropC (EmCall (TU_WrLn))
  1710. ELSIF which = BI_ReadLn THEN
  1711. DropC (EmCall (TU_RdLn))
  1712. END
  1713. END IoCall ;
  1714. PROCEDURE Statmnt () ;
  1715. VAR tok : CARDINAL ;
  1716. idx, i2 : CARDINAL ;
  1717. t, src : ERes ;
  1718. L1, zj, zj2, exj : CARDINAL ;
  1719. lo, hi, v : LONGINT ;
  1720. clso : CARDINAL ;
  1721. i : CARDINAL ;
  1722. nm : ARRAY [0..MaxName] OF CHAR ;
  1723. strf : BOOLEAN ;
  1724. dow : BOOLEAN ;
  1725. BEGIN
  1726. Skip () ;
  1727. IF Digit (CurCh ()) THEN
  1728. ParseLabelStmt () ; (* consumed 'n' ':' *)
  1729. Statmnt () ; (* 'n : statement' - the statement follows
  1730. the label directly, with no ';' between *)
  1731. RETURN
  1732. END ;
  1733. IF NOT Alpha (CurCh ()) THEN
  1734. ExpectDelim (';', ENoSemi) ;
  1735. RETURN
  1736. END ;
  1737. DropB (MatchKey (tok)) ;
  1738. IF tok = TkBegin THEN
  1739. Compound ()
  1740. ELSIF tok = TkIf THEN
  1741. ParseExpr (t) ;
  1742. LoadAtom (t) ;
  1743. EmCmpAxi (0) ;
  1744. zj := EmJcc (84H, 0) ; (* JZ -> else/end *)
  1745. IF NOT (MatchKey (tok) AND (tok = TkThen)) THEN
  1746. Err (ENoSemi)
  1747. END ;
  1748. Statmnt () ;
  1749. IF MatchKey (tok) AND (tok = TkElse) THEN
  1750. exj := EmJmpNear (0) ;
  1751. SetPatTgt (zj, pc) ;
  1752. Statmnt () ;
  1753. SetPatTgt (exj, pc)
  1754. ELSE
  1755. SetPatTgt (zj, pc)
  1756. END
  1757. ELSIF tok = TkWhile THEN
  1758. L1 := pc ;
  1759. ParseExpr (t) ;
  1760. LoadAtom (t) ;
  1761. EmCmpAxi (0) ;
  1762. zj := EmJcc (84H, 0) ; (* JZ -> end *)
  1763. IF NOT (MatchKey (tok) AND (tok = TkDo)) THEN
  1764. Err (ENoSemi)
  1765. END ;
  1766. brkSave [brkN] := exitCnt ;
  1767. loopTy [brkN] := 1 ;
  1768. INC (brkN) ;
  1769. Statmnt () ;
  1770. DEC (brkN) ;
  1771. i := brkSave [brkN] ;
  1772. WHILE i < exitCnt DO
  1773. SetPatTgt (exitPatch [i], pc) ;
  1774. INC (i)
  1775. END ;
  1776. exitCnt := brkSave [brkN] ;
  1777. DropC (EmJmpNear (L1)) ;
  1778. SetPatTgt (zj, pc)
  1779. ELSIF tok = TkRepeat THEN
  1780. L1 := pc ;
  1781. brkSave [brkN] := exitCnt ;
  1782. loopTy [brkN] := 1 ;
  1783. INC (brkN) ;
  1784. Statmnt () ;
  1785. IF NOT (MatchKey (tok) AND (tok = TkUntil)) THEN
  1786. Err (ENoSemi)
  1787. END ;
  1788. ParseExpr (t) ;
  1789. LoadAtom (t) ;
  1790. EmCmpAxi (0) ;
  1791. zj := EmJcc (85H, L1) ; (* JNZ -> body again *)
  1792. DEC (brkN) ;
  1793. i := brkSave [brkN] ;
  1794. WHILE i < exitCnt DO
  1795. SetPatTgt (exitPatch [i], pc) ;
  1796. INC (i)
  1797. END ;
  1798. exitCnt := brkSave [brkN]
  1799. ELSIF tok = TkFor THEN
  1800. (* control variable *)
  1801. Skip () ; (* after the FOR keyword: skip blanks *)
  1802. IF NOT Alpha (CurCh ()) THEN
  1803. Err (EUnknown) ;
  1804. RETURN
  1805. END ;
  1806. GetWord () ;
  1807. IF NOT Search (wrd, idx) THEN
  1808. Err (EUnknown) ;
  1809. RETURN
  1810. END ;
  1811. IF symtab [idx].size > 2 THEN
  1812. Err (ENoLib) ;
  1813. RETURN
  1814. END ;
  1815. IF NOT MatchAssign () THEN
  1816. Err (ENoSemi)
  1817. END ;
  1818. ParseExpr (src) ;
  1819. LoadAtom (src) ;
  1820. EmStoreVar (symtab [idx].local, symtab [idx].off,
  1821. symtab [idx].size) ;
  1822. IF NOT MatchKey (tok) THEN
  1823. Err (ESimpType) ;
  1824. RETURN
  1825. END ;
  1826. IF (tok = TkTo) OR (tok = TkDownto) THEN
  1827. dow := (tok = TkDownto)
  1828. ELSE
  1829. Err (ESimpType) ;
  1830. RETURN
  1831. END ;
  1832. ParseExpr (t) ;
  1833. LoadAtom (t) ;
  1834. EmPushAx () ; (* loop bound on the stack *)
  1835. IF NOT (MatchKey (tok) AND (tok = TkDo)) THEN
  1836. Err (ENoSemi)
  1837. END ;
  1838. brkSave [brkN] := exitCnt ;
  1839. loopTy [brkN] := 2 ;
  1840. INC (brkN) ;
  1841. L1 := pc ; (* Ltest *)
  1842. Statmnt () ;
  1843. DEC (brkN) ;
  1844. i := brkSave [brkN] ;
  1845. WHILE i < exitCnt DO
  1846. SetPatTgt (exitPatch [i], pc) ;
  1847. INC (i)
  1848. END ;
  1849. exitCnt := brkSave [brkN] ;
  1850. (* test then step: ax = var ; cx = bound (from [sp]) *)
  1851. EmMovCxSp () ;
  1852. EmLoadVar (symtab [idx].local, symtab [idx].off,
  1853. symtab [idx].size) ;
  1854. EmCmpAxCx () ;
  1855. IF dow THEN
  1856. zj := EmJcc (8CH, 0) (* JL -> done *)
  1857. ELSE
  1858. zj := EmJcc (8FH, 0) (* JG -> done *)
  1859. END ;
  1860. EmLoadVar (symtab [idx].local, symtab [idx].off,
  1861. symtab [idx].size) ;
  1862. IF dow THEN
  1863. EmDecAx ()
  1864. ELSE
  1865. EmIncAx ()
  1866. END ;
  1867. EmStoreVar (symtab [idx].local, symtab [idx].off,
  1868. symtab [idx].size) ;
  1869. DropC (EmJmpNear (L1)) ;
  1870. SetPatTgt (zj, pc) ; (* done: drop bound, continue *)
  1871. EmAddSp (2)
  1872. ELSIF tok = TkCase THEN
  1873. ParseExpr (t) ;
  1874. LoadAtom (t) ;
  1875. EmPushAx () ; (* selector on the stack *)
  1876. IF NOT (MatchKey (tok) AND (tok = TkOf)) THEN
  1877. Err (ENoSemi)
  1878. END ;
  1879. caseN := 0 ;
  1880. LOOP
  1881. Skip () ;
  1882. IF MatchDelim (';') THEN
  1883. Skip ()
  1884. END ;
  1885. PeekKw (tok) ;
  1886. IF (tok = TkEnd) OR (tok = TkElse) THEN
  1887. EXIT
  1888. END ;
  1889. (* case label : constant identifier or literal *)
  1890. IF Alpha (CurCh ()) THEN
  1891. GetWord () ;
  1892. IF Search (wrd, i2) AND (symtab [i2].tag = KConst) THEN
  1893. lo := symtab [i2].lval
  1894. ELSE
  1895. Err (EUnknown) ;
  1896. EXIT
  1897. END
  1898. ELSE
  1899. RdConst (lo, clso, strf)
  1900. END ;
  1901. IF MatchRange () THEN
  1902. RdConst (hi, clso, strf)
  1903. ELSE
  1904. hi := lo
  1905. END ;
  1906. ExpectDelim (':', ENoSemi) ;
  1907. EmMovAxSp () ;
  1908. EmCmpAxi (W16 (lo)) ;
  1909. zj := EmJcc (85H, 0) ; (* JNZ -> next *)
  1910. IF hi # lo THEN
  1911. EmCmpAxi (W16 (hi)) ;
  1912. zj2 := EmJcc (85H, 0)
  1913. ELSE
  1914. zj2 := 0
  1915. END ;
  1916. Statmnt () ;
  1917. IF caseN >= 64 THEN
  1918. Err (ECompOvf) ;
  1919. EXIT
  1920. END ;
  1921. caseJmp [caseN] := EmJmpNear (0) ;
  1922. INC (caseN) ;
  1923. SetPatTgt (zj, pc) ;
  1924. IF zj2 # 0 THEN
  1925. SetPatTgt (zj2, pc)
  1926. END
  1927. END ;
  1928. IF tok = TkElse THEN
  1929. DropB (MatchKey (tok)) ;
  1930. Statmnt () ;
  1931. IF NOT (MatchKey (tok) AND (tok = TkEnd)) THEN
  1932. Err (ENoSemi)
  1933. END
  1934. ELSE
  1935. DropB (MatchKey (tok))
  1936. END ;
  1937. EmAddSp (2) ;
  1938. FOR i := 0 TO caseN - 1 DO
  1939. SetPatTgt (caseJmp [i], pc)
  1940. END
  1941. ELSIF tok = TkGoto THEN
  1942. v := 0 ;
  1943. Skip () ; (* after the GOTO keyword: skip blanks *)
  1944. IF Digit (CurCh ()) THEN
  1945. RdIntConst (v) ;
  1946. NumToName (W16 (v), nm) ;
  1947. IF Search (nm, idx) THEN
  1948. IF symtab [idx].tag = KLabel THEN
  1949. IF symtab [idx].defnd THEN
  1950. DropC (EmJmpNear (symtab [idx].goPos))
  1951. ELSE
  1952. zj := EmJmpNear (0) ;
  1953. AddPend (0, idx, zj)
  1954. END
  1955. ELSE
  1956. Err (EUnknown)
  1957. END
  1958. ELSE
  1959. idx := NewSym (nm, KLabel, TScalar, 0, 0, 0, 0, FALSE) ;
  1960. zj := EmJmpNear (0) ;
  1961. AddPend (0, idx, zj)
  1962. END
  1963. ELSE
  1964. Err (EUnknown)
  1965. END
  1966. ELSIF tok = TkExit THEN
  1967. IF brkN = 0 THEN
  1968. Err (EUnknown)
  1969. ELSE
  1970. IF loopTy [brkN - 1] = 2 THEN
  1971. EmAddSp (2) (* drop FOR bound *)
  1972. END ;
  1973. zj := EmJmpNear (0) ;
  1974. IF exitCnt < 64 THEN
  1975. exitPatch [exitCnt] := zj ;
  1976. INC (exitCnt)
  1977. END
  1978. END
  1979. ELSIF tok = TkWith THEN
  1980. Err (ENoLib)
  1981. ELSE
  1982. (* identifier statement: assignment or call *)
  1983. IF NOT Search (wrd, idx) THEN
  1984. Err (EUnknown) ;
  1985. RETURN
  1986. END ;
  1987. IF symtab [idx].tag = KBuiltin THEN
  1988. IoCall (idx) ;
  1989. RETURN
  1990. END ;
  1991. IF symtab [idx].tag = KProc THEN
  1992. IF MatchDelim ('(') THEN
  1993. ParseCallArgs (idx)
  1994. ELSE
  1995. ParseCall (idx)
  1996. END ;
  1997. RETURN
  1998. END ;
  1999. IF (symtab [idx].tag = KVar) OR (symtab [idx].tag = KFunc) THEN
  2000. t.idx := idx ;
  2001. t.kind := 1 ;
  2002. t.boff := 0 ;
  2003. t.cls := symtab [idx].cls ;
  2004. IF symtab [idx].tag = KFunc THEN
  2005. t.idx := symtab [idx].resvar ;
  2006. t.cls := symtab [t.idx].cls
  2007. END ;
  2008. ParseSub (t) ;
  2009. IF MatchAssign () THEN
  2010. Assignment (t) ;
  2011. RETURN
  2012. END ;
  2013. Err (ENoSemi) ;
  2014. RETURN
  2015. END ;
  2016. Err (ENoSemi)
  2017. END
  2018. END Statmnt ;
  2019. (* ---------------------------------------------------------------- *)
  2020. (* types and declarations (TPSRC7) *)
  2021. (* ---------------------------------------------------------------- *)
  2022. PROCEDURE ParseType (VAR cls, size, elem : CARDINAL) ;
  2023. VAR tok : CARDINAL ;
  2024. idx : CARDINAL ;
  2025. lo, hi : LONGINT ;
  2026. s2, e2 : CARDINAL ;
  2027. subcls : CARDINAL ;
  2028. strf : BOOLEAN ;
  2029. consumed : BOOLEAN ;
  2030. BEGIN
  2031. cls := TNone ; size := 0 ; elem := 0 ;
  2032. consumed := FALSE ;
  2033. Skip () ; (* after ':' / '=' : skip blanks *)
  2034. IF Alpha (CurCh ()) THEN
  2035. DropB (MatchKey (tok)) ;
  2036. consumed := TRUE
  2037. ELSE
  2038. tok := TkNone
  2039. END ;
  2040. IF tok = TkArray THEN
  2041. ExpectDelim ('[', ENoSemi) ;
  2042. RdConst (lo, subcls, strf) ;
  2043. IF NOT MatchRange () THEN
  2044. Err (ESimpType)
  2045. END ;
  2046. RdConst (hi, subcls, strf) ;
  2047. ExpectDelim (']', ENoSemi) ;
  2048. IF NOT (MatchKey (tok) AND (tok = TkOf)) THEN
  2049. Err (ENoSemi)
  2050. END ;
  2051. ParseType (cls, s2, e2) ;
  2052. cls := TArray ;
  2053. elem := s2 ;
  2054. size := s2 * (W16 (VAL (LONGINT, W16 (hi))
  2055. - VAL (LONGINT, W16 (lo)) + 1))
  2056. ELSIF tok = TkString THEN
  2057. cls := TString ;
  2058. size := 256 ;
  2059. elem := 1 ;
  2060. IF MatchDelim ('[') THEN
  2061. RdConst (hi, subcls, strf) ;
  2062. ExpectDelim (']', ENoSemi) ;
  2063. size := W16 (hi) + 1
  2064. END
  2065. ELSIF tok = TkSet THEN
  2066. Err (ENoLib) ;
  2067. IF MatchKey (tok) AND (tok = TkOf) THEN
  2068. ParseType (cls, s2, e2)
  2069. END
  2070. ELSIF tok = TkRecord THEN
  2071. Err (ENoLib) ;
  2072. LOOP
  2073. PeekKw (tok) ;
  2074. IF tok = TkEnd THEN
  2075. DropB (MatchKey (tok)) ;
  2076. EXIT
  2077. END ;
  2078. IF CurCh () = 0C THEN
  2079. EXIT
  2080. END ;
  2081. Skip () ;
  2082. IF Alpha (CurCh ()) THEN
  2083. DropCh (GetCh ())
  2084. ELSE
  2085. DropCh (GetCh ())
  2086. END
  2087. END
  2088. ELSIF (tok = TkFile) OR (tok = TkText) THEN
  2089. cls := TFile ;
  2090. size := 0 ;
  2091. elem := 0 ;
  2092. Err (ENoLib)
  2093. ELSE
  2094. IF consumed THEN
  2095. IF Search (wrd, idx) AND (symtab [idx].tag = KType) THEN
  2096. cls := symtab [idx].cls ;
  2097. size := symtab [idx].size ;
  2098. elem := symtab [idx].size
  2099. ELSE
  2100. Err (EUnknown)
  2101. END
  2102. ELSE
  2103. (* subrange lo .. hi *)
  2104. RdConst (lo, subcls, strf) ;
  2105. IF NOT MatchRange () THEN
  2106. Err (ESimpType) ;
  2107. RETURN
  2108. END ;
  2109. RdConst (hi, subcls, strf) ;
  2110. cls := TScalar ;
  2111. size := 2 ;
  2112. elem := 2
  2113. END
  2114. END
  2115. END ParseType ;
  2116. PROCEDURE DefVar () ;
  2117. (* 'name' (',' name)* ':' type [ABSOLUTE addr] ; group repeated until a
  2118. declaration keyword appears *)
  2119. VAR nm : ARRAY [0..MaxName] OF CHAR ;
  2120. cls, size, elem : CARDINAL ;
  2121. tok : CARDINAL ;
  2122. v : LONGINT ;
  2123. off : CARDINAL ;
  2124. BEGIN
  2125. LOOP
  2126. Skip () ; (* after the VAR keyword: skip blanks *)
  2127. IF NOT Alpha (CurCh ()) THEN
  2128. Err (EUnknown) ;
  2129. RETURN
  2130. END ;
  2131. LOOP
  2132. GetWord () ;
  2133. SaveWord (nm) ;
  2134. DupTest (nm) ;
  2135. IF NOT MatchDelim (':') THEN
  2136. Err (ENoSemi)
  2137. END ;
  2138. ParseType (cls, size, elem) ;
  2139. off := 0 ;
  2140. IF lexnest = 0 THEN
  2141. IF size > 2 THEN
  2142. Err (ENoLib) ;
  2143. RETURN
  2144. END ;
  2145. PeekKw (tok) ;
  2146. IF tok = TkAbsolute THEN
  2147. DropB (MatchKey (tok)) ;
  2148. IF (CurCh () = '$') OR (Digit (CurCh ())) THEN
  2149. RdIntConst (v) ;
  2150. off := W16 (v)
  2151. ELSE
  2152. Err (EUnknown)
  2153. END
  2154. ELSE
  2155. off := dc ;
  2156. dc := dc + size
  2157. END ;
  2158. DropC (NewSym (nm, KVar, cls, size, elem, off, 0, FALSE)) ;
  2159. varspc := varspc + size
  2160. ELSE
  2161. IF size > 2 THEN
  2162. Err (ENoLib) ;
  2163. RETURN
  2164. END ;
  2165. DropC (NewSym (nm, KVar, cls, size, elem, locFree, 0, TRUE)) ;
  2166. locFree := (locFree - size) MOD 10000H ;
  2167. locBytes := locBytes + size
  2168. END ;
  2169. IF NOT MatchDelim (',') THEN
  2170. EXIT
  2171. END
  2172. END ;
  2173. IF NOT MatchDelim (';') THEN
  2174. Err (ENoSemi) ;
  2175. RETURN
  2176. END ;
  2177. PeekKw (tok) ;
  2178. IF tok # TkNone THEN
  2179. RETURN
  2180. END
  2181. END
  2182. END DefVar ;
  2183. PROCEDURE DefConst () ;
  2184. VAR nm : ARRAY [0..MaxName] OF CHAR ;
  2185. v : LONGINT ;
  2186. cls : CARDINAL ;
  2187. isStr : BOOLEAN ;
  2188. tok : CARDINAL ;
  2189. BEGIN
  2190. LOOP
  2191. PeekKw (tok) ;
  2192. IF tok # TkNone THEN
  2193. RETURN
  2194. END ;
  2195. Skip () ; (* after the CONST keyword: skip blanks *)
  2196. IF NOT Alpha (CurCh ()) THEN
  2197. Err (EUnknown) ;
  2198. RETURN
  2199. END ;
  2200. GetWord () ;
  2201. SaveWord (nm) ;
  2202. DupTest (nm) ;
  2203. ExpectDelim ('=', ENoSemi) ;
  2204. RdConst (v, cls, isStr) ;
  2205. IF isStr THEN
  2206. Err (ENoLib)
  2207. END ;
  2208. DropC (NewSym (nm, KConst, cls, 0, 0, 0, v, FALSE)) ;
  2209. IF NOT MatchDelim (';') THEN
  2210. Err (ENoSemi) ;
  2211. RETURN
  2212. END
  2213. END
  2214. END DefConst ;
  2215. PROCEDURE DefLabelPart () ;
  2216. VAR nm : ARRAY [0..9] OF CHAR ;
  2217. n : CARDINAL ;
  2218. BEGIN
  2219. LOOP
  2220. Skip () ;
  2221. IF NOT Digit (CurCh ()) THEN
  2222. Err (EUnknown) ;
  2223. RETURN
  2224. END ;
  2225. n := 0 ;
  2226. WHILE Digit (CurCh ()) DO
  2227. n := n * 10 + (ORD (CurCh ()) - ORD ('0')) ;
  2228. DropCh (GetCh ())
  2229. END ;
  2230. NumToName (n, nm) ;
  2231. IF NOT Search (nm, n) THEN
  2232. DropC (NewSym (nm, KLabel, TScalar, 0, 0, 0, 0, FALSE))
  2233. END ;
  2234. IF NOT MatchDelim (',') THEN
  2235. IF MatchDelim (';') THEN
  2236. RETURN
  2237. END ;
  2238. Err (ENoSemi) ;
  2239. RETURN
  2240. END
  2241. END
  2242. END DefLabelPart ;
  2243. PROCEDURE IfMatchSemi () ;
  2244. BEGIN
  2245. IF NOT MatchDelim (';') THEN
  2246. Err (ENoSemi)
  2247. END
  2248. END IfMatchSemi ;
  2249. PROCEDURE SymEpi () ;
  2250. (* function result: AX := result var *)
  2251. BEGIN
  2252. IF curIsFunc THEN
  2253. IF OK () THEN
  2254. EmLoadVar (TRUE, symtab [resultVar].off, symtab [resultVar].size)
  2255. END
  2256. END
  2257. END SymEpi ;
  2258. PROCEDURE ProcFunc () ;
  2259. (* PROCEDURE name (params) ; body | FUNCTION name (params) : type ; body *)
  2260. VAR nm : ARRAY [0..MaxName] OF CHAR ;
  2261. idx, old : CARDINAL ;
  2262. tok, tok2 : CARDINAL ;
  2263. parmNm : ARRAY [0..MaxName] OF CHAR ;
  2264. cls, size, elem : CARDINAL ;
  2265. isFunc : BOOLEAN ;
  2266. saveNest, saveLoc, saveRes, saveF : CARDINAL ;
  2267. saveLB, savePO : CARDINAL ;
  2268. i : CARDINAL ;
  2269. BEGIN
  2270. isFunc := curIsFunc ;
  2271. Skip () ; (* after the PROCEDURE/FUNCTION keyword *)
  2272. IF NOT Alpha (CurCh ()) THEN
  2273. Err (EUnknown) ;
  2274. RETURN
  2275. END ;
  2276. GetWord () ;
  2277. SaveWord (nm) ;
  2278. IF Search (nm, idx) AND (symtab [idx].tag = KProc)
  2279. AND (symtab [idx].fwd) THEN
  2280. old := idx
  2281. ELSIF Search (nm, idx) THEN
  2282. Err (EUnknown) ;
  2283. RETURN
  2284. ELSE
  2285. old := NewSym (nm, KProc, TNone, 0, 0, 0, 0, FALSE)
  2286. END ;
  2287. IF isFunc THEN
  2288. symtab [old].tag := KFunc
  2289. END ;
  2290. saveNest := lexnest ;
  2291. saveLoc := locFree ;
  2292. saveRes := resultVar ;
  2293. saveF := VAL (CARDINAL, ORD (curIsFunc)) ;
  2294. saveLB := locBytes ;
  2295. savePO := parmOff ;
  2296. INC (lexnest) ;
  2297. locFree := 0FFFEH ;
  2298. locBytes := 0 ;
  2299. parmOff := 4 ;
  2300. IF MatchDelim ('(') THEN
  2301. IF CurCh () # ')' THEN
  2302. LOOP
  2303. (* PeekKw, not MatchKey: MatchKey CONSUMES the word it reads, so
  2304. using it to test for VAR would eat the parameter's name. *)
  2305. PeekKw (tok) ;
  2306. IF tok = TkVar THEN
  2307. (* VAR parameter recorded as value in this milestone *)
  2308. DropB (MatchKey (tok))
  2309. END ;
  2310. Skip () ; (* blanks before the parameter name *)
  2311. IF NOT Alpha (CurCh ()) THEN
  2312. Err (EUnknown) ;
  2313. RETURN
  2314. END ;
  2315. GetWord () ;
  2316. SaveWord (parmNm) ;
  2317. DupTest (parmNm) ;
  2318. ExpectDelim (':', ENoSemi) ; (* formal is 'name : type' *)
  2319. ParseType (cls, size, elem) ;
  2320. IF size > 2 THEN
  2321. Err (ENoLib) ;
  2322. RETURN
  2323. END ;
  2324. DropC (NewSym (parmNm, KVar, cls, size, elem, parmOff, 0, TRUE)) ;
  2325. parmOff := parmOff + 2 ;
  2326. IF NOT MatchDelim (',') THEN
  2327. IF MatchDelim (')') THEN
  2328. EXIT
  2329. END ;
  2330. Err (ENoSemi) ;
  2331. EXIT
  2332. END
  2333. END
  2334. ELSE
  2335. DropCh (GetCh ())
  2336. END
  2337. END ;
  2338. IF isFunc THEN
  2339. IF MatchDelim (':') THEN
  2340. ParseType (cls, size, elem)
  2341. ELSE
  2342. cls := TScalar ;
  2343. size := 2 ;
  2344. elem := 2
  2345. END ;
  2346. IF size > 2 THEN
  2347. Err (ENoLib) ;
  2348. RETURN
  2349. END ;
  2350. symtab [old].cls := cls ;
  2351. symtab [old].size := size ;
  2352. resultVar := NewSym (nm, KVar, cls, size, elem, locFree, 0, TRUE) ;
  2353. symtab [old].resvar := resultVar ;
  2354. locFree := (locFree - size) MOD 10000H ;
  2355. locBytes := locBytes + size
  2356. END ;
  2357. IfMatchSemi () ;
  2358. PeekKw (tok2) ;
  2359. IF (tok2 = TkForward) OR (tok2 = TkExternal) THEN
  2360. DropB (MatchKey (tok2)) ;
  2361. symtab [old].fwd := TRUE ;
  2362. symtab [old].defnd := (tok2 = TkExternal) ;
  2363. IfMatchSemi () ;
  2364. lexnest := saveNest ;
  2365. locFree := saveLoc ;
  2366. resultVar := saveRes ;
  2367. curIsFunc := (saveF # 0) ;
  2368. locBytes := saveLB ;
  2369. parmOff := savePO ;
  2370. RETURN
  2371. END ;
  2372. (* body *)
  2373. symtab [old].goPos := pc ;
  2374. symtab [old].defnd := TRUE ;
  2375. EmPushBp () ;
  2376. EmMovBpSp () ;
  2377. DefPart () ; (* nested declarations; stops at BEGIN *)
  2378. IF locBytes > 0 THEN
  2379. EmSubSp (locBytes)
  2380. END ;
  2381. DropC (EmCall (TU_StackChk)) ;
  2382. Statmnt () ; (* body *)
  2383. IF OK () THEN
  2384. SymEpi () ;
  2385. EmLeave () ;
  2386. EmRet ()
  2387. END ;
  2388. (* patch pending forward calls to this proc *)
  2389. i := 0 ;
  2390. WHILE i < nPend DO
  2391. IF (pend [i].kind = 1) AND (pend [i].who = old) THEN
  2392. SetPatTgt (pend [i].place, symtab [old].goPos) ;
  2393. pend [i].kind := 99
  2394. END ;
  2395. INC (i)
  2396. END ;
  2397. lexnest := saveNest ;
  2398. locFree := saveLoc ;
  2399. resultVar := saveRes ;
  2400. curIsFunc := (saveF # 0) ;
  2401. locBytes := saveLB ;
  2402. parmOff := savePO
  2403. END ProcFunc ;
  2404. PROCEDURE DefType () ;
  2405. (* 'name' '=' typeDef ; ... until a declaration keyword appears *)
  2406. VAR nm : ARRAY [0..MaxName] OF CHAR ;
  2407. cls, size, elem : CARDINAL ;
  2408. tok : CARDINAL ;
  2409. BEGIN
  2410. LOOP
  2411. PeekKw (tok) ;
  2412. IF tok # TkNone THEN
  2413. RETURN
  2414. END ;
  2415. Skip () ; (* after the TYPE keyword: skip blanks *)
  2416. IF NOT Alpha (CurCh ()) THEN
  2417. Err (EUnknown) ;
  2418. RETURN
  2419. END ;
  2420. GetWord () ;
  2421. SaveWord (nm) ;
  2422. DupTest (nm) ;
  2423. ExpectDelim ('=', ENoSemi) ;
  2424. ParseType (cls, size, elem) ;
  2425. IF NOT OK () THEN
  2426. RETURN
  2427. END ;
  2428. DropC (NewSym (nm, KType, cls, size, elem, 0, 0, FALSE)) ;
  2429. IF NOT MatchDelim (';') THEN
  2430. Err (ENoSemi) ;
  2431. RETURN
  2432. END
  2433. END
  2434. END DefType ;
  2435. PROCEDURE DefPart () ;
  2436. (* LABEL / CONST / TYPE / VAR / OVERLAY / PROC / FUNCTION / BEGIN *)
  2437. VAR tok : CARDINAL ;
  2438. BEGIN
  2439. LOOP
  2440. IF MatchDelim (';') THEN
  2441. (* separator between declarations *)
  2442. ELSE
  2443. PeekKw (tok) ;
  2444. IF tok = TkBegin THEN
  2445. RETURN
  2446. END ;
  2447. IF NOT MatchKey (tok) THEN
  2448. Err (EUnknown) ;
  2449. RETURN
  2450. END ;
  2451. CASE tok OF
  2452. TkLabel : DefLabelPart () ;
  2453. | TkConst : DefConst () ;
  2454. | TkType : DefType () ;
  2455. | TkVar : DefVar () ;
  2456. | TkOverlay :
  2457. LOOP
  2458. Skip () ;
  2459. IF CurCh () = ';' THEN
  2460. DropCh (GetCh ()) ;
  2461. EXIT
  2462. END ;
  2463. IF CurCh () = 0C THEN
  2464. Err (ENoSemi) ;
  2465. EXIT
  2466. END ;
  2467. DropCh (GetCh ())
  2468. END ;
  2469. | TkProcedure : curIsFunc := FALSE ; ProcFunc () ;
  2470. | TkFunction : curIsFunc := TRUE ; ProcFunc () ;
  2471. ELSE
  2472. Err (EUnknown) ;
  2473. RETURN
  2474. END ;
  2475. IF NOT OK () THEN
  2476. RETURN
  2477. END
  2478. END
  2479. END
  2480. END DefPart ;
  2481. (* ---------------------------------------------------------------- *)
  2482. (* driver (TPSRC7 compile) *)
  2483. (* ---------------------------------------------------------------- *)
  2484. PROCEDURE DefBuiltins () ;
  2485. (* The standard procedures. Without these, WRITELN is absent from the
  2486. symbol table, Statmnt's identifier branch fails its Search and every
  2487. program that prints anything dies with EUnknown (41) on the '(' after the
  2488. call name - the single remaining cause of failure in the fixture matrix.
  2489. Tagged KBuiltin (not KProc) because these are not called generically:
  2490. WRITE/WRITELN/READ/READLN need TP3's per-argument type dispatch
  2491. (IoCall), and HALT takes no argument at all. defnd is TRUE because the
  2492. entry point is known - there is no forward reference to patch. *)
  2493. VAR i : CARDINAL ;
  2494. BEGIN
  2495. i := NewSym ("WRITE" , KBuiltin, BI_Write , 0, 0, 0, 0, FALSE) ;
  2496. symtab [i].defnd := TRUE ;
  2497. symtab [i].goPos := TU_WrInt ;
  2498. i := NewSym ("WRITELN", KBuiltin, BI_WriteLn, 0, 0, 0, 0, FALSE) ;
  2499. symtab [i].defnd := TRUE ;
  2500. symtab [i].goPos := TU_WrInt ;
  2501. i := NewSym ("READ" , KBuiltin, BI_Read , 0, 0, 0, 0, FALSE) ;
  2502. symtab [i].defnd := TRUE ;
  2503. symtab [i].goPos := TU_RdInt ;
  2504. i := NewSym ("READLN" , KBuiltin, BI_ReadLn , 0, 0, 0, 0, FALSE) ;
  2505. symtab [i].defnd := TRUE ;
  2506. symtab [i].goPos := TU_RdInt ;
  2507. i := NewSym ("HALT" , KBuiltin, BI_Halt , 0, 0, 0, 0, FALSE) ;
  2508. symtab [i].defnd := TRUE ;
  2509. symtab [i].goPos := TU_Halt
  2510. END DefBuiltins ;
  2511. PROCEDURE Inittur () ;
  2512. (* reset compiler state and define the standard types *)
  2513. BEGIN
  2514. abortFac := FALSE ;
  2515. errNum := 0 ;
  2516. txerrPos := 0 ;
  2517. srcPos := 0 ;
  2518. srcLen := Length () ;
  2519. pc := 0 ;
  2520. dc := 100H ;
  2521. varspc := 0 ;
  2522. symTop := 0 ;
  2523. nPatch := 0 ;
  2524. nPend := 0 ;
  2525. exitCnt := 0 ;
  2526. brkN := 0 ;
  2527. caseN := 0 ;
  2528. lexnest := 0 ;
  2529. curIsFunc := FALSE ;
  2530. resultVar := 0 ;
  2531. locFree := 0FFFEH ;
  2532. locBytes := 0 ;
  2533. parmOff := 4 ;
  2534. dirs.rng := TRUE ;
  2535. dirs.chk := TRUE ;
  2536. InitKeys () ;
  2537. DropC (NewSym ("INTEGER", KType, TScalar, 2, 2, 0, 0, FALSE)) ;
  2538. DropC (NewSym ("BYTE" , KType, TScalar, 1, 1, 0, 0, FALSE)) ;
  2539. DropC (NewSym ("CHAR" , KType, TScalar, 1, 1, 0, 0, FALSE)) ;
  2540. DropC (NewSym ("BOOLEAN", KType, TBool , 1, 1, 0, 0, FALSE)) ;
  2541. DropC (NewSym ("REAL" , KType, TReal , 6, 6, 0, 0, FALSE)) ;
  2542. DropC (NewSym ("STRING" , KType, TString, 256, 1, 0, 0, FALSE)) ;
  2543. DropC (NewSym ("TRUE" , KConst, TBool, 1, 1, 0, 1, FALSE)) ;
  2544. DropC (NewSym ("FALSE" , KConst, TBool, 1, 1, 0, 0, FALSE)) ;
  2545. DefBuiltins () ;
  2546. tmpA := NewSym ("@@T1", KVar, TScalar, 2, 2, dc, 0, FALSE) ;
  2547. dc := dc + 2 ;
  2548. tmpB := NewSym ("@@T2", KVar, TScalar, 2, 2, dc, 0, FALSE) ;
  2549. dc := dc + 2
  2550. END Inittur ;
  2551. PROCEDURE HeadWord (VAR slot : CARDINAL) ;
  2552. BEGIN
  2553. slot := pc ;
  2554. Eword (0)
  2555. END HeadWord ;
  2556. PROCEDURE Compile (VAR errNo, errPos : CARDINAL) : BOOLEAN ;
  2557. VAR tok : CARDINAL ;
  2558. BEGIN
  2559. Inittur () ;
  2560. IF OK () THEN
  2561. (* program prologue: header words, CALL initmem, MOV BP,SP *)
  2562. HeadWord (hdrFlag) ;
  2563. HeadWord (hdrCS) ;
  2564. HeadWord (hdrDS) ;
  2565. HeadWord (hdrHeap) ;
  2566. HeadWord (hdrMax) ;
  2567. Eword (16) ; (* max open files *)
  2568. Eword (0) ; (* input buffer word *)
  2569. Eword (0) ; (* output buffer word *)
  2570. DropC (EmCall (TU_InitMem)) ;
  2571. EmMovBpSp () ;
  2572. IF MatchKey (tok) AND (tok = TkProgram) THEN
  2573. (* MatchKey stops right after "PROGRAM", so the optional program
  2574. name normally follows blanks. Skip them before testing for the
  2575. name: otherwise Alpha sees the blank, the name is never consumed
  2576. and IfMatchSemi reports ENoSemi at the name. *)
  2577. Skip () ;
  2578. IF Alpha (CurCh ()) THEN
  2579. GetWord ()
  2580. END ;
  2581. IF MatchDelim ('(') THEN
  2582. WHILE NOT MatchDelim (')') DO
  2583. IF Alpha (CurCh ()) THEN
  2584. GetWord ()
  2585. END ;
  2586. IF CurCh () = ',' THEN
  2587. DropCh (GetCh ())
  2588. END
  2589. END
  2590. END ;
  2591. IfMatchSemi ()
  2592. END ;
  2593. IF OK () THEN
  2594. DefPart () ;
  2595. IF OK () THEN
  2596. IF MatchKey (tok) AND (tok = TkBegin) THEN
  2597. Compound () ;
  2598. IF OK () THEN
  2599. EmXorAxAx () ;
  2600. DropC (EmCall (TU_ProgEnd)) ;
  2601. ResolvePatches () ;
  2602. codeSz := pc ;
  2603. dataSz := dc ;
  2604. cbuf [hdrCS] := VAL (BYTE, (codeSz DIV 16) MOD 100H) ;
  2605. cbuf [hdrCS + 1] := VAL (BYTE, ((codeSz DIV 16) DIV 100H) MOD 100H) ;
  2606. cbuf [hdrDS] := VAL (BYTE, (dataSz DIV 16) MOD 100H) ;
  2607. cbuf [hdrDS + 1] := VAL (BYTE, ((dataSz DIV 16) DIV 100H) MOD 100H) ;
  2608. cbuf [hdrFlag] := 1 ;
  2609. cbuf [hdrFlag + 1] := 0 ;
  2610. cbuf [hdrHeap] := 0 ;
  2611. cbuf [hdrHeap + 1] := 0 ;
  2612. cbuf [hdrMax] := 0 ;
  2613. cbuf [hdrMax + 1] := 0
  2614. END
  2615. ELSE
  2616. Err (EUnknown)
  2617. END
  2618. END
  2619. END
  2620. END ;
  2621. IF NOT MatchDelim ('.') THEN
  2622. Err (EPointExp)
  2623. END ;
  2624. IF abortFac THEN
  2625. errNo := errNum ; (* was "errNo := errNo": a self-assignment,
  2626. because the formal shadowed the module
  2627. variable, so the error code always
  2628. reached the caller as 0 *)
  2629. errPos := txerrPos ;
  2630. RETURN FALSE
  2631. END ;
  2632. errNo := 0 ;
  2633. errPos := 0 ;
  2634. RETURN TRUE
  2635. END Compile ;
  2636. PROCEDURE CodeBytes () : CARDINAL ;
  2637. BEGIN
  2638. RETURN codeSz
  2639. END CodeBytes ;
  2640. PROCEDURE DataBytes () : CARDINAL ;
  2641. BEGIN
  2642. RETURN dataSz
  2643. END DataBytes ;
  2644. PROCEDURE CodeByteAt (i : CARDINAL) : BYTE ;
  2645. (* i-th byte of the emitted image, for test harnesses that need to check
  2646. the generated 8086 code rather than just its size. Returns 0 past the
  2647. end of the image. *)
  2648. BEGIN
  2649. IF i >= codeSz THEN
  2650. RETURN 0
  2651. END ;
  2652. RETURN cbuf [i]
  2653. END CodeByteAt ;
  2654. END Compiler.