Compiler.mod 66 KB

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