Compiler.mod 83 KB

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