Compiler.mod 75 KB

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