Compiler.mod 67 KB

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