|
|
@@ -0,0 +1,2594 @@
|
|
|
+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.
|