| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594 |
- IMPLEMENTATION MODULE Compiler ;
- (* Turbo Pascal 3-style single-pass Pascal -> 8086 compiler in
- GNU Modula-2 (-fiso), following the structure of the original
- TPSRC6 'turbo' entry / TPSRC7-10:
- Inittur reset state, pre-defined types, scratch temporaries
- Skip lexer: blanks, comments { } and (* *), directives {$ }
- GetWord/WddTok/MatchKey word lexing with a keyword table (kName/kTk)
- PeekKw lookahead keyword check WITHOUT consuming (via saved
- srcPos) - needed because declarations and compound
- statements peek at END/ELSE/etc
- RdIntConst/RdConst integer, hex and char constants
- Search symbol table lookup filtered by lexical level
- ParseExpr -> ParseCmp -> ParseAdd -> ParseMul -> ParseNeg
- -> ParseAtom precedence climb (TPSRC9)
- Statmnt statements: if/while/repeat/for/case/goto/exit/begin
- assignment and calls (TPSRC8)
- ParseType/Decls ARRAY, STRING, scalar/subrange types; variable,
- constant, label and procedure/function definitions
- Compile driver: optional PROGRAM header, DefPart, progpart,
- final '.', header size patch, patch resolution.
- Ebyte/Eword/Ecall/Ejmp + patch list code emission (TPSRC10).
- The emitted image is a byte array (mode word, CS/DS, size words,
- CALL initmem, MOV BP,SP, then generated code). Forward labels and
- forward procedure calls resolve through a patch list (ptc records).
- Working subset (v0.3): integer/char/boolean/byte scalars, constants
- with folding, globals, locals, value parameters, procedures and
- scalar-result functions, ARRAY[const..const] with constant indexing,
- control flow, GOTO/EXIT. Real/set/record/file and string runtime
- raise Err (ENoLib) pending the future runtime library - matching the
- original's "not implemented" error path. *)
- FROM TextBuf IMPORT Length, CharAt ;
- FROM SYSTEM IMPORT BYTE ;
- (* ---------------------------------------------------------------- *)
- (* constants *)
- (* ---------------------------------------------------------------- *)
- CONST
- MaxLine = 128 ;
- MaxName = 31 ;
- MaxCode = 24000 ;
- MaxSym = 3000 ;
- MaxPatch = 2000 ;
- MaxPend = 400 ;
- (* type codes (TP3 vartp) *)
- TNone = 0 ; TArray = 1 ; TRecord = 2 ; TSet = 3 ;
- TPtr = 4 ; TFile = 5 ; TText = 6 ; TUntyp = 7 ;
- TString = 8 ; TReal = 9 ; TScalar = 10 ; TBool = 11 ;
- (* symbol kinds *)
- KLabel = 100H ; KConst = 200H ; KType = 300H ;
- KVar = 400H ; KProc = 500H ; KFunc = 600H ;
- (* keyword tokens *)
- TkNone = 0 ; TkProgram = 1 ; TkBegin = 2 ; TkEnd = 3 ;
- TkIf = 4 ; TkThen = 5 ; TkElse = 6 ; TkWhile = 7 ;
- TkDo = 8 ; TkRepeat = 9 ; TkUntil = 10 ; TkFor = 11 ;
- TkTo = 12 ; TkDownto = 13 ; TkCase = 14 ; TkOf = 15 ;
- TkGoto = 16 ; TkExit = 17 ; TkWith = 18 ; TkVar = 19 ;
- TkConst= 20 ; TkType = 21 ; TkLabel = 22 ; TkProcedure = 23 ;
- TkFunction = 24 ; TkNil = 25 ; TkAnd = 26 ; TkOr = 27 ;
- TkNot = 28 ; TkDiv = 29 ; TkMod = 30 ; TkIn = 31 ;
- TkFile = 32 ; TkText = 33 ; TkRecord = 34 ; TkArray = 35 ;
- TkSet = 36 ; TkPacked = 37 ; TkForward = 38 ; TkExternal = 39 ;
- TkAbsolute = 40 ; TkOverlay = 41 ; TkString = 42 ;
- (* runtime entry offsets in the emitted image (TU_InitMem etc.) *)
- TU_InitMem = 8H ;
- TU_ProgEnd = 10H ;
- TU_StackChk = 18H ;
- (* TP3 error numbers *)
- ENoSemi = 1 ; EPointExp = 10 ; ESimpType = 30 ;
- EUnknown = 41 ; EConstRange = 45 ; EMemOvf = 98 ;
- ECompOvf = 99 ; ENoLib = 102 ; ETypeErr = 56 ;
- AposC = 39 ; (* ORD ("'") - avoids quote-in-quote *)
- (* ---------------------------------------------------------------- *)
- (* types *)
- (* ---------------------------------------------------------------- *)
- TYPE
- SymEntry =
- RECORD
- name : ARRAY [0..MaxName] OF CHAR ;
- tag : CARDINAL ;
- cls : CARDINAL ;
- size : CARDINAL ;
- elem : CARDINAL ;
- off : CARDINAL ;
- lval : LONGINT ;
- level : CARDINAL ;
- local : BOOLEAN ;
- resvar : CARDINAL ;
- goPos : CARDINAL ;
- defnd : BOOLEAN ;
- fwd : BOOLEAN ;
- END ;
- PatchRec =
- RECORD
- place : CARDINAL ;
- target : CARDINAL ;
- filled : BOOLEAN ;
- END ;
- PendRec =
- RECORD
- kind : CARDINAL ; (* 0 goto, 1 call *)
- who : CARDINAL ;
- place : CARDINAL ; (* patch slot index *)
- END ;
- ERes =
- RECORD
- cls : CARDINAL ;
- kind : CARDINAL ; (* 0 const, 1 var, 2 value in AX *)
- imm : LONGINT ;
- idx : CARDINAL ;
- boff : CARDINAL ; (* constant fold-in for subscripts *)
- END ;
- DirRec = RECORD rng, chk : BOOLEAN END ;
- (* ---------------------------------------------------------------- *)
- (* state *)
- (* ---------------------------------------------------------------- *)
- VAR
- srcPos, srcLen : CARDINAL ;
- wrd : ARRAY [0..MaxName] OF CHAR ;
- symtab : ARRAY [0..MaxSym - 1] OF SymEntry ;
- symTop : CARDINAL ;
- patches : ARRAY [0..MaxPatch - 1] OF PatchRec ;
- nPatch : CARDINAL ;
- pend : ARRAY [0..MaxPend - 1] OF PendRec ;
- nPend : CARDINAL ;
- exitPatch : ARRAY [0..63] OF CARDINAL ;
- exitCnt : CARDINAL ;
- brkSave : ARRAY [0..15] OF CARDINAL ;
- loopTy : ARRAY [0..15] OF CARDINAL ; (* 1 while/repeat, 2 for *)
- brkN : CARDINAL ;
- caseJmp : ARRAY [0..63] OF CARDINAL ;
- caseN : CARDINAL ;
- pc, dc : CARDINAL ;
- varspc : CARDINAL ;
- cbuf : ARRAY [0..MaxCode - 1] OF BYTE ;
- codeSz, dataSz : CARDINAL ;
- abortFac : BOOLEAN ;
- errNo : CARDINAL ;
- txerrPos : CARDINAL ;
- lexnest : CARDINAL ;
- curIsFunc : BOOLEAN ;
- resultVar : CARDINAL ;
- locFree : CARDINAL ; (* next local slot (BP-relative, 8-bit) *)
- locBytes : CARDINAL ; (* frame size for SUB SP *)
- parmOff : CARDINAL ; (* next parameter slot (BP-relative) *)
- dirs : DirRec ;
- tmpA, tmpB : CARDINAL ; (* global scratch word addresses *)
- hdrFlag, hdrCS, hdrDS, hdrHeap, hdrMax : CARDINAL ;
- kName : ARRAY [0..42] OF ARRAY [0..15] OF CHAR ;
- kTk : ARRAY [0..42] OF CARDINAL ;
- (* ---------------------------------------------------------------- *)
- (* small char helpers *)
- (* ---------------------------------------------------------------- *)
- PROCEDURE CurCh () : CHAR ;
- BEGIN
- IF srcPos >= srcLen THEN
- RETURN 0C
- END ;
- RETURN CharAt (srcPos)
- END CurCh ;
- PROCEDURE GetCh () : CHAR ;
- VAR ch : CHAR ;
- BEGIN
- ch := CurCh () ;
- IF srcPos < srcLen THEN
- INC (srcPos)
- END ;
- RETURN ch
- END GetCh ;
- PROCEDURE PeekAhead (k : CARDINAL) : CHAR ;
- BEGIN
- IF srcPos + k >= srcLen THEN
- RETURN 0C
- END ;
- RETURN CharAt (srcPos + k)
- END PeekAhead ;
- PROCEDURE Digit (ch : CHAR) : BOOLEAN ;
- BEGIN
- RETURN (ch >= '0') AND (ch <= '9')
- END Digit ;
- PROCEDURE Alpha (ch : CHAR) : BOOLEAN ;
- BEGIN
- RETURN ((ch >= 'A') AND (ch <= 'Z')) OR ((ch >= 'a') AND (ch <= 'z'))
- OR (ch = '_')
- END Alpha ;
- PROCEDURE AlphaNum (ch : CHAR) : BOOLEAN ;
- BEGIN
- RETURN (Alpha (ch)) OR (Digit (ch))
- END AlphaNum ;
- PROCEDURE IsHexCh (ch : CHAR) : BOOLEAN ;
- BEGIN
- RETURN (Digit (ch)) OR ((ch >= 'A') AND (ch <= 'F'))
- OR ((ch >= 'a') AND (ch <= 'f'))
- END IsHexCh ;
- PROCEDURE Upper (ch : CHAR) : CHAR ;
- BEGIN
- IF (ch >= 'a') AND (ch <= 'z') THEN
- RETURN CHR (ORD (ch) - ORD ('a') + ORD ('A'))
- END ;
- RETURN ch
- END Upper ;
- PROCEDURE W16 (x : LONGINT) : CARDINAL ;
- (* fold x modulo 10000H, handling negatives (no negative MOD) *)
- VAR m : CARDINAL ;
- BEGIN
- IF x >= 0 THEN
- RETURN VAL (CARDINAL, x MOD 10000H)
- END ;
- m := VAL (CARDINAL, (0 - x) MOD 10000H) ;
- RETURN (10000H - m) MOD 10000H
- END W16 ;
- PROCEDURE DropCh (v : CHAR) ;
- BEGIN
- END DropCh ;
- PROCEDURE DropB (v : BOOLEAN) ;
- BEGIN
- END DropB ;
- PROCEDURE DropC (v : CARDINAL) ;
- BEGIN
- END DropC ;
- PROCEDURE BitAnd (a, b : LONGINT) : LONGINT ;
- BEGIN
- RETURN VAL (LONGINT, CARDINAL (VAL (BITSET, W16 (a))
- * VAL (BITSET, W16 (b))))
- END BitAnd ;
- PROCEDURE BitOr (a, b : LONGINT) : LONGINT ;
- BEGIN
- RETURN VAL (LONGINT, CARDINAL (VAL (BITSET, W16 (a))
- + VAL (BITSET, W16 (b))))
- END BitOr ;
- PROCEDURE BitNot (a : LONGINT) : LONGINT ;
- BEGIN
- RETURN VAL (LONGINT, CARDINAL (VAL (BITSET, 0FFFFH)
- - VAL (BITSET, W16 (a))))
- END BitNot ;
- (* ---------------------------------------------------------------- *)
- (* errors *)
- (* ---------------------------------------------------------------- *)
- PROCEDURE Err (n : CARDINAL) ;
- BEGIN
- IF NOT abortFac THEN
- abortFac := TRUE ;
- errNo := n ;
- txerrPos := srcPos
- END
- END Err ;
- PROCEDURE OK () : BOOLEAN ;
- BEGIN
- RETURN NOT abortFac
- END OK ;
- (* ---------------------------------------------------------------- *)
- (* emission : ebyte / eword / ecall / ejump *)
- (* ---------------------------------------------------------------- *)
- PROCEDURE Ebyte (b : BYTE) ;
- BEGIN
- IF pc >= MaxCode THEN
- Err (EMemOvf)
- ELSE
- cbuf [pc] := b ;
- INC (pc)
- END
- END Ebyte ;
- PROCEDURE Eword (w : CARDINAL) ;
- BEGIN
- Ebyte (VAL (BYTE, w MOD 100H)) ;
- Ebyte (VAL (BYTE, (w DIV 100H) MOD 100H))
- END Eword ;
- PROCEDURE AddPatch (place, target : CARDINAL) ;
- BEGIN
- IF nPatch < MaxPatch THEN
- patches [nPatch].place := place ;
- patches [nPatch].target := target ;
- patches [nPatch].filled := FALSE ;
- INC (nPatch)
- ELSE
- Err (ECompOvf)
- END
- END AddPatch ;
- PROCEDURE SetPatTgt (idx, t : CARDINAL) ;
- BEGIN
- IF idx < nPatch THEN
- patches [idx].target := t
- END
- END SetPatTgt ;
- PROCEDURE EmCall (target : CARDINAL) : CARDINAL ;
- (* E8 rel16 near call; target = 0 => forward (patched later).
- Returns the patch slot, or 0 when resolved directly. *)
- VAR rel, p : CARDINAL ;
- BEGIN
- Ebyte (0E8H) ;
- IF target = 0 THEN
- Eword (0) ;
- p := nPatch ;
- AddPatch (pc - 2, 0) ;
- RETURN p
- END ;
- rel := (target + 10000H - pc) MOD 10000H ;
- Eword (rel) ;
- RETURN 0
- END EmCall ;
- PROCEDURE EmJmpNear (target : CARDINAL) : CARDINAL ;
- (* E9 rel16; target = 0 => forward. Returns patch slot or 0. *)
- VAR rel, p : CARDINAL ;
- BEGIN
- Ebyte (0E9H) ;
- IF target = 0 THEN
- Eword (0) ;
- p := nPatch ;
- AddPatch (pc - 2, 0) ;
- RETURN p
- END ;
- rel := (target + 10000H - pc) MOD 10000H ;
- Eword (rel) ;
- RETURN 0
- END EmJmpNear ;
- PROCEDURE EmJcc (cc : BYTE ; target : CARDINAL) : CARDINAL ;
- (* 0F 8x rel16 near conditional; target = 0 => forward. *)
- VAR rel, p : CARDINAL ;
- BEGIN
- Ebyte (0FH) ;
- Ebyte (cc) ;
- IF target = 0 THEN
- Eword (0) ;
- p := nPatch ;
- AddPatch (pc - 2, 0) ;
- RETURN p
- END ;
- rel := (target + 10000H - pc) MOD 10000H ;
- Eword (rel) ;
- RETURN 0
- END EmJcc ;
- PROCEDURE ResolvePatches () ;
- VAR i : CARDINAL ;
- rel : CARDINAL ;
- BEGIN
- i := 0 ;
- WHILE i < nPatch DO
- IF NOT patches [i].filled THEN
- rel := (patches [i].target + 10000H - (patches [i].place + 2))
- MOD 10000H ;
- cbuf [patches [i].place] := VAL (BYTE, rel MOD 100H) ;
- cbuf [patches [i].place + 1] := VAL (BYTE, (rel DIV 100H) MOD 100H) ;
- patches [i].filled := TRUE
- END ;
- INC (i)
- END
- END ResolvePatches ;
- (* 1-byte const emitters *)
- PROCEDURE EmMovAxi (imm : CARDINAL) ;
- BEGIN
- Ebyte (0B8H) ; Eword (imm)
- END EmMovAxi ;
- PROCEDURE EmMovBpSp () ;
- BEGIN
- Ebyte (8BH) ; Ebyte (0ECH)
- END EmMovBpSp ;
- PROCEDURE EmMovAh0 () ;
- BEGIN
- Ebyte (0B4H) ; Ebyte (0H)
- END EmMovAh0 ;
- PROCEDURE EmMovAxSp () ;
- BEGIN
- Ebyte (8BH) ; Ebyte (04H)
- END EmMovAxSp ;
- PROCEDURE EmMovCxSp () ;
- BEGIN
- Ebyte (8BH) ; Ebyte (0CH)
- END EmMovCxSp ;
- PROCEDURE EmPushAx () ;
- BEGIN
- Ebyte (50H)
- END EmPushAx ;
- PROCEDURE EmPopCx () ;
- BEGIN
- Ebyte (59H)
- END EmPopCx ;
- PROCEDURE EmPopDx () ;
- BEGIN
- Ebyte (5AH)
- END EmPopDx ;
- PROCEDURE EmXchgAxCx () ;
- BEGIN
- Ebyte (93H)
- END EmXchgAxCx ;
- PROCEDURE EmXorAxAx () ;
- BEGIN
- Ebyte (33H) ; Ebyte (0C0H)
- END EmXorAxAx ;
- PROCEDURE EmAddAxCx () ;
- BEGIN
- Ebyte (3H) ; Ebyte (0C1H)
- END EmAddAxCx ;
- PROCEDURE EmSubAxCx () ;
- BEGIN
- Ebyte (2BH) ; Ebyte (0C1H)
- END EmSubAxCx ;
- PROCEDURE EmMulAxCx () ;
- BEGIN
- Ebyte (0F7H) ; Ebyte (0E9H)
- END EmMulAxCx ;
- PROCEDURE EmIDivAxCx () ;
- BEGIN
- Ebyte (99H) ; Ebyte (0F7H) ; Ebyte (0F9H)
- END EmIDivAxCx ;
- PROCEDURE EmAndAxCx () ;
- BEGIN
- Ebyte (23H) ; Ebyte (0C1H)
- END EmAndAxCx ;
- PROCEDURE EmOrAxCx () ;
- BEGIN
- Ebyte (0BH) ; Ebyte (0C1H)
- END EmOrAxCx ;
- PROCEDURE EmNegAx () ;
- BEGIN
- Ebyte (0F7H) ; Ebyte (0D8H)
- END EmNegAx ;
- PROCEDURE EmNotAx () ;
- BEGIN
- Ebyte (0F7H) ; Ebyte (0D0H)
- END EmNotAx ;
- PROCEDURE EmCmpAxCx () ;
- BEGIN
- Ebyte (3BH) ; Ebyte (0C1H)
- END EmCmpAxCx ;
- PROCEDURE EmCmpAxi (imm : CARDINAL) ;
- BEGIN
- Ebyte (03DH) ; Eword (imm)
- END EmCmpAxi ;
- PROCEDURE EmSetcc (cc : BYTE) ;
- BEGIN
- Ebyte (0FH) ; Ebyte (cc) ; Ebyte (0C0H) ;
- EmMovAh0 ()
- END EmSetcc ;
- PROCEDURE EmIncAx () ;
- BEGIN
- Ebyte (40H)
- END EmIncAx ;
- PROCEDURE EmDecAx () ;
- BEGIN
- Ebyte (48H)
- END EmDecAx ;
- PROCEDURE EmLoadVar (local : BOOLEAN ; off, nbytes : CARDINAL) ;
- VAR disp : CARDINAL ;
- BEGIN
- disp := off MOD 100H ;
- IF nbytes = 1 THEN
- IF local THEN
- Ebyte (8AH) ; Ebyte (46H) ; Ebyte (VAL (BYTE, disp))
- ELSE
- Ebyte (0A0H) ; Eword (off)
- END
- ELSE
- IF local THEN
- Ebyte (8BH) ; Ebyte (46H) ; Ebyte (VAL (BYTE, disp))
- ELSE
- Ebyte (0A1H) ; Eword (off)
- END
- END
- END EmLoadVar ;
- PROCEDURE EmStoreVar (local : BOOLEAN ; off, nbytes : CARDINAL) ;
- VAR disp : CARDINAL ;
- BEGIN
- disp := off MOD 100H ;
- IF nbytes = 1 THEN
- IF local THEN
- Ebyte (88H) ; Ebyte (46H) ; Ebyte (VAL (BYTE, disp))
- ELSE
- Ebyte (0A2H) ; Eword (off)
- END
- ELSE
- IF local THEN
- Ebyte (89H) ; Ebyte (46H) ; Ebyte (VAL (BYTE, disp))
- ELSE
- Ebyte (0A3H) ; Eword (off)
- END
- END
- END EmStoreVar ;
- PROCEDURE EmSubSp (n : CARDINAL) ;
- BEGIN
- Ebyte (81H) ; Ebyte (0ECH) ; Eword (n MOD 10000H)
- END EmSubSp ;
- PROCEDURE EmAddSp (n : CARDINAL) ;
- BEGIN
- IF n <= 126 THEN
- Ebyte (83H) ; Ebyte (0C4H) ; Ebyte (VAL (BYTE, n))
- ELSE
- Ebyte (81H) ; Ebyte (0C4H) ; Eword (n MOD 10000H)
- END
- END EmAddSp ;
- PROCEDURE EmPushBp () ;
- BEGIN
- Ebyte (55H)
- END EmPushBp ;
- PROCEDURE EmLeave () ;
- BEGIN
- Ebyte (0C9H)
- END EmLeave ;
- PROCEDURE EmRet () ;
- BEGIN
- Ebyte (0C3H)
- END EmRet ;
- (* ---------------------------------------------------------------- *)
- (* symbol table *)
- (* ---------------------------------------------------------------- *)
- PROCEDURE NameEq (a : ARRAY OF CHAR ; b : ARRAY OF CHAR) : BOOLEAN ;
- VAR i : CARDINAL ;
- BEGIN
- i := 0 ;
- LOOP
- IF i > HIGH (a) THEN
- RETURN FALSE
- END ;
- IF i > HIGH (b) THEN
- RETURN FALSE
- END ;
- IF a [i] # b [i] THEN
- RETURN FALSE
- END ;
- IF a [i] = 0C THEN
- RETURN TRUE
- END ;
- INC (i)
- END
- END NameEq ;
- PROCEDURE CopyStr (VAR dst : ARRAY OF CHAR ; src : ARRAY OF CHAR) ;
- VAR i : CARDINAL ;
- BEGIN
- i := 0 ;
- LOOP
- IF i > HIGH (dst) THEN
- dst [HIGH (dst)] := 0C ;
- RETURN
- END ;
- IF i > HIGH (src) THEN
- dst [i] := 0C ;
- RETURN
- END ;
- dst [i] := src [i] ;
- IF src [i] = 0C THEN
- RETURN
- END ;
- INC (i)
- END
- END CopyStr ;
- PROCEDURE CopyWord (name : ARRAY OF CHAR) ;
- (* stash current word into global wrd (uppercased) *)
- VAR i : CARDINAL ;
- BEGIN
- i := 0 ;
- LOOP
- IF i > HIGH (name) THEN
- wrd [i] := 0C ;
- RETURN
- END ;
- IF i > MaxName THEN
- wrd [MaxName] := 0C ;
- RETURN
- END ;
- IF name [i] = 0C THEN
- wrd [i] := 0C ;
- RETURN
- END ;
- wrd [i] := Upper (name [i]) ;
- INC (i)
- END
- END CopyWord ;
- PROCEDURE SaveWord (VAR dst : ARRAY OF CHAR) ;
- (* copy wrd into dst *)
- VAR i : CARDINAL ;
- BEGIN
- i := 0 ;
- LOOP
- IF i > HIGH (dst) THEN
- dst [HIGH (dst)] := 0C ;
- RETURN
- END ;
- IF i > MaxName THEN
- dst [MaxName] := 0C ;
- RETURN
- END ;
- dst [i] := wrd [i] ;
- IF wrd [i] = 0C THEN
- RETURN
- END ;
- INC (i)
- END
- END SaveWord ;
- PROCEDURE NumToName (n : CARDINAL ; VAR dst : ARRAY OF CHAR) ;
- VAR buf : ARRAY [0..9] OF CHAR ;
- i, j : CARDINAL ;
- BEGIN
- IF n = 0 THEN
- dst [0] := '0' ;
- dst [1] := 0C ;
- RETURN
- END ;
- i := 0 ;
- WHILE n > 0 DO
- IF i <= 9 THEN
- buf [i] := CHR (ORD ('0') + (n MOD 10)) ;
- INC (i)
- END ;
- n := n DIV 10
- END ;
- j := 0 ;
- WHILE i > 0 DO
- DEC (i) ;
- IF j <= HIGH (dst) THEN
- dst [j] := buf [i] ;
- INC (j)
- END
- END ;
- IF j <= HIGH (dst) THEN
- dst [j] := 0C
- END
- END NumToName ;
- PROCEDURE NewSym (name : ARRAY OF CHAR ; tag : CARDINAL ;
- cls, size, elem, off : CARDINAL ; v : LONGINT ;
- local : BOOLEAN) : CARDINAL ;
- VAR e : SymEntry ;
- BEGIN
- IF symTop >= MaxSym THEN
- Err (ECompOvf) ;
- RETURN 0
- END ;
- CopyWord (name) ;
- CopyStr (e.name, wrd) ;
- e.tag := tag ;
- e.cls := cls ;
- e.size := size ;
- e.elem := elem ;
- e.off := off ;
- e.lval := v ;
- e.level := lexnest ;
- e.local := local ;
- e.resvar := 0 ;
- e.goPos := 0 ;
- e.defnd := FALSE ;
- e.fwd := FALSE ;
- symtab [symTop] := e ;
- INC (symTop) ;
- RETURN symTop - 1
- END NewSym ;
- PROCEDURE Search (nm : ARRAY OF CHAR ; VAR idx : CARDINAL) : BOOLEAN ;
- (* find nm among symbols visible at the current lexical level *)
- VAR p : CARDINAL ;
- BEGIN
- CopyWord (nm) ;
- p := symTop ;
- WHILE p > 0 DO
- DEC (p) ;
- IF symtab [p].level <= lexnest THEN
- IF NameEq (symtab [p].name, wrd) THEN
- idx := p ;
- RETURN TRUE
- END
- END
- END ;
- RETURN FALSE
- END Search ;
- PROCEDURE DupTest (nm : ARRAY OF CHAR) ;
- VAR i : CARDINAL ;
- BEGIN
- IF Search (nm, i) THEN
- Err (EUnknown)
- END
- END DupTest ;
- (* ---------------------------------------------------------------- *)
- (* lexer *)
- (* ---------------------------------------------------------------- *)
- PROCEDURE InitKeys () ;
- VAR i : CARDINAL ;
- BEGIN
- FOR i := 0 TO 42 DO
- kTk [i] := 0 ;
- kName [i] [0] := 0C
- END ;
- kName [1] := "PROGRAM" ; kTk [1] := TkProgram ;
- kName [2] := "BEGIN" ; kTk [2] := TkBegin ;
- kName [3] := "END" ; kTk [3] := TkEnd ;
- kName [4] := "IF" ; kTk [4] := TkIf ;
- kName [5] := "THEN" ; kTk [5] := TkThen ;
- kName [6] := "ELSE" ; kTk [6] := TkElse ;
- kName [7] := "WHILE" ; kTk [7] := TkWhile ;
- kName [8] := "DO" ; kTk [8] := TkDo ;
- kName [9] := "REPEAT" ; kTk [9] := TkRepeat ;
- kName [10] := "UNTIL" ; kTk [10] := TkUntil ;
- kName [11] := "FOR" ; kTk [11] := TkFor ;
- kName [12] := "TO" ; kTk [12] := TkTo ;
- kName [13] := "DOWNTO" ; kTk [13] := TkDownto ;
- kName [14] := "CASE" ; kTk [14] := TkCase ;
- kName [15] := "OF" ; kTk [15] := TkOf ;
- kName [16] := "GOTO" ; kTk [16] := TkGoto ;
- kName [17] := "EXIT" ; kTk [17] := TkExit ;
- kName [18] := "WITH" ; kTk [18] := TkWith ;
- kName [19] := "VAR" ; kTk [19] := TkVar ;
- kName [20] := "CONST" ; kTk [20] := TkConst ;
- kName [21] := "TYPE" ; kTk [21] := TkType ;
- kName [22] := "LABEL" ; kTk [22] := TkLabel ;
- kName [23] := "PROCEDURE" ; kTk [23] := TkProcedure ;
- kName [24] := "FUNCTION" ; kTk [24] := TkFunction ;
- kName [25] := "NIL" ; kTk [25] := TkNil ;
- kName [26] := "AND" ; kTk [26] := TkAnd ;
- kName [27] := "OR" ; kTk [27] := TkOr ;
- kName [28] := "NOT" ; kTk [28] := TkNot ;
- kName [29] := "DIV" ; kTk [29] := TkDiv ;
- kName [30] := "MOD" ; kTk [30] := TkMod ;
- kName [31] := "IN" ; kTk [31] := TkIn ;
- kName [32] := "FILE" ; kTk [32] := TkFile ;
- kName [33] := "TEXT" ; kTk [33] := TkText ;
- kName [34] := "RECORD" ; kTk [34] := TkRecord ;
- kName [35] := "ARRAY" ; kTk [35] := TkArray ;
- kName [36] := "SET" ; kTk [36] := TkSet ;
- kName [37] := "PACKED" ; kTk [37] := TkPacked ;
- kName [38] := "FORWARD" ; kTk [38] := TkForward ;
- kName [39] := "EXTERNAL" ; kTk [39] := TkExternal ;
- kName [40] := "ABSOLUTE" ; kTk [40] := TkAbsolute ;
- kName [41] := "OVERLAY" ; kTk [41] := TkOverlay ;
- kName [42] := "STRING" ; kTk [42] := TkString
- END InitKeys ;
- PROCEDURE IsBlank (ch : CHAR) : BOOLEAN ;
- BEGIN
- RETURN (ch = ' ') OR (ORD (ch) = 09H) OR (ORD (ch) = 0DH) OR (ORD (ch) = 0AH) OR (ORD (ch) = 0CH)
- END IsBlank ;
- PROCEDURE Skip () ;
- (* blanks, comments { } and (* *), compiler directives {$ } / (*$ *)
- letter + sign toggles rng/chk *)
- VAR ch : CHAR ;
- letter : CHAR ;
- BEGIN
- WHILE NOT abortFac DO
- WHILE IsBlank (CurCh ()) DO
- ch := GetCh ()
- END ;
- IF CurCh () = '{' THEN
- ch := GetCh () ;
- IF CurCh () = '$' THEN
- ch := GetCh () ;
- letter := GetCh () ;
- ch := GetCh () ;
- IF ch = '+' THEN
- IF letter = 'R' THEN dirs.rng := TRUE END ;
- IF letter = 'I' THEN dirs.chk := TRUE END
- ELSIF ch = '-' THEN
- IF letter = 'R' THEN dirs.rng := FALSE END ;
- IF letter = 'I' THEN dirs.chk := FALSE END
- END
- END ;
- WHILE (CurCh () # '}') AND (CurCh () # 0C) DO
- ch := GetCh ()
- END ;
- IF CurCh () = '}' THEN
- ch := GetCh ()
- END
- ELSIF (CurCh () = '(') AND (PeekAhead (1) = '*') THEN
- ch := GetCh () ;
- ch := GetCh () ;
- IF CurCh () = '$' THEN
- ch := GetCh () ;
- letter := GetCh () ;
- ch := GetCh () ;
- IF ch = '+' THEN
- IF letter = 'R' THEN dirs.rng := TRUE END
- ELSIF ch = '-' THEN
- IF letter = 'R' THEN dirs.rng := FALSE END
- END
- END ;
- LOOP
- IF (CurCh () = '*') AND (PeekAhead (1) = ')') THEN
- ch := GetCh () ;
- ch := GetCh () ;
- EXIT
- END ;
- IF CurCh () = 0C THEN
- EXIT
- END ;
- ch := GetCh ()
- END
- ELSE
- RETURN
- END
- END
- END Skip ;
- PROCEDURE GetWord () ;
- (* read identifier into wrd (uppercased); next char must be alpha *)
- VAR i : CARDINAL ;
- ch : CHAR ;
- BEGIN
- i := 0 ;
- ch := GetCh () ;
- LOOP
- IF i > MaxName THEN
- wrd [MaxName] := 0C ;
- RETURN
- END ;
- wrd [i] := Upper (ch) ;
- INC (i) ;
- ch := CurCh () ;
- IF NOT AlphaNum (ch) THEN
- wrd [i] := 0C ;
- RETURN
- END ;
- ch := GetCh ()
- END
- END GetWord ;
- PROCEDURE WddTok () : CARDINAL ;
- (* map wrd -> keyword token *)
- VAR i : CARDINAL ;
- BEGIN
- i := 1 ;
- WHILE i <= 42 DO
- IF kName [i] [0] # 0C THEN
- IF NameEq (wrd, kName [i]) THEN
- RETURN kTk [i]
- END
- END ;
- INC (i)
- END ;
- RETURN TkNone
- END WddTok ;
- PROCEDURE KwAhead (word : ARRAY OF CHAR) : BOOLEAN ;
- (* does the next token (past blanks/comments) equal the keyword 'word',
- without consuming it? srcPos is saved and restored. *)
- VAR save : CARDINAL ;
- k : BOOLEAN ;
- BEGIN
- save := srcPos ;
- Skip () ;
- k := FALSE ;
- IF Alpha (CurCh ()) THEN
- GetWord () ;
- k := NameEq (wrd, word)
- END ;
- srcPos := save ;
- RETURN k
- END KwAhead ;
- PROCEDURE PeekKw (VAR tok : CARDINAL) ;
- (* peek at the next keyword token without consuming it *)
- VAR i : CARDINAL ;
- BEGIN
- tok := TkNone ;
- i := 1 ;
- WHILE i <= 42 DO
- IF kName [i] [0] # 0C THEN
- IF KwAhead (kName [i]) THEN
- tok := kTk [i] ;
- RETURN
- END
- END ;
- INC (i)
- END
- END PeekKw ;
- PROCEDURE MatchKey (VAR tok : CARDINAL) : BOOLEAN ;
- (* skip; if next symbol is a word, read it into wrd and set its token.
- Returns TRUE when a word was read (tok = TkNone for plain ids). *)
- BEGIN
- tok := TkNone ;
- Skip () ;
- IF NOT Alpha (CurCh ()) THEN
- RETURN FALSE
- END ;
- GetWord () ;
- tok := WddTok () ;
- RETURN TRUE
- END MatchKey ;
- PROCEDURE MatchDelim (ch : CHAR) : BOOLEAN ;
- BEGIN
- Skip () ;
- IF CurCh () = ch THEN
- DropCh (GetCh ()) ;
- RETURN TRUE
- END ;
- RETURN FALSE
- END MatchDelim ;
- PROCEDURE MatchAssign () : BOOLEAN ;
- BEGIN
- Skip () ;
- IF (CurCh () = ':') AND (PeekAhead (1) = '=') THEN
- DropCh (GetCh ()) ;
- DropCh (GetCh ()) ;
- RETURN TRUE
- END ;
- RETURN FALSE
- END MatchAssign ;
- PROCEDURE MatchRange () : BOOLEAN ;
- BEGIN
- Skip () ;
- IF (CurCh () = '.') AND (PeekAhead (1) = '.') THEN
- DropCh (GetCh ()) ;
- DropCh (GetCh ()) ;
- RETURN TRUE
- END ;
- RETURN FALSE
- END MatchRange ;
- PROCEDURE ExpectDelim (ch : CHAR ; n : CARDINAL) ;
- BEGIN
- Skip () ;
- IF CurCh () = ch THEN
- DropCh (GetCh ())
- ELSE
- Err (n)
- END
- END ExpectDelim ;
- PROCEDURE HexVal (ch : CHAR) : CARDINAL ;
- BEGIN
- IF (ch >= '0') AND (ch <= '9') THEN
- RETURN ORD (ch) - ORD ('0')
- ELSIF (ch >= 'A') AND (ch <= 'F') THEN
- RETURN ORD (ch) - ORD ('A') + 10
- END ;
- RETURN ORD (ch) - ORD ('a') + 10
- END HexVal ;
- PROCEDURE RdIntConst (VAR v : LONGINT) ;
- (* bare integer constant; current char is digit or '$' *)
- VAR acc : LONGINT ;
- BEGIN
- acc := 0 ;
- IF CurCh () = '$' THEN
- DropCh (GetCh ()) ;
- WHILE IsHexCh (CurCh ()) DO
- acc := acc * 16 + VAL (LONGINT, HexVal (CurCh ())) ;
- DropCh (GetCh ())
- END
- ELSE
- WHILE Digit (CurCh ()) DO
- acc := acc * 10 + VAL (LONGINT, ORD (CurCh ()) - ORD ('0')) ;
- DropCh (GetCh ())
- END
- END ;
- v := acc
- END RdIntConst ;
- PROCEDURE RdConst (VAR v : LONGINT ; VAR cls : CARDINAL ;
- VAR isStr : BOOLEAN) ;
- (* scalar or string constant. String values (isStr) can only be
- rejected with ENoLib by the caller. *)
- CONST q = AposC ;
- BEGIN
- isStr := FALSE ;
- cls := TScalar ;
- v := 0 ;
- Skip () ;
- IF CurCh () = '$' THEN
- RdIntConst (v) ;
- cls := TScalar
- ELSIF Digit (CurCh ()) THEN
- RdIntConst (v) ;
- IF (CurCh () = '.') AND (Digit (PeekAhead (1))) THEN
- cls := TReal ;
- DropCh (GetCh ())
- END ;
- IF (CurCh () = 'E') OR (CurCh () = 'e') THEN
- cls := TReal ;
- DropCh (GetCh ())
- END ;
- IF cls = TReal THEN
- WHILE AlphaNum (CurCh ()) OR (CurCh () = '.') OR (CurCh () = '-')
- OR (CurCh () = '+') DO
- DropCh (GetCh ())
- END
- END
- ELSIF ORD (CurCh ()) = q THEN
- DropCh (GetCh ()) ;
- IF ORD (CurCh ()) = q THEN
- DropCh (GetCh ()) ;
- v := VAL (LONGINT, q) ;
- cls := TScalar
- ELSIF (CurCh () = 0C) OR ((ORD (CurCh ()) = 0DH)) OR ((ORD (CurCh ()) = 0AH)) THEN
- Err (EUnknown)
- ELSE
- v := VAL (LONGINT, ORD (GetCh ())) ;
- cls := TScalar ;
- IF ORD (CurCh ()) = q THEN
- DropCh (GetCh ())
- ELSE
- isStr := TRUE ;
- cls := TString ;
- WHILE (ORD (CurCh ()) # q) AND (CurCh () # 0C) DO
- IF ORD (PeekAhead (1)) = q THEN
- DropCh (GetCh ()) ; DropCh (GetCh ())
- ELSE
- DropCh (GetCh ())
- END
- END ;
- IF ORD (CurCh ()) = q THEN
- DropCh (GetCh ())
- END
- END
- END
- ELSE
- Err (EUnknown)
- END
- END RdConst ;
- (* ---------------------------------------------------------------- *)
- (* forward declarations *)
- (* ---------------------------------------------------------------- *)
- PROCEDURE ParseExpr (VAR r : ERes) ; FORWARD ;
- PROCEDURE ParseAdd (VAR r : ERes) ; FORWARD ;
- PROCEDURE ParseMul (VAR r : ERes) ; FORWARD ;
- PROCEDURE ParseNeg (VAR r : ERes) ; FORWARD ;
- PROCEDURE ParseAtom (VAR r : ERes) ; FORWARD ;
- PROCEDURE ParseType (VAR cls, size, elem : CARDINAL) ; FORWARD ;
- PROCEDURE Statmnt () ; FORWARD ;
- PROCEDURE ParseCall (idx : CARDINAL) ; FORWARD ;
- PROCEDURE ParseCallArgs (idx : CARDINAL) ; FORWARD ;
- PROCEDURE EmCallMost (idx, nk : CARDINAL) ; FORWARD ;
- (* ---------------------------------------------------------------- *)
- (* expressions (TPSRC9) *)
- (* ---------------------------------------------------------------- *)
- PROCEDURE LoadAtom (VAR r : ERes) ;
- (* load value of r into AX (folding constants) *)
- BEGIN
- IF r.kind = 0 THEN
- EmMovAxi (W16 (r.imm)) ;
- r.kind := 2
- ELSIF r.kind = 1 THEN
- IF symtab [r.idx].size > 2 THEN
- Err (ENoLib)
- ELSE
- EmLoadVar (symtab [r.idx].local,
- (symtab [r.idx].off + r.boff) MOD 10000H,
- symtab [r.idx].size) ;
- IF symtab [r.idx].size = 1 THEN
- EmMovAh0 ()
- END ;
- r.kind := 2
- END
- END
- END LoadAtom ;
- PROCEDURE ParseSub (VAR r : ERes) ;
- (* consume '[' constExpr ']' while present, folding the index into the
- base offset (constant indexing only) *)
- VAR t : ERes ;
- BEGIN
- LOOP
- Skip () ;
- IF CurCh () # '[' THEN
- RETURN
- END ;
- DropCh (GetCh ()) ;
- ParseExpr (t) ;
- IF OK () THEN
- IF t.kind # 0 THEN
- Err (ENoLib) ;
- RETURN
- END ;
- IF symtab [r.idx].cls = TArray THEN
- r.boff := W16 (VAL (LONGINT, r.boff)
- + t.imm * VAL (LONGINT, symtab [r.idx].elem))
- ELSE
- Err (ESimpType) ;
- RETURN
- END
- END ;
- ExpectDelim (']', ENoSemi)
- END
- END ParseSub ;
- PROCEDURE ParseVar (VAR r : ERes) ;
- (* name [ '[' constExpr ']' ]* ; a function name maps to its result var *)
- VAR idx : CARDINAL ;
- BEGIN
- IF NOT Search (wrd, idx) THEN
- Err (EUnknown) ;
- RETURN
- END ;
- r.idx := idx ;
- r.kind := 1 ;
- r.boff := 0 ;
- r.cls := symtab [idx].cls ;
- IF symtab [idx].tag = KFunc THEN
- idx := symtab [idx].resvar ;
- r.idx := idx ;
- r.cls := symtab [idx].cls
- ELSIF (symtab [idx].tag # KVar) AND (symtab [idx].tag # KType) THEN
- Err (EUnknown) ;
- RETURN
- END ;
- ParseSub (r)
- END ParseVar ;
- PROCEDURE ConstAdd (a, b : LONGINT) : LONGINT ;
- BEGIN
- RETURN VAL (LONGINT, W16 (a + b))
- END ConstAdd ;
- PROCEDURE ConstSub (a, b : LONGINT) : LONGINT ;
- BEGIN
- RETURN VAL (LONGINT, W16 (a - b))
- END ConstSub ;
- PROCEDURE ConstMul (a, b : LONGINT) : LONGINT ;
- BEGIN
- RETURN VAL (LONGINT, W16 (a * b))
- END ConstMul ;
- PROCEDURE EmMoveAxDx () ;
- BEGIN
- Ebyte (92H)
- END EmMoveAxDx ;
- PROCEDURE BinOpEmit (op : CARDINAL ; left, right : ERes ; VAR res : ERes) ;
- (* binary operation at one precedence level; folds constant operands *)
- VAR f : LONGINT ;
- okc : BOOLEAN ;
- BEGIN
- IF op = TkAnd THEN
- IF (left.kind = 0) AND (right.kind = 0) THEN
- res.kind := 0 ;
- res.imm := BitAnd (left.imm, right.imm) ;
- res.cls := TBool ;
- RETURN
- END ;
- LoadAtom (left) ; EmPushAx () ;
- LoadAtom (right) ; EmPopCx () ;
- EmAndAxCx () ;
- res.kind := 2 ; res.cls := TBool ;
- RETURN
- END ;
- IF op = TkOr THEN
- IF (left.kind = 0) AND (right.kind = 0) THEN
- res.kind := 0 ;
- res.imm := BitOr (left.imm, right.imm) ;
- res.cls := TBool ;
- RETURN
- END ;
- LoadAtom (left) ; EmPushAx () ;
- LoadAtom (right) ; EmPopCx () ;
- EmOrAxCx () ;
- res.kind := 2 ; res.cls := TBool ;
- RETURN
- END ;
- IF (left.kind = 0) AND (right.kind = 0) THEN
- okc := FALSE ;
- CASE op OF
- 1 : f := ConstAdd (left.imm, right.imm) ; okc := TRUE ;
- | 2 : f := ConstSub (left.imm, right.imm) ; okc := TRUE ;
- | 3 : f := ConstMul (left.imm, right.imm) ; okc := TRUE ;
- | TkDiv : okc := (right.imm # 0) AND (right.imm > 0)
- AND (left.imm >= 0) ;
- IF okc THEN f := left.imm DIV right.imm END ;
- | TkMod : okc := (right.imm # 0) AND (right.imm > 0)
- AND (left.imm >= 0) ;
- IF okc THEN f := left.imm MOD right.imm END ;
- ELSE
- okc := FALSE
- END ;
- IF okc THEN
- res.kind := 0 ;
- res.imm := VAL (LONGINT, W16 (f)) ;
- res.cls := left.cls ;
- RETURN
- ELSIF op = TkDiv THEN
- Err (EConstRange) ;
- RETURN
- END
- END ;
- LoadAtom (left) ; EmPushAx () ;
- LoadAtom (right) ; EmPopCx () ;
- EmXchgAxCx () ;
- CASE op OF
- 1 : EmAddAxCx ;
- | 2 : EmSubAxCx ;
- | 3 : EmMulAxCx ;
- | TkDiv : EmIDivAxCx ;
- | TkMod : EmIDivAxCx ; EmMoveAxDx ;
- ELSE
- Err (ETypeErr)
- END ;
- res.kind := 2 ;
- res.cls := left.cls
- END BinOpEmit ;
- PROCEDURE ConstCmp (op : CARDINAL ; a, b : LONGINT ; VAR f : LONGINT)
- : BOOLEAN ;
- VAR a16, b16 : CARDINAL ;
- BEGIN
- a16 := W16 (a) ;
- b16 := W16 (b) ;
- f := 0 ;
- CASE op OF
- 1 : f := VAL (LONGINT, ORD (a16 = b16)) ;
- | 2 : f := VAL (LONGINT, ORD (a16 # b16)) ;
- | 3 : f := VAL (LONGINT, ORD (a16 < b16)) ;
- | 4 : f := VAL (LONGINT, ORD (a16 >= b16)) ;
- | 5 : f := VAL (LONGINT, ORD (a16 > b16)) ;
- | 6 : f := VAL (LONGINT, ORD (a16 <= b16)) ;
- ELSE
- RETURN FALSE
- END ;
- RETURN TRUE
- END ConstCmp ;
- PROCEDURE ParseCmp (VAR r : ERes) ;
- (* "=" | "<>" | "<" | "<=" | ">" | ">=" *)
- VAR op : CARDINAL ;
- left, right : ERes ;
- f : LONGINT ;
- BEGIN
- ParseAdd (r) ;
- LOOP
- op := 0 ;
- Skip () ;
- IF CurCh () = '=' THEN
- op := 1 ; DropCh (GetCh ())
- ELSIF (CurCh () = '<') AND (PeekAhead (1) = '>') THEN
- op := 2 ; DropCh (GetCh ()) ; DropCh (GetCh ())
- ELSIF CurCh () = '<' THEN
- IF PeekAhead (1) = '=' THEN
- op := 6 ; DropCh (GetCh ()) ; DropCh (GetCh ())
- ELSE
- op := 3 ; DropCh (GetCh ())
- END
- ELSIF CurCh () = '>' THEN
- IF PeekAhead (1) = '=' THEN
- op := 5 ; DropCh (GetCh ()) ; DropCh (GetCh ())
- ELSE
- op := 4 ; DropCh (GetCh ())
- END
- END ;
- IF op = 0 THEN
- RETURN
- END ;
- left := r ;
- ParseAdd (right) ;
- IF (left.kind = 0) AND (right.kind = 0) THEN
- IF ConstCmp (op, left.imm, right.imm, f) THEN
- r.kind := 0 ;
- r.imm := f ;
- r.cls := TBool
- ELSE
- r.kind := 0 ;
- r.imm := 0 ;
- r.cls := TBool
- END
- ELSE
- LoadAtom (left) ; EmPushAx () ;
- LoadAtom (right) ; EmPopCx () ;
- EmXchgAxCx () ;
- EmCmpAxCx () ;
- CASE op OF
- 1 : EmSetcc (94H) ;
- | 2 : EmSetcc (95H) ;
- | 3 : EmSetcc (9CH) ;
- | 4 : EmSetcc (9DH) ;
- | 5 : EmSetcc (9FH) ;
- | 6 : EmSetcc (9EH)
- END ;
- r.kind := 2 ;
- r.cls := TBool
- END
- END
- END ParseCmp ;
- PROCEDURE ParseAdd (VAR r : ERes) ;
- VAR op : CARDINAL ;
- left, right : ERes ;
- BEGIN
- ParseMul (r) ;
- LOOP
- op := 0 ;
- Skip () ;
- IF CurCh () = '+' THEN
- op := 1 ; DropCh (GetCh ())
- ELSIF CurCh () = '-' THEN
- op := 2 ; DropCh (GetCh ())
- ELSIF KwAhead ("OR") THEN
- GetWord () ;
- op := TkOr
- ELSE
- RETURN
- END ;
- left := r ;
- ParseMul (right) ;
- BinOpEmit (op, left, right, r)
- END
- END ParseAdd ;
- PROCEDURE ParseMul (VAR r : ERes) ;
- VAR op : CARDINAL ;
- left, right : ERes ;
- BEGIN
- ParseNeg (r) ;
- LOOP
- op := 0 ;
- Skip () ;
- IF CurCh () = '*' THEN
- op := 1 ; DropCh (GetCh ())
- ELSIF CurCh () = '/' THEN
- op := 2 ; DropCh (GetCh ()) ; Err (ENoLib)
- ELSIF KwAhead ("DIV") THEN
- GetWord () ; op := TkDiv
- ELSIF KwAhead ("MOD") THEN
- GetWord () ; op := TkMod
- ELSIF KwAhead ("AND") THEN
- GetWord () ; op := TkAnd
- ELSE
- RETURN
- END ;
- IF op = 2 THEN
- RETURN
- END ;
- left := r ;
- ParseNeg (right) ;
- BinOpEmit (op, left, right, r)
- END
- END ParseMul ;
- PROCEDURE ParseNeg (VAR r : ERes) ;
- BEGIN
- Skip () ;
- IF CurCh () = '+' THEN
- DropCh (GetCh ()) ;
- ParseNeg (r) ;
- RETURN
- ELSIF CurCh () = '-' THEN
- DropCh (GetCh ()) ;
- ParseNeg (r) ;
- IF r.kind = 0 THEN
- r.imm := VAL (LONGINT, W16 (0 - r.imm))
- ELSE
- LoadAtom (r) ;
- EmNegAx () ;
- r.kind := 2
- END ;
- RETURN
- ELSIF KwAhead ("NOT") THEN
- GetWord () ;
- ParseNeg (r) ;
- IF r.kind = 0 THEN
- r.imm := BitNot (r.imm)
- ELSE
- LoadAtom (r) ;
- EmNotAx () ;
- r.kind := 2
- END ;
- RETURN
- END ;
- ParseAtom (r)
- END ParseNeg ;
- PROCEDURE ParseAtom (VAR r : ERes) ;
- (* const | variable | func(params) | '(' expr ')' *)
- VAR idx : CARDINAL ;
- strf : BOOLEAN ;
- BEGIN
- Skip () ;
- IF CurCh () = '(' THEN
- DropCh (GetCh ()) ;
- ParseExpr (r) ;
- ExpectDelim (')', ENoSemi) ;
- RETURN
- END ;
- IF (CurCh () = '$') OR (Digit (CurCh ())) OR (ORD (CurCh ()) = AposC) THEN
- RdConst (r.imm, r.cls, strf) ;
- IF r.cls = TReal THEN
- Err (ENoLib) ;
- r.kind := 2 ;
- RETURN
- END ;
- IF strf THEN
- Err (ENoLib) ;
- r.kind := 2 ;
- RETURN
- END ;
- r.kind := 0 ;
- RETURN
- END ;
- IF NOT Alpha (CurCh ()) THEN
- Err (EUnknown) ;
- RETURN
- END ;
- GetWord () ;
- IF NOT Search (wrd, idx) THEN
- Err (EUnknown) ;
- RETURN
- END ;
- IF symtab [idx].tag = KConst THEN
- r.kind := 0 ;
- r.imm := symtab [idx].lval ;
- r.cls := symtab [idx].cls ;
- RETURN
- ELSIF symtab [idx].tag = KFunc THEN
- ParseCall (idx) ;
- r.kind := 2 ;
- r.cls := symtab [idx].cls ;
- RETURN
- ELSIF (symtab [idx].tag = KVar) OR (symtab [idx].tag = KType) THEN
- ParseVar (r) ;
- r.boff := 0 ;
- RETURN
- ELSE
- Err (EUnknown)
- END
- END ParseAtom ;
- PROCEDURE AddPend (kind, who, place : CARDINAL) ;
- BEGIN
- IF nPend < MaxPend THEN
- pend [nPend].kind := kind ;
- pend [nPend].who := who ;
- pend [nPend].place := place ;
- INC (nPend)
- ELSE
- Err (ECompOvf)
- END
- END AddPend ;
- PROCEDURE EmCallMost (idx, nk : CARDINAL) ;
- (* emit the call to sym 'idx' and clean up nk value arguments *)
- VAR p : CARDINAL ;
- BEGIN
- IF symtab [idx].defnd THEN
- DropC (EmCall (symtab [idx].goPos))
- ELSE
- p := EmCall (0) ;
- AddPend (1, idx, p)
- END ;
- IF nk > 0 THEN
- EmAddSp (2 * nk)
- END
- END EmCallMost ;
- PROCEDURE ParseCallArgs (idx : CARDINAL) ;
- (* '(' already consumed: read args ')' then call. Arguments are pushed
- right-to-left so the first-declared parameter lands at BP+4. *)
- VAR args : ARRAY [0..15] OF ERes ;
- nArgs, i : CARDINAL ;
- BEGIN
- nArgs := 0 ;
- IF CurCh () = ')' THEN
- DropCh (GetCh ())
- ELSE
- LOOP
- IF nArgs >= 16 THEN
- Err (ECompOvf) ;
- EXIT
- END ;
- ParseExpr (args [nArgs]) ;
- INC (nArgs) ;
- IF NOT MatchDelim (',') THEN
- EXIT
- END
- END ;
- ExpectDelim (')', ENoSemi)
- END ;
- i := nArgs ;
- WHILE i > 0 DO
- DEC (i) ;
- LoadAtom (args [i]) ;
- EmPushAx ()
- END ;
- EmCallMost (idx, nArgs)
- END ParseCallArgs ;
- PROCEDURE ParseCall (idx : CARDINAL) ;
- (* procedure/function call; '(' optional *)
- VAR args : ARRAY [0..15] OF ERes ;
- nArgs, i : CARDINAL ;
- BEGIN
- nArgs := 0 ;
- IF MatchDelim ('(') THEN
- IF CurCh () # ')' THEN
- LOOP
- IF nArgs >= 16 THEN
- Err (ECompOvf) ;
- EXIT
- END ;
- ParseExpr (args [nArgs]) ;
- INC (nArgs) ;
- IF NOT MatchDelim (',') THEN
- EXIT
- END
- END ;
- ExpectDelim (')', ENoSemi)
- ELSE
- DropCh (GetCh ())
- END
- END ;
- i := nArgs ;
- WHILE i > 0 DO
- DEC (i) ;
- LoadAtom (args [i]) ;
- EmPushAx ()
- END ;
- EmCallMost (idx, nArgs)
- END ParseCall ;
- PROCEDURE ParseExpr (VAR r : ERes) ;
- BEGIN
- ParseCmp (r)
- END ParseExpr ;
- (* ---------------------------------------------------------------- *)
- (* statements (TPSRC8) *)
- (* ---------------------------------------------------------------- *)
- PROCEDURE ParseLabelStmt () ;
- (* numeric label definition 'n :' *)
- VAR n : CARDINAL ;
- nm : ARRAY [0..9] OF CHAR ;
- idx : CARDINAL ;
- i : CARDINAL ;
- BEGIN
- n := 0 ;
- WHILE Digit (CurCh ()) DO
- n := n * 10 + (ORD (CurCh ()) - ORD ('0')) ;
- DropCh (GetCh ())
- END ;
- ExpectDelim (':', ENoSemi) ;
- NumToName (n, nm) ;
- IF Search (nm, idx) THEN
- IF symtab [idx].tag = KLabel THEN
- symtab [idx].defnd := TRUE ;
- symtab [idx].goPos := pc ;
- i := 0 ;
- WHILE i < nPend DO
- IF (pend [i].kind = 0) AND (pend [i].who = idx) THEN
- SetPatTgt (pend [i].place, pc) ;
- pend [i].kind := 99
- END ;
- INC (i)
- END
- ELSE
- Err (EUnknown)
- END
- ELSE
- idx := NewSym (nm, KLabel, TScalar, 0, 0, 0, 0, FALSE) ;
- symtab [idx].defnd := TRUE ;
- symtab [idx].goPos := pc
- END
- END ParseLabelStmt ;
- PROCEDURE Assignment (r : ERes) ;
- (* ':=' already consumed by the caller; store expression into r *)
- VAR src : ERes ;
- BEGIN
- IF r.kind # 1 THEN
- Err (EUnknown) ;
- RETURN
- END ;
- IF symtab [r.idx].size > 2 THEN
- Err (ENoLib) ;
- RETURN
- END ;
- ParseExpr (src) ;
- LoadAtom (src) ;
- EmStoreVar (symtab [r.idx].local,
- (symtab [r.idx].off + r.boff) MOD 10000H,
- symtab [r.idx].size)
- END Assignment ;
- PROCEDURE Compound () ;
- (* BEGIN statement ';' ... END; END is consumed here *)
- VAR tok : CARDINAL ;
- BEGIN
- LOOP
- PeekKw (tok) ;
- IF tok = TkEnd THEN
- DropB (MatchKey (tok)) ;
- RETURN
- END ;
- Statmnt () ;
- IF NOT OK () THEN
- RETURN
- END ;
- IF NOT MatchDelim (';') THEN
- PeekKw (tok) ;
- IF tok = TkEnd THEN
- DropB (MatchKey (tok)) ;
- RETURN
- END ;
- Err (ENoSemi) ;
- RETURN
- END
- END
- END Compound ;
- PROCEDURE Statmnt () ;
- VAR tok : CARDINAL ;
- idx, i2 : CARDINAL ;
- t, src : ERes ;
- L1, zj, zj2, exj : CARDINAL ;
- lo, hi, v : LONGINT ;
- clso : CARDINAL ;
- i : CARDINAL ;
- nm : ARRAY [0..MaxName] OF CHAR ;
- strf : BOOLEAN ;
- dow : BOOLEAN ;
- BEGIN
- Skip () ;
- IF Digit (CurCh ()) THEN
- ParseLabelStmt () ;
- RETURN
- END ;
- IF NOT Alpha (CurCh ()) THEN
- ExpectDelim (';', ENoSemi) ;
- RETURN
- END ;
- DropB (MatchKey (tok)) ;
- IF tok = TkBegin THEN
- Compound ()
- ELSIF tok = TkIf THEN
- ParseExpr (t) ;
- LoadAtom (t) ;
- EmCmpAxi (0) ;
- zj := EmJcc (84H, 0) ; (* JZ -> else/end *)
- IF NOT (MatchKey (tok) AND (tok = TkThen)) THEN
- Err (ENoSemi)
- END ;
- Statmnt () ;
- IF MatchKey (tok) AND (tok = TkElse) THEN
- exj := EmJmpNear (0) ;
- SetPatTgt (zj, pc) ;
- Statmnt () ;
- SetPatTgt (exj, pc)
- ELSE
- SetPatTgt (zj, pc)
- END
- ELSIF tok = TkWhile THEN
- L1 := pc ;
- ParseExpr (t) ;
- LoadAtom (t) ;
- EmCmpAxi (0) ;
- zj := EmJcc (84H, 0) ; (* JZ -> end *)
- IF NOT (MatchKey (tok) AND (tok = TkDo)) THEN
- Err (ENoSemi)
- END ;
- brkSave [brkN] := exitCnt ;
- loopTy [brkN] := 1 ;
- INC (brkN) ;
- Statmnt () ;
- DEC (brkN) ;
- i := brkSave [brkN] ;
- WHILE i < exitCnt DO
- SetPatTgt (exitPatch [i], pc) ;
- INC (i)
- END ;
- exitCnt := brkSave [brkN] ;
- DropC (EmJmpNear (L1)) ;
- SetPatTgt (zj, pc)
- ELSIF tok = TkRepeat THEN
- L1 := pc ;
- brkSave [brkN] := exitCnt ;
- loopTy [brkN] := 1 ;
- INC (brkN) ;
- Statmnt () ;
- IF NOT (MatchKey (tok) AND (tok = TkUntil)) THEN
- Err (ENoSemi)
- END ;
- ParseExpr (t) ;
- LoadAtom (t) ;
- EmCmpAxi (0) ;
- zj := EmJcc (85H, L1) ; (* JNZ -> body again *)
- DEC (brkN) ;
- i := brkSave [brkN] ;
- WHILE i < exitCnt DO
- SetPatTgt (exitPatch [i], pc) ;
- INC (i)
- END ;
- exitCnt := brkSave [brkN]
- ELSIF tok = TkFor THEN
- (* control variable *)
- IF NOT Alpha (CurCh ()) THEN
- Err (EUnknown) ;
- RETURN
- END ;
- GetWord () ;
- IF NOT Search (wrd, idx) THEN
- Err (EUnknown) ;
- RETURN
- END ;
- IF symtab [idx].size > 2 THEN
- Err (ENoLib) ;
- RETURN
- END ;
- IF NOT MatchAssign () THEN
- Err (ENoSemi)
- END ;
- ParseExpr (src) ;
- LoadAtom (src) ;
- EmStoreVar (symtab [idx].local, symtab [idx].off,
- symtab [idx].size) ;
- IF NOT MatchKey (tok) THEN
- Err (ESimpType) ;
- RETURN
- END ;
- IF (tok = TkTo) OR (tok = TkDownto) THEN
- dow := (tok = TkDownto)
- ELSE
- Err (ESimpType) ;
- RETURN
- END ;
- ParseExpr (t) ;
- LoadAtom (t) ;
- EmPushAx () ; (* loop bound on the stack *)
- IF NOT (MatchKey (tok) AND (tok = TkDo)) THEN
- Err (ENoSemi)
- END ;
- brkSave [brkN] := exitCnt ;
- loopTy [brkN] := 2 ;
- INC (brkN) ;
- L1 := pc ; (* Ltest *)
- Statmnt () ;
- DEC (brkN) ;
- i := brkSave [brkN] ;
- WHILE i < exitCnt DO
- SetPatTgt (exitPatch [i], pc) ;
- INC (i)
- END ;
- exitCnt := brkSave [brkN] ;
- (* test then step: ax = var ; cx = bound (from [sp]) *)
- EmMovCxSp () ;
- EmLoadVar (symtab [idx].local, symtab [idx].off,
- symtab [idx].size) ;
- EmCmpAxCx () ;
- IF dow THEN
- zj := EmJcc (8CH, 0) (* JL -> done *)
- ELSE
- zj := EmJcc (8FH, 0) (* JG -> done *)
- END ;
- EmLoadVar (symtab [idx].local, symtab [idx].off,
- symtab [idx].size) ;
- IF dow THEN
- EmDecAx ()
- ELSE
- EmIncAx ()
- END ;
- EmStoreVar (symtab [idx].local, symtab [idx].off,
- symtab [idx].size) ;
- DropC (EmJmpNear (L1)) ;
- SetPatTgt (zj, pc) ; (* done: drop bound, continue *)
- EmAddSp (2)
- ELSIF tok = TkCase THEN
- ParseExpr (t) ;
- LoadAtom (t) ;
- EmPushAx () ; (* selector on the stack *)
- IF NOT (MatchKey (tok) AND (tok = TkOf)) THEN
- Err (ENoSemi)
- END ;
- caseN := 0 ;
- LOOP
- Skip () ;
- IF MatchDelim (';') THEN
- Skip ()
- END ;
- PeekKw (tok) ;
- IF (tok = TkEnd) OR (tok = TkElse) THEN
- EXIT
- END ;
- (* case label : constant identifier or literal *)
- IF Alpha (CurCh ()) THEN
- GetWord () ;
- IF Search (wrd, i2) AND (symtab [i2].tag = KConst) THEN
- lo := symtab [i2].lval
- ELSE
- Err (EUnknown) ;
- EXIT
- END
- ELSE
- RdConst (lo, clso, strf)
- END ;
- IF MatchRange () THEN
- RdConst (hi, clso, strf)
- ELSE
- hi := lo
- END ;
- ExpectDelim (':', ENoSemi) ;
- EmMovAxSp () ;
- EmCmpAxi (W16 (lo)) ;
- zj := EmJcc (85H, 0) ; (* JNZ -> next *)
- IF hi # lo THEN
- EmCmpAxi (W16 (hi)) ;
- zj2 := EmJcc (85H, 0)
- ELSE
- zj2 := 0
- END ;
- Statmnt () ;
- IF caseN >= 64 THEN
- Err (ECompOvf) ;
- EXIT
- END ;
- caseJmp [caseN] := EmJmpNear (0) ;
- INC (caseN) ;
- SetPatTgt (zj, pc) ;
- IF zj2 # 0 THEN
- SetPatTgt (zj2, pc)
- END
- END ;
- IF tok = TkElse THEN
- DropB (MatchKey (tok)) ;
- Statmnt () ;
- IF NOT (MatchKey (tok) AND (tok = TkEnd)) THEN
- Err (ENoSemi)
- END
- ELSE
- DropB (MatchKey (tok))
- END ;
- EmAddSp (2) ;
- FOR i := 0 TO caseN - 1 DO
- SetPatTgt (caseJmp [i], pc)
- END
- ELSIF tok = TkGoto THEN
- v := 0 ;
- IF Digit (CurCh ()) THEN
- RdIntConst (v) ;
- NumToName (W16 (v), nm) ;
- IF Search (nm, idx) THEN
- IF symtab [idx].tag = KLabel THEN
- IF symtab [idx].defnd THEN
- DropC (EmJmpNear (symtab [idx].goPos))
- ELSE
- zj := EmJmpNear (0) ;
- AddPend (0, idx, zj)
- END
- ELSE
- Err (EUnknown)
- END
- ELSE
- idx := NewSym (nm, KLabel, TScalar, 0, 0, 0, 0, FALSE) ;
- zj := EmJmpNear (0) ;
- AddPend (0, idx, zj)
- END
- ELSE
- Err (EUnknown)
- END
- ELSIF tok = TkExit THEN
- IF brkN = 0 THEN
- Err (EUnknown)
- ELSE
- IF loopTy [brkN - 1] = 2 THEN
- EmAddSp (2) (* drop FOR bound *)
- END ;
- zj := EmJmpNear (0) ;
- IF exitCnt < 64 THEN
- exitPatch [exitCnt] := zj ;
- INC (exitCnt)
- END
- END
- ELSIF tok = TkWith THEN
- Err (ENoLib)
- ELSE
- (* identifier statement: assignment or call *)
- IF NOT Search (wrd, idx) THEN
- Err (EUnknown) ;
- RETURN
- END ;
- IF symtab [idx].tag = KProc THEN
- IF MatchDelim ('(') THEN
- ParseCallArgs (idx)
- ELSE
- ParseCall (idx)
- END ;
- RETURN
- END ;
- IF (symtab [idx].tag = KVar) OR (symtab [idx].tag = KFunc) THEN
- t.idx := idx ;
- t.kind := 1 ;
- t.boff := 0 ;
- t.cls := symtab [idx].cls ;
- IF symtab [idx].tag = KFunc THEN
- t.idx := symtab [idx].resvar ;
- t.cls := symtab [t.idx].cls
- END ;
- ParseSub (t) ;
- IF MatchAssign () THEN
- Assignment (t) ;
- RETURN
- END ;
- Err (ENoSemi) ;
- RETURN
- END ;
- Err (ENoSemi)
- END
- END Statmnt ;
- (* ---------------------------------------------------------------- *)
- (* types and declarations (TPSRC7) *)
- (* ---------------------------------------------------------------- *)
- PROCEDURE ParseType (VAR cls, size, elem : CARDINAL) ;
- VAR tok : CARDINAL ;
- idx : CARDINAL ;
- lo, hi : LONGINT ;
- s2, e2 : CARDINAL ;
- subcls : CARDINAL ;
- strf : BOOLEAN ;
- consumed : BOOLEAN ;
- BEGIN
- cls := TNone ; size := 0 ; elem := 0 ;
- consumed := FALSE ;
- IF Alpha (CurCh ()) THEN
- DropB (MatchKey (tok)) ;
- consumed := TRUE
- ELSE
- tok := TkNone
- END ;
- IF tok = TkArray THEN
- ExpectDelim ('[', ENoSemi) ;
- RdConst (lo, subcls, strf) ;
- IF NOT MatchRange () THEN
- Err (ESimpType)
- END ;
- RdConst (hi, subcls, strf) ;
- ExpectDelim (']', ENoSemi) ;
- IF NOT (MatchKey (tok) AND (tok = TkOf)) THEN
- Err (ENoSemi)
- END ;
- ParseType (cls, s2, e2) ;
- cls := TArray ;
- elem := s2 ;
- size := s2 * (W16 (VAL (LONGINT, W16 (hi))
- - VAL (LONGINT, W16 (lo)) + 1))
- ELSIF tok = TkString THEN
- cls := TString ;
- size := 256 ;
- elem := 1 ;
- IF MatchDelim ('[') THEN
- RdConst (hi, subcls, strf) ;
- ExpectDelim (']', ENoSemi) ;
- size := W16 (hi) + 1
- END
- ELSIF tok = TkSet THEN
- Err (ENoLib) ;
- IF MatchKey (tok) AND (tok = TkOf) THEN
- ParseType (cls, s2, e2)
- END
- ELSIF tok = TkRecord THEN
- Err (ENoLib) ;
- LOOP
- PeekKw (tok) ;
- IF tok = TkEnd THEN
- DropB (MatchKey (tok)) ;
- EXIT
- END ;
- IF CurCh () = 0C THEN
- EXIT
- END ;
- Skip () ;
- IF Alpha (CurCh ()) THEN
- DropCh (GetCh ())
- ELSE
- DropCh (GetCh ())
- END
- END
- ELSIF (tok = TkFile) OR (tok = TkText) THEN
- cls := TFile ;
- size := 0 ;
- elem := 0 ;
- Err (ENoLib)
- ELSE
- IF consumed THEN
- IF Search (wrd, idx) AND (symtab [idx].tag = KType) THEN
- cls := symtab [idx].cls ;
- size := symtab [idx].size ;
- elem := symtab [idx].size
- ELSE
- Err (EUnknown)
- END
- ELSE
- (* subrange lo .. hi *)
- RdConst (lo, subcls, strf) ;
- IF NOT MatchRange () THEN
- Err (ESimpType) ;
- RETURN
- END ;
- RdConst (hi, subcls, strf) ;
- cls := TScalar ;
- size := 2 ;
- elem := 2
- END
- END
- END ParseType ;
- PROCEDURE DefVar () ;
- (* 'name' (',' name)* ':' type [ABSOLUTE addr] ; group repeated until a
- declaration keyword appears *)
- VAR nm : ARRAY [0..MaxName] OF CHAR ;
- cls, size, elem : CARDINAL ;
- tok : CARDINAL ;
- v : LONGINT ;
- off : CARDINAL ;
- BEGIN
- LOOP
- IF NOT Alpha (CurCh ()) THEN
- Err (EUnknown) ;
- RETURN
- END ;
- LOOP
- GetWord () ;
- SaveWord (nm) ;
- DupTest (nm) ;
- IF NOT MatchDelim (':') THEN
- Err (ENoSemi)
- END ;
- ParseType (cls, size, elem) ;
- off := 0 ;
- IF lexnest = 0 THEN
- IF size > 2 THEN
- Err (ENoLib) ;
- RETURN
- END ;
- PeekKw (tok) ;
- IF tok = TkAbsolute THEN
- DropB (MatchKey (tok)) ;
- IF (CurCh () = '$') OR (Digit (CurCh ())) THEN
- RdIntConst (v) ;
- off := W16 (v)
- ELSE
- Err (EUnknown)
- END
- ELSE
- off := dc ;
- dc := dc + size
- END ;
- DropC (NewSym (nm, KVar, cls, size, elem, off, 0, FALSE)) ;
- varspc := varspc + size
- ELSE
- IF size > 2 THEN
- Err (ENoLib) ;
- RETURN
- END ;
- DropC (NewSym (nm, KVar, cls, size, elem, locFree, 0, TRUE)) ;
- locFree := (locFree - size) MOD 10000H ;
- locBytes := locBytes + size
- END ;
- IF NOT MatchDelim (',') THEN
- EXIT
- END
- END ;
- IF NOT MatchDelim (';') THEN
- Err (ENoSemi) ;
- RETURN
- END ;
- PeekKw (tok) ;
- IF tok # TkNone THEN
- RETURN
- END
- END
- END DefVar ;
- PROCEDURE DefConst () ;
- VAR nm : ARRAY [0..MaxName] OF CHAR ;
- v : LONGINT ;
- cls : CARDINAL ;
- isStr : BOOLEAN ;
- tok : CARDINAL ;
- BEGIN
- LOOP
- PeekKw (tok) ;
- IF tok # TkNone THEN
- RETURN
- END ;
- IF NOT Alpha (CurCh ()) THEN
- Err (EUnknown) ;
- RETURN
- END ;
- GetWord () ;
- SaveWord (nm) ;
- DupTest (nm) ;
- ExpectDelim ('=', ENoSemi) ;
- RdConst (v, cls, isStr) ;
- IF isStr THEN
- Err (ENoLib)
- END ;
- DropC (NewSym (nm, KConst, cls, 0, 0, 0, v, FALSE)) ;
- IF NOT MatchDelim (';') THEN
- Err (ENoSemi) ;
- RETURN
- END
- END
- END DefConst ;
- PROCEDURE DefLabelPart () ;
- VAR nm : ARRAY [0..9] OF CHAR ;
- n : CARDINAL ;
- BEGIN
- LOOP
- Skip () ;
- IF NOT Digit (CurCh ()) THEN
- Err (EUnknown) ;
- RETURN
- END ;
- n := 0 ;
- WHILE Digit (CurCh ()) DO
- n := n * 10 + (ORD (CurCh ()) - ORD ('0')) ;
- DropCh (GetCh ())
- END ;
- NumToName (n, nm) ;
- IF NOT Search (nm, n) THEN
- DropC (NewSym (nm, KLabel, TScalar, 0, 0, 0, 0, FALSE))
- END ;
- IF NOT MatchDelim (',') THEN
- IF MatchDelim (';') THEN
- RETURN
- END ;
- Err (ENoSemi) ;
- RETURN
- END
- END
- END DefLabelPart ;
- PROCEDURE IfMatchSemi () ;
- BEGIN
- IF NOT MatchDelim (';') THEN
- Err (ENoSemi)
- END
- END IfMatchSemi ;
- PROCEDURE SymEpi () ;
- (* function result: AX := result var *)
- BEGIN
- IF curIsFunc THEN
- IF OK () THEN
- EmLoadVar (TRUE, symtab [resultVar].off, symtab [resultVar].size)
- END
- END
- END SymEpi ;
- PROCEDURE ProcFunc () ;
- (* PROCEDURE name (params) ; body | FUNCTION name (params) : type ; body *)
- VAR nm : ARRAY [0..MaxName] OF CHAR ;
- idx, old : CARDINAL ;
- tok, tok2 : CARDINAL ;
- parmNm : ARRAY [0..MaxName] OF CHAR ;
- cls, size, elem : CARDINAL ;
- isFunc : BOOLEAN ;
- saveNest, saveLoc, saveRes, saveF : CARDINAL ;
- saveLB, savePO : CARDINAL ;
- i : CARDINAL ;
- BEGIN
- isFunc := curIsFunc ;
- IF NOT Alpha (CurCh ()) THEN
- Err (EUnknown) ;
- RETURN
- END ;
- GetWord () ;
- SaveWord (nm) ;
- IF Search (nm, idx) AND (symtab [idx].tag = KProc)
- AND (symtab [idx].fwd) THEN
- old := idx
- ELSIF Search (nm, idx) THEN
- Err (EUnknown) ;
- RETURN
- ELSE
- old := NewSym (nm, KProc, TNone, 0, 0, 0, 0, FALSE)
- END ;
- IF isFunc THEN
- symtab [old].tag := KFunc
- END ;
- saveNest := lexnest ;
- saveLoc := locFree ;
- saveRes := resultVar ;
- saveF := VAL (CARDINAL, ORD (curIsFunc)) ;
- saveLB := locBytes ;
- savePO := parmOff ;
- INC (lexnest) ;
- locFree := 0FFFEH ;
- locBytes := 0 ;
- parmOff := 4 ;
- IF MatchDelim ('(') THEN
- IF CurCh () # ')' THEN
- LOOP
- IF MatchKey (tok) AND (tok = TkVar) THEN
- (* VAR parameter recorded as value in this milestone *)
- END ;
- IF NOT Alpha (CurCh ()) THEN
- Err (EUnknown) ;
- RETURN
- END ;
- GetWord () ;
- SaveWord (parmNm) ;
- DupTest (parmNm) ;
- ParseType (cls, size, elem) ;
- IF size > 2 THEN
- Err (ENoLib) ;
- RETURN
- END ;
- DropC (NewSym (parmNm, KVar, cls, size, elem, parmOff, 0, TRUE)) ;
- parmOff := parmOff + 2 ;
- IF NOT MatchDelim (',') THEN
- IF MatchDelim (')') THEN
- EXIT
- END ;
- Err (ENoSemi) ;
- EXIT
- END
- END
- ELSE
- DropCh (GetCh ())
- END
- END ;
- IF isFunc THEN
- IF MatchDelim (':') THEN
- ParseType (cls, size, elem)
- ELSE
- cls := TScalar ;
- size := 2 ;
- elem := 2
- END ;
- IF size > 2 THEN
- Err (ENoLib) ;
- RETURN
- END ;
- symtab [old].cls := cls ;
- symtab [old].size := size ;
- resultVar := NewSym (nm, KVar, cls, size, elem, locFree, 0, TRUE) ;
- symtab [old].resvar := resultVar ;
- locFree := (locFree - size) MOD 10000H ;
- locBytes := locBytes + size
- END ;
- IfMatchSemi () ;
- PeekKw (tok2) ;
- IF (tok2 = TkForward) OR (tok2 = TkExternal) THEN
- DropB (MatchKey (tok2)) ;
- symtab [old].fwd := TRUE ;
- symtab [old].defnd := (tok2 = TkExternal) ;
- IfMatchSemi () ;
- lexnest := saveNest ;
- locFree := saveLoc ;
- resultVar := saveRes ;
- curIsFunc := (saveF # 0) ;
- locBytes := saveLB ;
- parmOff := savePO ;
- RETURN
- END ;
- (* body *)
- symtab [old].goPos := pc ;
- symtab [old].defnd := TRUE ;
- EmPushBp () ;
- EmMovBpSp () ;
- DefPart () ; (* nested declarations; stops at BEGIN *)
- IF locBytes > 0 THEN
- EmSubSp (locBytes)
- END ;
- DropC (EmCall (TU_StackChk)) ;
- Statmnt () ; (* body *)
- IF OK () THEN
- SymEpi () ;
- EmLeave () ;
- EmRet ()
- END ;
- (* patch pending forward calls to this proc *)
- i := 0 ;
- WHILE i < nPend DO
- IF (pend [i].kind = 1) AND (pend [i].who = old) THEN
- SetPatTgt (pend [i].place, symtab [old].goPos) ;
- pend [i].kind := 99
- END ;
- INC (i)
- END ;
- lexnest := saveNest ;
- locFree := saveLoc ;
- resultVar := saveRes ;
- curIsFunc := (saveF # 0) ;
- locBytes := saveLB ;
- parmOff := savePO
- END ProcFunc ;
- PROCEDURE DefType () ;
- (* 'name' '=' typeDef ; ... until a declaration keyword appears *)
- VAR nm : ARRAY [0..MaxName] OF CHAR ;
- cls, size, elem : CARDINAL ;
- tok : CARDINAL ;
- BEGIN
- LOOP
- PeekKw (tok) ;
- IF tok # TkNone THEN
- RETURN
- END ;
- IF NOT Alpha (CurCh ()) THEN
- Err (EUnknown) ;
- RETURN
- END ;
- GetWord () ;
- SaveWord (nm) ;
- DupTest (nm) ;
- ExpectDelim ('=', ENoSemi) ;
- ParseType (cls, size, elem) ;
- IF NOT OK () THEN
- RETURN
- END ;
- DropC (NewSym (nm, KType, cls, size, elem, 0, 0, FALSE)) ;
- IF NOT MatchDelim (';') THEN
- Err (ENoSemi) ;
- RETURN
- END
- END
- END DefType ;
- PROCEDURE DefPart () ;
- (* LABEL / CONST / TYPE / VAR / OVERLAY / PROC / FUNCTION / BEGIN *)
- VAR tok : CARDINAL ;
- BEGIN
- LOOP
- IF MatchDelim (';') THEN
- (* separator between declarations *)
- ELSE
- PeekKw (tok) ;
- IF tok = TkBegin THEN
- RETURN
- END ;
- IF NOT MatchKey (tok) THEN
- Err (EUnknown) ;
- RETURN
- END ;
- CASE tok OF
- TkLabel : DefLabelPart () ;
- | TkConst : DefConst () ;
- | TkType : DefType () ;
- | TkVar : DefVar () ;
- | TkOverlay :
- LOOP
- Skip () ;
- IF CurCh () = ';' THEN
- DropCh (GetCh ()) ;
- EXIT
- END ;
- IF CurCh () = 0C THEN
- Err (ENoSemi) ;
- EXIT
- END ;
- DropCh (GetCh ())
- END ;
- | TkProcedure : curIsFunc := FALSE ; ProcFunc () ;
- | TkFunction : curIsFunc := TRUE ; ProcFunc () ;
- ELSE
- Err (EUnknown) ;
- RETURN
- END ;
- IF NOT OK () THEN
- RETURN
- END
- END
- END
- END DefPart ;
- (* ---------------------------------------------------------------- *)
- (* driver (TPSRC7 compile) *)
- (* ---------------------------------------------------------------- *)
- PROCEDURE Inittur () ;
- (* reset compiler state and define the standard types *)
- BEGIN
- abortFac := FALSE ;
- errNo := 0 ;
- txerrPos := 0 ;
- srcPos := 0 ;
- srcLen := Length () ;
- pc := 0 ;
- dc := 100H ;
- varspc := 0 ;
- symTop := 0 ;
- nPatch := 0 ;
- nPend := 0 ;
- exitCnt := 0 ;
- brkN := 0 ;
- caseN := 0 ;
- lexnest := 0 ;
- curIsFunc := FALSE ;
- resultVar := 0 ;
- locFree := 0FFFEH ;
- locBytes := 0 ;
- parmOff := 4 ;
- dirs.rng := TRUE ;
- dirs.chk := TRUE ;
- InitKeys () ;
- DropC (NewSym ("INTEGER", KType, TScalar, 2, 2, 0, 0, FALSE)) ;
- DropC (NewSym ("BYTE" , KType, TScalar, 1, 1, 0, 0, FALSE)) ;
- DropC (NewSym ("CHAR" , KType, TScalar, 1, 1, 0, 0, FALSE)) ;
- DropC (NewSym ("BOOLEAN", KType, TBool , 1, 1, 0, 0, FALSE)) ;
- DropC (NewSym ("REAL" , KType, TReal , 6, 6, 0, 0, FALSE)) ;
- DropC (NewSym ("STRING" , KType, TString, 256, 1, 0, 0, FALSE)) ;
- DropC (NewSym ("TRUE" , KConst, TBool, 1, 1, 0, 1, FALSE)) ;
- DropC (NewSym ("FALSE" , KConst, TBool, 1, 1, 0, 0, FALSE)) ;
- tmpA := NewSym ("@@T1", KVar, TScalar, 2, 2, dc, 0, FALSE) ;
- dc := dc + 2 ;
- tmpB := NewSym ("@@T2", KVar, TScalar, 2, 2, dc, 0, FALSE) ;
- dc := dc + 2
- END Inittur ;
- PROCEDURE HeadWord (VAR slot : CARDINAL) ;
- BEGIN
- slot := pc ;
- Eword (0)
- END HeadWord ;
- PROCEDURE Compile (VAR errNo, errPos : CARDINAL) : BOOLEAN ;
- VAR tok : CARDINAL ;
- BEGIN
- Inittur () ;
- IF OK () THEN
- (* program prologue: header words, CALL initmem, MOV BP,SP *)
- HeadWord (hdrFlag) ;
- HeadWord (hdrCS) ;
- HeadWord (hdrDS) ;
- HeadWord (hdrHeap) ;
- HeadWord (hdrMax) ;
- Eword (16) ; (* max open files *)
- Eword (0) ; (* input buffer word *)
- Eword (0) ; (* output buffer word *)
- DropC (EmCall (TU_InitMem)) ;
- EmMovBpSp () ;
- IF MatchKey (tok) AND (tok = TkProgram) THEN
- IF Alpha (CurCh ()) THEN
- GetWord ()
- END ;
- IF MatchDelim ('(') THEN
- WHILE NOT MatchDelim (')') DO
- IF Alpha (CurCh ()) THEN
- GetWord ()
- END ;
- IF CurCh () = ',' THEN
- DropCh (GetCh ())
- END
- END
- END ;
- IfMatchSemi ()
- END ;
- IF OK () THEN
- DefPart () ;
- IF OK () THEN
- IF MatchKey (tok) AND (tok = TkBegin) THEN
- Compound () ;
- IF OK () THEN
- EmXorAxAx () ;
- DropC (EmCall (TU_ProgEnd)) ;
- ResolvePatches () ;
- codeSz := pc ;
- dataSz := dc ;
- cbuf [hdrCS] := VAL (BYTE, (codeSz DIV 16) MOD 100H) ;
- cbuf [hdrCS + 1] := VAL (BYTE, ((codeSz DIV 16) DIV 100H) MOD 100H) ;
- cbuf [hdrDS] := VAL (BYTE, (dataSz DIV 16) MOD 100H) ;
- cbuf [hdrDS + 1] := VAL (BYTE, ((dataSz DIV 16) DIV 100H) MOD 100H) ;
- cbuf [hdrFlag] := 1 ;
- cbuf [hdrFlag + 1] := 0 ;
- cbuf [hdrHeap] := 0 ;
- cbuf [hdrHeap + 1] := 0 ;
- cbuf [hdrMax] := 0 ;
- cbuf [hdrMax + 1] := 0
- END
- ELSE
- Err (EUnknown)
- END
- END
- END
- END ;
- IF NOT MatchDelim ('.') THEN
- Err (EPointExp)
- END ;
- IF abortFac THEN
- errNo := errNo ;
- errPos := txerrPos ;
- RETURN FALSE
- END ;
- errNo := 0 ;
- errPos := 0 ;
- RETURN TRUE
- END Compile ;
- PROCEDURE CodeBytes () : CARDINAL ;
- BEGIN
- RETURN codeSz
- END CodeBytes ;
- PROCEDURE DataBytes () : CARDINAL ;
- BEGIN
- RETURN dataSz
- END DataBytes ;
- END Compiler.
|