|
|
@@ -148,6 +148,7 @@ CONST
|
|
|
BI_Ln = 31 ; BI_Exp = 32 ; BI_Sin = 33 ; BI_Cos = 34 ; BI_Arctan = 35 ;
|
|
|
BI_Int = 36 ; BI_Delete = 37 ; BI_Insert = 38 ; BI_Ord = 39 ;
|
|
|
BI_Round = 40 ; BI_Trunc = 41 ; BI_Msdos = 42 ; BI_Intr = 43 ;
|
|
|
+ BI_GetDir = 44 ; BI_Seg = 45 ; BI_Ofs = 46 ;
|
|
|
(* the sub-codes EmCrtSeq takes *)
|
|
|
CrtClr = 0 ; CrtDl = 1 ; CrtDh = 2 ; CrtCaret = 3 ; CrtEol = 4 ;
|
|
|
CrtLow = 5 ; CrtNorm = 6 ; CrtDelay = 7 ; CrtKey = 8 ;
|
|
|
@@ -257,6 +258,7 @@ TYPE
|
|
|
fldFirst, fldLast : CARDINAL ; (* current record metadata *)
|
|
|
arrIdx : CARDINAL ; (* current array shape, if any *)
|
|
|
ptrElem : CARDINAL ; (* pointee type, for pointer arrays *)
|
|
|
+ dynElem : CARDINAL ; (* element symbol for a dynamic set literal *)
|
|
|
END ;
|
|
|
|
|
|
DirRec = RECORD rng, chk : BOOLEAN END ;
|
|
|
@@ -412,6 +414,7 @@ VAR
|
|
|
TU_MemCopy : CARDINAL ;
|
|
|
TU_RealToInt : CARDINAL ;
|
|
|
TU_Msdos : CARDINAL ;
|
|
|
+ TU_GetDir : CARDINAL ;
|
|
|
TU_WrReal : CARDINAL ; TU_RealWrite : CARDINAL ; TU_RealFmt : CARDINAL ;
|
|
|
TU_RealVal : CARDINAL ; TU_RealCmp : CARDINAL ;
|
|
|
TU_RealAdd : CARDINAL ; TU_RealSub : CARDINAL ;
|
|
|
@@ -430,6 +433,7 @@ VAR
|
|
|
TU_SetOp : CARDINAL ; (* runtime set operations, entries 31..33 *)
|
|
|
TU_SetCmp : CARDINAL ;
|
|
|
TU_SetCopy : CARDINAL ;
|
|
|
+ TU_SetSingle : CARDINAL ;
|
|
|
TU_FileAssign : CARDINAL ; (* file control block operations, entries 34..38 *)
|
|
|
TU_FileReset : CARDINAL ;
|
|
|
TU_FileRewrite : CARDINAL ;
|
|
|
@@ -439,7 +443,11 @@ VAR
|
|
|
TU_HeapNew : CARDINAL ; (* bump allocation for New *)
|
|
|
TU_FileEof : CARDINAL ; (* text-file end of file *)
|
|
|
TU_FileReadln : CARDINAL ; (* text-file line read *)
|
|
|
+ TU_FileRdtok : CARDINAL ; (* text-file token read *)
|
|
|
+ TU_FileRdln : CARDINAL ; (* discard the rest of a text-file line *)
|
|
|
TU_IntFmt : CARDINAL ; (* integer -> counted string *)
|
|
|
+ TU_IntFmtW : CARDINAL ; (* integer -> counted string, width-padded *)
|
|
|
+ TU_StrFmtW : CARDINAL ; (* string -> fixed-width counted string *)
|
|
|
TU_ValInt : CARDINAL ; (* counted string -> integer *)
|
|
|
TU_StrCopy : CARDINAL ; (* Copy(S,start,len) *)
|
|
|
TU_ValReal : CARDINAL ; (* counted string -> REAL *)
|
|
|
@@ -1639,6 +1647,12 @@ BEGIN Ebyte (88H) ; Ebyte (05H) END EmStDiAl ; (* 88 05: [DI] := AL *)
|
|
|
PROCEDURE EmPushDi () ;
|
|
|
BEGIN Ebyte (57H) END EmPushDi ; (* PUSH DI *)
|
|
|
|
|
|
+PROCEDURE EmPushSi () ;
|
|
|
+BEGIN Ebyte (56H) END EmPushSi ; (* PUSH SI *)
|
|
|
+
|
|
|
+PROCEDURE EmMovAxDs () ;
|
|
|
+BEGIN Ebyte (8CH) ; Ebyte (0D8H) END EmMovAxDs ; (* MOV AX,DS *)
|
|
|
+
|
|
|
PROCEDURE EmPopDi () ;
|
|
|
BEGIN Ebyte (5FH) END EmPopDi ; (* POP DI *)
|
|
|
|
|
|
@@ -2887,6 +2901,16 @@ BEGIN
|
|
|
IF NOT OK () THEN
|
|
|
RETURN
|
|
|
END ;
|
|
|
+ Skip () ;
|
|
|
+ IF CurCh () = ':' THEN
|
|
|
+ (* TP3 segment:offset form in Mem[...]; the segment
|
|
|
+ expression is consumed and the offset is the index. *)
|
|
|
+ DropCh (GetCh ()) ;
|
|
|
+ ParseExpr (t) ;
|
|
|
+ IF NOT OK () THEN
|
|
|
+ RETURN
|
|
|
+ END
|
|
|
+ END ;
|
|
|
st := arrs [ai].elem ;
|
|
|
k := nd + 1 ;
|
|
|
WHILE k < arrs [ai].n DO
|
|
|
@@ -3459,6 +3483,28 @@ BEGIN
|
|
|
res.setsize := size
|
|
|
END SetBinEmit ;
|
|
|
|
|
|
+PROCEDURE MaterializeDyn (VAR r : ERes ; base, size : CARDINAL) ;
|
|
|
+(* Build a scratch set of `size' bytes with the single dynamic element at
|
|
|
+ `base' set. Used for TP3's `[Storage[Index]]' constructor. *)
|
|
|
+VAR dest : CARDINAL ;
|
|
|
+BEGIN
|
|
|
+ dest := AllocSetScratch (size) ;
|
|
|
+ IF NOT OK () THEN
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ EmMovAxi (size) ; EmPushAx () ;
|
|
|
+ EmMovAxi (base) ; EmPushAx () ;
|
|
|
+ LoadSymVar (r.dynElem, symtab [r.dynElem].off, 2) ;
|
|
|
+ EmPushAx () ;
|
|
|
+ EmPushVarAddr (FALSE, dest) ;
|
|
|
+ DropC (EmCall (TU_SetSingle)) ;
|
|
|
+ EmAddSp (8) ;
|
|
|
+ r.kind := 8 ;
|
|
|
+ r.setoff := dest ;
|
|
|
+ r.setbase := base ;
|
|
|
+ r.setsize := size
|
|
|
+END MaterializeDyn ;
|
|
|
+
|
|
|
PROCEDURE EmPushStrAddr (r : ERes) ;
|
|
|
(* Push the ADDRESS of a whole-string operand - the argument shape cmpstr
|
|
|
takes, one per operand.
|
|
|
@@ -3919,6 +3965,14 @@ BEGIN
|
|
|
RETURN symTop - 1
|
|
|
END NewScratchStr ;
|
|
|
|
|
|
+PROCEDURE NewScratchWord () : CARDINAL ;
|
|
|
+(* Two bytes for a dynamic set literal's element value. *)
|
|
|
+BEGIN
|
|
|
+ DropC (NewSym ("@@DW", KVar, TScalar, 2, 2, dc, 0, FALSE)) ;
|
|
|
+ dc := dc + 2 ;
|
|
|
+ RETURN symTop - 1
|
|
|
+END NewScratchWord ;
|
|
|
+
|
|
|
PROCEDURE NewScratchReal () : CARDINAL ;
|
|
|
(* Six bytes of storage for a REAL function result, one per call site. *)
|
|
|
BEGIN
|
|
|
@@ -4272,6 +4326,9 @@ BEGIN
|
|
|
Err (ETypeErr) ;
|
|
|
RETURN
|
|
|
END ;
|
|
|
+ IF right.kind = 9 THEN
|
|
|
+ MaterializeDyn (right, left.setbase, left.setsize)
|
|
|
+ END ;
|
|
|
IF op = OpAdd THEN
|
|
|
SetBinEmit (1, left, right, r)
|
|
|
ELSE
|
|
|
@@ -4475,7 +4532,8 @@ VAR idx : CARDINAL ;
|
|
|
ssize, sbase : CARDINAL ;
|
|
|
sbuf : ARRAY [0..31] OF CHAR ;
|
|
|
uj1, uj2 : CARDINAL ;
|
|
|
- litStart, scratch, asciiAddr : CARDINAL ;
|
|
|
+ litStart, scratch, asciiAddr, savePos : CARDINAL ;
|
|
|
+ dyn : ERes ;
|
|
|
BEGIN
|
|
|
r.chr := FALSE ; (* default: not a quoted char literal *)
|
|
|
Skip () ;
|
|
|
@@ -4486,10 +4544,40 @@ BEGIN
|
|
|
RETURN
|
|
|
END ;
|
|
|
IF CurCh () = '[' THEN
|
|
|
- (* An inline set literal. Full TP3 takes its type from context; here it
|
|
|
- defaults to `set of Char' (0..255), which is what CALC writes
|
|
|
- (`Ch in ['a'..'z']'), and its bytes are materialised in the code
|
|
|
- stream. A typed/larger-base literal is a later milestone. *)
|
|
|
+ (* An inline set literal. A literal whose first element is a variable
|
|
|
+ (e.g. `[Storage[Index]]') is dynamic: evaluate the element once and
|
|
|
+ mark it kind 9, to be materialised when the target's base/size is
|
|
|
+ known. Constant literals stay code-resident. *)
|
|
|
+ savePos := srcPos ;
|
|
|
+ DropCh (GetCh ()) ;
|
|
|
+ Skip () ;
|
|
|
+ IF Alpha (CurCh ()) THEN
|
|
|
+ GetWord () ;
|
|
|
+ IF Search (wrd, idx) AND ((symtab [idx].tag = KVar) OR
|
|
|
+ (symtab [idx].tag = KFunc)) THEN
|
|
|
+ srcPos := savePos + 1 ;
|
|
|
+ ParseExpr (dyn) ;
|
|
|
+ ExpectDelim (']', ENoSemi) ;
|
|
|
+ IF NOT OK () THEN
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ IF (dyn.cls # TScalar) AND (dyn.cls # TChar) AND
|
|
|
+ (dyn.cls # TEnum) THEN
|
|
|
+ Err (ETypeErr) ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ scratch := NewScratchWord () ;
|
|
|
+ LoadAtom (dyn) ;
|
|
|
+ EmStoreVar (FALSE, symtab [scratch].off, 2) ;
|
|
|
+ r.kind := 9 ;
|
|
|
+ r.cls := TSet ;
|
|
|
+ r.setbase := 0 ;
|
|
|
+ r.setsize := 0 ;
|
|
|
+ r.dynElem := scratch ;
|
|
|
+ RETURN
|
|
|
+ END
|
|
|
+ END ;
|
|
|
+ srcPos := savePos ;
|
|
|
ssize := 32 ;
|
|
|
sbase := 0 ;
|
|
|
IF RdSetLiteral (sbase, ssize, sbuf) THEN
|
|
|
@@ -4598,6 +4686,51 @@ BEGIN
|
|
|
r.idx := 0 ;
|
|
|
RETURN
|
|
|
END ;
|
|
|
+ IF NameEq (wrd, "SEG") THEN
|
|
|
+ (* TP3 Seg(x): the current DS. The argument is parsed for its type
|
|
|
+ and side effects; the .COM has one segment. *)
|
|
|
+ IF NOT MatchDelim ('(') THEN
|
|
|
+ Err (ENoSemi) ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ ParseExpr (r) ;
|
|
|
+ ExpectDelim (')', ENoSemi) ;
|
|
|
+ IF NOT OK () THEN
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ EmMovAxDs () ; (* MOV AX,DS *)
|
|
|
+ r.kind := 2 ; r.cls := TScalar ; r.sz := 2 ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ IF NameEq (wrd, "OFS") THEN
|
|
|
+ (* TP3 Ofs(x): the run-time address of x. *)
|
|
|
+ IF NOT MatchDelim ('(') THEN
|
|
|
+ Err (ENoSemi) ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ Skip () ;
|
|
|
+ IF NOT Alpha (CurCh ()) THEN
|
|
|
+ Err (EUnknown) ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ GetWord () ;
|
|
|
+ ParseVar (r) ;
|
|
|
+ ExpectDelim (')', ENoSemi) ;
|
|
|
+ IF NOT OK () THEN
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ IF r.kind = 5 THEN
|
|
|
+ EmMovAxDi ()
|
|
|
+ ELSIF r.kind = 1 THEN
|
|
|
+ EmPushSymAddr (r.idx, (symtab [r.idx].off + r.boff) MOD 10000H) ;
|
|
|
+ EmPopAx ()
|
|
|
+ ELSE
|
|
|
+ Err (ETypeErr) ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ r.kind := 2 ; r.cls := TScalar ; r.sz := 2 ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
IF NOT Search (wrd, idx) THEN
|
|
|
Err (EUnknown) ;
|
|
|
RETURN
|
|
|
@@ -4630,6 +4763,30 @@ BEGIN
|
|
|
r.cls := symtab [idx].cls
|
|
|
END ;
|
|
|
RETURN
|
|
|
+ ELSIF (symtab [idx].tag = KType) AND (symtab [idx].cls = TChar)
|
|
|
+ AND (CurCh () = '(') THEN
|
|
|
+ (* TP3 also spells the character cast `Char(n)', not only `Chr(n)'. *)
|
|
|
+ DropCh (GetCh ()) ;
|
|
|
+ ParseExpr (r) ;
|
|
|
+ ExpectDelim (')', ENoSemi) ;
|
|
|
+ IF NOT OK () THEN
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ IF (r.cls # TScalar) AND (r.cls # TChar) THEN
|
|
|
+ Err (ETypeErr) ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ IF r.kind = 0 THEN
|
|
|
+ r.imm := VAL (LONGINT, W16 (r.imm) MOD 256) ;
|
|
|
+ r.chr := TRUE
|
|
|
+ ELSE
|
|
|
+ LoadAtom (r) ;
|
|
|
+ r.kind := 2 ;
|
|
|
+ r.chr := FALSE
|
|
|
+ END ;
|
|
|
+ r.cls := TChar ;
|
|
|
+ r.sz := 1 ;
|
|
|
+ RETURN
|
|
|
ELSIF (symtab [idx].tag = KVar) OR (symtab [idx].tag = KType) THEN
|
|
|
(* ParseVar initialises boff to 0 and then ParseSub folds any constant
|
|
|
subscript into it. Do NOT reset boff here: doing so after ParseVar
|
|
|
@@ -5717,6 +5874,9 @@ BEGIN
|
|
|
Err (ETypeErr) ;
|
|
|
RETURN
|
|
|
END ;
|
|
|
+ IF src.kind = 9 THEN
|
|
|
+ MaterializeDyn (src, r.setbase, r.setsize)
|
|
|
+ END ;
|
|
|
IF r.kind = 1 THEN
|
|
|
EmPushSymAddr (r.idx, (symtab [r.idx].off + r.boff) MOD 10000H)
|
|
|
ELSIF r.kind # 5 THEN
|
|
|
@@ -5735,17 +5895,16 @@ BEGIN
|
|
|
RETURN
|
|
|
END ;
|
|
|
IF (r.kind = 5) AND (r.cls = TString) THEN
|
|
|
- (* A string field of a DI-addressed record element (CALC's
|
|
|
- `with Sheet[I,J] do Contents := '''). DI is the field's address.
|
|
|
- A literal's bytes are known: store <len><chars>, truncated to the
|
|
|
- field's capacity (size-1). A string VARIABLE source uses strstore,
|
|
|
- with DI pushed as the destination. *)
|
|
|
+ (* A string field of a DI-addressed record element. DI is the field's
|
|
|
+ address; park it because the source expression may reuse DI. *)
|
|
|
+ EmPushDi () ;
|
|
|
ParseExpr (src) ;
|
|
|
IF NOT OK () THEN
|
|
|
RETURN
|
|
|
END ;
|
|
|
n := VarSize (r) - 1 ; (* usable characters *)
|
|
|
IF src.kind = 3 THEN
|
|
|
+ EmPopDi () ;
|
|
|
IF strLen [src.strx] < n THEN
|
|
|
n := strLen [src.strx]
|
|
|
END ;
|
|
|
@@ -5757,10 +5916,20 @@ BEGIN
|
|
|
END
|
|
|
ELSIF src.kind = 1 THEN
|
|
|
EmPushSymAddr (src.idx, (symtab [src.idx].off + src.boff) MOD 10000H) ;
|
|
|
- EmPushDi () ; (* destination = the field *)
|
|
|
+ EmPopDi () ; (* destination = the field *)
|
|
|
+ EmPushDi () ;
|
|
|
EmMovCxi (n) ; (* strstore's limit *)
|
|
|
DropC (EmCall (TU_StrStore)) ;
|
|
|
EmAddSp (4)
|
|
|
+ ELSIF src.kind = 5 THEN
|
|
|
+ EmPushDi () ; (* source field address *)
|
|
|
+ EmPopSi () ;
|
|
|
+ EmPopDi () ; (* destination field address *)
|
|
|
+ EmPushSi () ; (* source address *)
|
|
|
+ EmPushDi () ;
|
|
|
+ EmMovCxi (n) ;
|
|
|
+ DropC (EmCall (TU_StrStore)) ;
|
|
|
+ EmAddSp (4)
|
|
|
ELSE
|
|
|
Err (ENoLib)
|
|
|
END ;
|
|
|
@@ -6285,11 +6454,27 @@ BEGIN
|
|
|
END ;
|
|
|
ParseExpr (arg) ;
|
|
|
IF OK () AND (arg.cls = TScalar) THEN
|
|
|
- (* Str(integer, S): no width formatting here; TP3's default width is
|
|
|
- zero, and CALC uses `Str(count,st)`. A colon would ask for a field
|
|
|
- width, which is a separate increment. *)
|
|
|
IF MatchDelim (':') THEN
|
|
|
- Err (ENoLib) ;
|
|
|
+ ParseExpr (errV) ;
|
|
|
+ IF NOT OK () THEN
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ LoadAtom (arg) ; EmPushAx () ;
|
|
|
+ LoadAtom (errV) ; EmPushAx () ;
|
|
|
+ IF NOT MatchDelim (',') THEN
|
|
|
+ Err (ENoSemi) ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ ParseExpr (dummy) ;
|
|
|
+ IF OK () AND (dummy.cls = TString) AND
|
|
|
+ ((dummy.kind = 1) OR (dummy.kind = 5)) THEN
|
|
|
+ EmPushStrAddr (dummy) ;
|
|
|
+ DropC (EmCall (TU_IntFmtW)) ;
|
|
|
+ EmAddSp (6)
|
|
|
+ ELSIF OK () THEN
|
|
|
+ Err (ETypeErr)
|
|
|
+ END ;
|
|
|
+ ExpectDelim (')', ENoSemi) ;
|
|
|
RETURN
|
|
|
END ;
|
|
|
LoadAtom (arg) ;
|
|
|
@@ -6368,6 +6553,30 @@ BEGIN
|
|
|
ExpectDelim (')', ENoSemi) ;
|
|
|
RETURN
|
|
|
END ;
|
|
|
+ IF which = BI_GetDir THEN
|
|
|
+ IF MatchDelim ('(') THEN
|
|
|
+ ParseExpr (arg) ;
|
|
|
+ IF OK () AND ((arg.cls = TScalar) OR (arg.cls = TChar)) THEN
|
|
|
+ LoadAtom (arg) ;
|
|
|
+ EmPushAx () ; (* drive *)
|
|
|
+ ExpectDelim (',', ENoSemi) ;
|
|
|
+ ParseExpr (dummy) ;
|
|
|
+ IF OK () AND (dummy.cls = TString) AND (dummy.kind = 1) THEN
|
|
|
+ EmPushSymAddr (dummy.idx, (symtab [dummy.idx].off + dummy.boff) MOD 10000H) ;
|
|
|
+ DropC (EmCall (TU_GetDir)) ;
|
|
|
+ EmAddSp (4)
|
|
|
+ ELSIF OK () THEN
|
|
|
+ Err (ETypeErr)
|
|
|
+ END
|
|
|
+ ELSIF OK () THEN
|
|
|
+ Err (ETypeErr)
|
|
|
+ END ;
|
|
|
+ ExpectDelim (')', ENoSemi)
|
|
|
+ ELSE
|
|
|
+ Err (ENoSemi)
|
|
|
+ END ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
IF (which = BI_Msdos) OR (which = BI_Intr) THEN
|
|
|
IF MatchDelim ('(') THEN
|
|
|
IF which = BI_Intr THEN
|
|
|
@@ -6496,47 +6705,78 @@ BEGIN
|
|
|
END ;
|
|
|
skipArg := TRUE
|
|
|
ELSIF reading THEN
|
|
|
- (* Readln(F, S): read one line from a text file into the
|
|
|
- counted string S. The runtime takes the file block,
|
|
|
- destination and capacity; it consumes CR and terminates
|
|
|
- on LF/^Z/physical EOF. *)
|
|
|
+ (* Text-file reads. A number is read as a whitespace-
|
|
|
+ delimited token and handed to ValInt/ValReal; a string
|
|
|
+ still uses the line reader. Readln consumes the rest
|
|
|
+ of the line after all numeric arguments. *)
|
|
|
IF NOT MatchDelim (',') THEN
|
|
|
Err (ENoSemi) ;
|
|
|
RETURN
|
|
|
END ;
|
|
|
- ParseExpr (dummy) ;
|
|
|
- IF OK () AND (dummy.cls = TString) AND
|
|
|
- ((dummy.kind = 1) OR (dummy.kind = 5)) THEN
|
|
|
- EmMovAxi ((VarSize (dummy) - 1) MOD 10000H) ;
|
|
|
- EmPushAx () ;
|
|
|
- EmPushStrAddr (dummy) ;
|
|
|
- EmPushSymAddr (arg.idx, (symtab [arg.idx].off + arg.boff) MOD 10000H) ;
|
|
|
- DropC (EmCall (TU_FileReadln)) ;
|
|
|
- EmAddSp (6)
|
|
|
- ELSIF OK () AND IsCharArray (dummy) AND (dummy.kind = 1) THEN
|
|
|
- (* Readln(F, Place): file_readln writes a counted string;
|
|
|
- use a scratch, prefill the tail with spaces, then copy
|
|
|
- the fixed width over the CHAR array. *)
|
|
|
- scratch := NewScratchStr () ;
|
|
|
- k := 1 ;
|
|
|
- WHILE k <= VarSize (dummy) DO
|
|
|
- EmMovAxi (ORD (' ')) ;
|
|
|
- EmStoreVar (FALSE, (symtab [scratch].off + k) MOD 10000H, 1) ;
|
|
|
- INC (k)
|
|
|
+ LOOP
|
|
|
+ ParseExpr (dummy) ;
|
|
|
+ IF NOT OK () THEN
|
|
|
+ RETURN
|
|
|
END ;
|
|
|
- EmMovAxi (VarSize (dummy)) ;
|
|
|
- EmPushAx () ;
|
|
|
- EmPushVarAddr (FALSE, symtab [scratch].off) ;
|
|
|
+ IF dummy.cls = TString THEN
|
|
|
+ IF (dummy.kind = 1) OR (dummy.kind = 5) THEN
|
|
|
+ EmMovAxi ((VarSize (dummy) - 1) MOD 10000H) ;
|
|
|
+ EmPushAx () ;
|
|
|
+ EmPushStrAddr (dummy) ;
|
|
|
+ EmPushSymAddr (arg.idx, (symtab [arg.idx].off + arg.boff) MOD 10000H) ;
|
|
|
+ DropC (EmCall (TU_FileReadln)) ;
|
|
|
+ EmAddSp (6)
|
|
|
+ ELSE
|
|
|
+ Err (ETypeErr) ;
|
|
|
+ RETURN
|
|
|
+ END
|
|
|
+ ELSIF IsCharArray (dummy) AND (dummy.kind = 1) THEN
|
|
|
+ scratch := NewScratchStr () ;
|
|
|
+ k := 1 ;
|
|
|
+ WHILE k <= VarSize (dummy) DO
|
|
|
+ EmMovAxi (ORD (' ')) ;
|
|
|
+ EmStoreVar (FALSE, (symtab [scratch].off + k) MOD 10000H, 1) ;
|
|
|
+ INC (k)
|
|
|
+ END ;
|
|
|
+ EmMovAxi (VarSize (dummy)) ;
|
|
|
+ EmPushAx () ;
|
|
|
+ EmPushVarAddr (FALSE, symtab [scratch].off) ;
|
|
|
+ EmPushSymAddr (arg.idx, (symtab [arg.idx].off + arg.boff) MOD 10000H) ;
|
|
|
+ DropC (EmCall (TU_FileReadln)) ;
|
|
|
+ EmAddSp (6) ;
|
|
|
+ EmPushVarAddr (FALSE, (symtab [scratch].off + 1) MOD 10000H) ;
|
|
|
+ EmPushSymAddr (dummy.idx, (symtab [dummy.idx].off + dummy.boff) MOD 10000H) ;
|
|
|
+ EmMovCxi (VarSize (dummy)) ;
|
|
|
+ DropC (EmCall (TU_MemCopy)) ;
|
|
|
+ EmAddSp (4)
|
|
|
+ ELSIF (dummy.kind = 1) AND
|
|
|
+ ((dummy.cls = TScalar) OR (dummy.cls = TReal)) THEN
|
|
|
+ scratch := NewScratchStr () ;
|
|
|
+ EmPushVarAddr (FALSE, symtab [scratch].off) ;
|
|
|
+ EmPushSymAddr (arg.idx, (symtab [arg.idx].off + arg.boff) MOD 10000H) ;
|
|
|
+ DropC (EmCall (TU_FileRdtok)) ;
|
|
|
+ EmAddSp (4) ;
|
|
|
+ EmPushVarAddr (FALSE, symtab [tmpA].off) ;
|
|
|
+ EmPushSymAddr (dummy.idx, (symtab [dummy.idx].off + dummy.boff) MOD 10000H) ;
|
|
|
+ EmPushVarAddr (FALSE, symtab [scratch].off) ;
|
|
|
+ IF dummy.cls = TReal THEN
|
|
|
+ DropC (EmCall (TU_ValReal))
|
|
|
+ ELSE
|
|
|
+ DropC (EmCall (TU_ValInt))
|
|
|
+ END ;
|
|
|
+ EmAddSp (6)
|
|
|
+ ELSE
|
|
|
+ Err (ETypeErr) ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ IF NOT MatchDelim (',') THEN
|
|
|
+ EXIT
|
|
|
+ END
|
|
|
+ END ;
|
|
|
+ IF which = BI_ReadLn THEN
|
|
|
EmPushSymAddr (arg.idx, (symtab [arg.idx].off + arg.boff) MOD 10000H) ;
|
|
|
- DropC (EmCall (TU_FileReadln)) ;
|
|
|
- EmAddSp (6) ;
|
|
|
- EmPushVarAddr (FALSE, (symtab [scratch].off + 1) MOD 10000H) ;
|
|
|
- EmPushSymAddr (dummy.idx, (symtab [dummy.idx].off + dummy.boff) MOD 10000H) ;
|
|
|
- EmMovCxi (VarSize (dummy)) ;
|
|
|
- DropC (EmCall (TU_MemCopy)) ;
|
|
|
- EmAddSp (4)
|
|
|
- ELSIF OK () THEN
|
|
|
- Err (ETypeErr)
|
|
|
+ DropC (EmCall (TU_FileRdln)) ;
|
|
|
+ EmAddSp (2)
|
|
|
END ;
|
|
|
ExpectDelim (')', ENoSemi) ;
|
|
|
RETURN
|
|
|
@@ -6551,34 +6791,138 @@ BEGIN
|
|
|
RETURN
|
|
|
END ;
|
|
|
IF MatchDelim (',') THEN
|
|
|
- ParseExpr (dummy) ;
|
|
|
- IF NOT OK () THEN
|
|
|
- RETURN
|
|
|
- END ;
|
|
|
- IF dummy.cls = TString THEN
|
|
|
- IF dummy.kind = 1 THEN
|
|
|
+ LOOP
|
|
|
+ ParseExpr (dummy) ;
|
|
|
+ IF NOT OK () THEN
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ IF dummy.cls = TString THEN
|
|
|
+ IF MatchDelim (':') THEN
|
|
|
+ ParseExpr (errV) ;
|
|
|
+ IF NOT OK () THEN
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ LoadAtom (errV) ;
|
|
|
+ EmPushAx () ; (* width *)
|
|
|
+ EmPushStrAddr (dummy) ; (* source *)
|
|
|
+ scratch := NewScratchStr () ;
|
|
|
+ EmPushVarAddr (FALSE, symtab [scratch].off) ;
|
|
|
+ DropC (EmCall (TU_StrFmtW)) ;
|
|
|
+ EmAddSp (6) ;
|
|
|
+ EmFileIo (FALSE, symtab [arg.idx].local,
|
|
|
+ symtab [arg.idx].off, 1, FALSE,
|
|
|
+ symtab [scratch].off, 0, TRUE)
|
|
|
+ ELSIF dummy.kind = 1 THEN
|
|
|
+ EmFileIo (FALSE, symtab [arg.idx].local,
|
|
|
+ symtab [arg.idx].off, 1,
|
|
|
+ symtab [dummy.idx].local,
|
|
|
+ (symtab [dummy.idx].off + dummy.boff)
|
|
|
+ MOD 10000H,
|
|
|
+ 0, TRUE)
|
|
|
+ ELSIF dummy.kind = 5 THEN
|
|
|
+ EmFileIo (FALSE, symtab [arg.idx].local,
|
|
|
+ symtab [arg.idx].off, 5, FALSE,
|
|
|
+ 0, 0, TRUE)
|
|
|
+ ELSIF dummy.kind = 3 THEN
|
|
|
+ EmFileIo (FALSE, symtab [arg.idx].local,
|
|
|
+ symtab [arg.idx].off, 4, FALSE,
|
|
|
+ EmStrBlob (dummy), 0, TRUE)
|
|
|
+ ELSE
|
|
|
+ Err (ENoLib) ;
|
|
|
+ RETURN
|
|
|
+ END
|
|
|
+ ELSIF (dummy.cls = TChar) OR
|
|
|
+ ((dummy.cls = TScalar) AND dummy.chr) THEN
|
|
|
+ IF dummy.kind = 1 THEN
|
|
|
+ EmFileIo (FALSE, symtab [arg.idx].local,
|
|
|
+ symtab [arg.idx].off, 1,
|
|
|
+ symtab [dummy.idx].local,
|
|
|
+ (symtab [dummy.idx].off + dummy.boff)
|
|
|
+ MOD 10000H,
|
|
|
+ 1, FALSE)
|
|
|
+ ELSIF dummy.kind = 5 THEN
|
|
|
+ EmFileIo (FALSE, symtab [arg.idx].local,
|
|
|
+ symtab [arg.idx].off, 5, FALSE,
|
|
|
+ 0, 1, FALSE)
|
|
|
+ ELSIF dummy.kind = 2 THEN
|
|
|
+ EmStoreVar (FALSE, symtab [tmpA].off, 1) ;
|
|
|
+ EmFileIo (FALSE, symtab [arg.idx].local,
|
|
|
+ symtab [arg.idx].off, 1, FALSE,
|
|
|
+ symtab [tmpA].off, 1, FALSE)
|
|
|
+ ELSIF dummy.kind = 0 THEN
|
|
|
+ EmFileIo (FALSE, symtab [arg.idx].local,
|
|
|
+ symtab [arg.idx].off, 4, FALSE,
|
|
|
+ EmInlineCh (VAL (CARDINAL, dummy.imm)),
|
|
|
+ 0, TRUE)
|
|
|
+ ELSE
|
|
|
+ Err (ENoLib) ;
|
|
|
+ RETURN
|
|
|
+ END
|
|
|
+ ELSIF dummy.cls = TReal THEN
|
|
|
+ EmPushRealAddr (dummy) ;
|
|
|
+ IF MatchDelim (':') THEN
|
|
|
+ ParseExpr (errV) ;
|
|
|
+ IF OK () THEN LoadAtom (errV) END ;
|
|
|
+ IF MatchDelim (':') THEN
|
|
|
+ EmPushAx () ;
|
|
|
+ ParseExpr (errV) ;
|
|
|
+ IF OK () THEN
|
|
|
+ LoadAtom (errV) ;
|
|
|
+ EmMovChAl () ;
|
|
|
+ EmPopAx () ;
|
|
|
+ EmMovClAl ()
|
|
|
+ END
|
|
|
+ ELSIF OK () THEN
|
|
|
+ EmMovClAl () ;
|
|
|
+ EmMovChImm (0FFH)
|
|
|
+ END
|
|
|
+ ELSE
|
|
|
+ EmMovCxi (0FF12H)
|
|
|
+ END ;
|
|
|
+ EmMovAxCx () ;
|
|
|
+ EmStoreVar (FALSE, symtab [tmpA].off, 2) ;
|
|
|
+ scratch := NewScratchStr () ;
|
|
|
+ EmPushVarAddr (FALSE, symtab [scratch].off) ;
|
|
|
+ EmPopAx () ;
|
|
|
+ EmPopBx () ;
|
|
|
+ EmPushAx () ;
|
|
|
+ EmPushBx () ;
|
|
|
+ EmLoadVar (FALSE, symtab [tmpA].off, 2) ;
|
|
|
+ EmXchgAxCx () ;
|
|
|
+ DropC (EmCall (TU_RealFmt)) ;
|
|
|
+ EmAddSp (4) ;
|
|
|
EmFileIo (FALSE, symtab [arg.idx].local,
|
|
|
- symtab [arg.idx].off, 1,
|
|
|
- symtab [dummy.idx].local,
|
|
|
- (symtab [dummy.idx].off + dummy.boff)
|
|
|
- MOD 10000H,
|
|
|
- 0, TRUE)
|
|
|
- ELSIF dummy.kind = 3 THEN
|
|
|
+ symtab [arg.idx].off, 1, FALSE,
|
|
|
+ symtab [scratch].off, 0, TRUE)
|
|
|
+ ELSIF dummy.cls = TScalar THEN
|
|
|
+ (* integer with the optional TP3 `:width' *)
|
|
|
+ LoadAtom (dummy) ;
|
|
|
+ EmPushAx () ;
|
|
|
+ IF MatchDelim (':') THEN
|
|
|
+ ParseExpr (errV) ;
|
|
|
+ IF NOT OK () THEN
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ LoadAtom (errV) ;
|
|
|
+ EmPushAx ()
|
|
|
+ ELSE
|
|
|
+ EmMovAxi (0) ;
|
|
|
+ EmPushAx ()
|
|
|
+ END ;
|
|
|
+ scratch := NewScratchStr () ;
|
|
|
+ EmPushVarAddr (FALSE, symtab [scratch].off) ;
|
|
|
+ DropC (EmCall (TU_IntFmtW)) ;
|
|
|
+ EmAddSp (6) ;
|
|
|
EmFileIo (FALSE, symtab [arg.idx].local,
|
|
|
- symtab [arg.idx].off, 4, FALSE,
|
|
|
- EmStrBlob (dummy), 0, TRUE)
|
|
|
+ symtab [arg.idx].off, 1, FALSE,
|
|
|
+ symtab [scratch].off, 0, TRUE)
|
|
|
ELSE
|
|
|
Err (ENoLib) ;
|
|
|
RETURN
|
|
|
+ END ;
|
|
|
+ IF NOT MatchDelim (',') THEN
|
|
|
+ EXIT
|
|
|
END
|
|
|
- ELSIF (dummy.cls = TScalar) AND dummy.chr THEN
|
|
|
- EmFileIo (FALSE, symtab [arg.idx].local,
|
|
|
- symtab [arg.idx].off, 4, FALSE,
|
|
|
- EmInlineCh (VAL (CARDINAL, dummy.imm)),
|
|
|
- 0, TRUE)
|
|
|
- ELSE
|
|
|
- Err (ENoLib) ;
|
|
|
- RETURN
|
|
|
END
|
|
|
END ;
|
|
|
IF which = BI_WriteLn THEN
|
|
|
@@ -9019,6 +9363,12 @@ BEGIN
|
|
|
symtab [i].defnd := TRUE ;
|
|
|
i := NewSym ("INTR", KBuiltin, BI_Intr, 0, 0, 0, 0, FALSE) ;
|
|
|
symtab [i].defnd := TRUE ;
|
|
|
+ i := NewSym ("GETDIR", KBuiltin, BI_GetDir, 0, 0, 0, 0, FALSE) ;
|
|
|
+ symtab [i].defnd := TRUE ;
|
|
|
+ i := NewSym ("SEG", KBuiltin, BI_Seg, 0, 0, 0, 0, FALSE) ;
|
|
|
+ symtab [i].defnd := TRUE ;
|
|
|
+ i := NewSym ("OFS", KBuiltin, BI_Ofs, 0, 0, 0, 0, FALSE) ;
|
|
|
+ symtab [i].defnd := TRUE ;
|
|
|
i := NewSym ("SUCC", KBuiltin, BI_Succ, 0, 0, 0, 0, FALSE) ;
|
|
|
i := NewSym ("PRED", KBuiltin, BI_Pred, 0, 0, 0, 0, FALSE) ;
|
|
|
symtab [i].defnd := TRUE ;
|
|
|
@@ -9184,6 +9534,15 @@ BEGIN
|
|
|
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)) ;
|
|
|
+ (* TP3's absolute byte array `Mem[address]'. The base is chosen so the
|
|
|
+ normal LoadBias addition lands on absolute offset zero. *)
|
|
|
+ arrs [0].n := 1 ; arrs [0].elem := 1 ; arrs [0].ecls := TScalar ;
|
|
|
+ arrs [0].lo [0] := 0 ; arrs [0].hi [0] := 65535 ;
|
|
|
+ arrs [0].fldFirst := 0 ; arrs [0].fldLast := 0 ; arrs [0].elemType := 0 ;
|
|
|
+ i := NewSym ("MEM", KVar, TArray, 65535, 1,
|
|
|
+ W16 (-VAL (LONGINT, LoadBias)), 0, FALSE) ;
|
|
|
+ symtab [i].arrIdx := 1 ;
|
|
|
+ arrTop := 1 ;
|
|
|
DefBuiltins () ;
|
|
|
tmpA := NewSym ("@@T1", KVar, TScalar, 2, 2, dc, 0, FALSE) ;
|
|
|
dc := dc + 2 ;
|
|
|
@@ -9227,6 +9586,7 @@ BEGIN
|
|
|
TU_MemCopy := RT_Entry (59) ;
|
|
|
TU_RealToInt := RT_Entry (60) ;
|
|
|
TU_Msdos := RT_Entry (61) ;
|
|
|
+ TU_GetDir := RT_Entry (64) ;
|
|
|
TU_WrReal := RT_Entry (6) ;
|
|
|
TU_RealWrite := RT_Entry (30) ; (* fmtreal + padding + output *)
|
|
|
TU_RealFmt := RT_Entry (28) ; (* fmtreal into a string variable *)
|
|
|
@@ -9248,6 +9608,7 @@ BEGIN
|
|
|
TU_SetOp := RT_Entry (31) ;
|
|
|
TU_SetCmp := RT_Entry (32) ;
|
|
|
TU_SetCopy := RT_Entry (33) ;
|
|
|
+ TU_SetSingle := RT_Entry (67) ;
|
|
|
TU_FileAssign := RT_Entry (34) ;
|
|
|
TU_FileReset := RT_Entry (35) ;
|
|
|
TU_FileRewrite := RT_Entry (36) ;
|
|
|
@@ -9257,7 +9618,11 @@ BEGIN
|
|
|
TU_HeapNew := RT_Entry (40) ;
|
|
|
TU_FileEof := RT_Entry (41) ;
|
|
|
TU_FileReadln := RT_Entry (42) ;
|
|
|
+ TU_FileRdtok := RT_Entry (65) ;
|
|
|
+ TU_FileRdln := RT_Entry (66) ;
|
|
|
TU_IntFmt := RT_Entry (43) ;
|
|
|
+ TU_IntFmtW := RT_Entry (62) ;
|
|
|
+ TU_StrFmtW := RT_Entry (63) ;
|
|
|
TU_ValInt := RT_Entry (44) ;
|
|
|
TU_StrCopy := RT_Entry (45) ;
|
|
|
TU_ValReal := RT_Entry (46) ;
|