|
|
@@ -1320,6 +1320,9 @@ BEGIN Ebyte (01H) ; Ebyte (0C7H) END EmAddDiAx ; (* 01 C7: DI := DI + AX *)
|
|
|
PROCEDURE EmLdAlDi () ;
|
|
|
BEGIN Ebyte (8AH) ; Ebyte (05H) END EmLdAlDi ; (* 8A 05: AL := [DI] *)
|
|
|
|
|
|
+PROCEDURE EmLdAxDi () ;
|
|
|
+BEGIN Ebyte (8BH) ; Ebyte (05H) END EmLdAxDi ; (* 8B 05: AX := [DI] *)
|
|
|
+
|
|
|
PROCEDURE EmStDiAl () ;
|
|
|
BEGIN Ebyte (88H) ; Ebyte (05H) END EmStDiAl ; (* 88 05: [DI] := AL *)
|
|
|
|
|
|
@@ -2179,16 +2182,24 @@ BEGIN
|
|
|
RETURN
|
|
|
END ;
|
|
|
IF r.kind = 5 THEN
|
|
|
- (* A string element with a variable index: ParseSub already computed its
|
|
|
- address into DI (LEA DI,[base] / ADD DI,AX), so the byte is at [DI].
|
|
|
- Zeroing AH keeps the value a clean 16-bit char, the same thing the
|
|
|
- size-1 load below does, because every consumer of a CHAR expects the
|
|
|
- high half to be zero. The read must happen HERE, before anything
|
|
|
- else is emitted: the caller reaches this immediately after parsing
|
|
|
- the subscript, or - for a binary operator - SaveLeft has already
|
|
|
- materialised it, so DI is still the element's address. *)
|
|
|
- EmLdAlDi () ;
|
|
|
- EmMovAh0 () ;
|
|
|
+ (* An element whose address ParseSub computed into DI (LEA DI,[base] /
|
|
|
+ ADD DI,AX): a string character, or an array element of one or two
|
|
|
+ bytes. Zeroing AH keeps a one-byte value a clean 16-bit char. The
|
|
|
+ read must happen HERE, before anything else is emitted: the caller
|
|
|
+ reaches this immediately after parsing the subscript, or - for a
|
|
|
+ binary operator - SaveLeft has already materialised it, so DI is
|
|
|
+ still the element's address. *)
|
|
|
+ IF VarSize (r) > 2 THEN
|
|
|
+ Err (ENoLib) ; (* a whole record/array as a value *)
|
|
|
+ r.kind := 2 ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ IF VarSize (r) = 2 THEN
|
|
|
+ EmLdAxDi ()
|
|
|
+ ELSE
|
|
|
+ EmLdAlDi () ;
|
|
|
+ EmMovAh0 ()
|
|
|
+ END ;
|
|
|
r.kind := 2 ;
|
|
|
RETURN
|
|
|
END ;
|
|
|
@@ -2250,6 +2261,12 @@ BEGIN
|
|
|
(* FIELD selection: `r.f'. The field's offset adds to the record
|
|
|
base's, and the value's class and WIDTH become the field's - which
|
|
|
is the whole reason a width rides on the expression (VarSize). *)
|
|
|
+ IF r.kind = 5 THEN
|
|
|
+ (* the element is addressed through DI, not by idx+boff; its field
|
|
|
+ table would have to travel with the expression *)
|
|
|
+ Err (ENoLib) ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
DropCh (GetCh ()) ;
|
|
|
Skip () ;
|
|
|
IF NOT Alpha (CurCh ()) THEN
|
|
|
@@ -2314,25 +2331,53 @@ BEGIN
|
|
|
r.cls := TChar ;
|
|
|
r.sz := 1
|
|
|
ELSIF symtab [r.idx].cls = TArray THEN
|
|
|
- (* A constant array subscript. The element's address is
|
|
|
+ (* An array subscript. The element's address is
|
|
|
(index - lower bound) * element size from the array base, and
|
|
|
the value's width and class become the ELEMENT's - so a store
|
|
|
writes two bytes for an `array of Integer', not the whole
|
|
|
- array. A VARIABLE index needs scaled run-time addressing and
|
|
|
- is the next increment. *)
|
|
|
- IF t.kind # 0 THEN
|
|
|
- Err (ENoLib) ;
|
|
|
+ array. *)
|
|
|
+ IF symtab [r.idx].arrIdx = 0 THEN
|
|
|
+ Err (ESimpType) ;
|
|
|
RETURN
|
|
|
END ;
|
|
|
- IF symtab [r.idx].arrIdx > 0 THEN
|
|
|
- ai := symtab [r.idx].arrIdx - 1 ;
|
|
|
+ ai := symtab [r.idx].arrIdx - 1 ;
|
|
|
+ IF t.kind = 0 THEN
|
|
|
+ (* constant index: fold it into boff, as before *)
|
|
|
r.boff := W16 (VAL (LONGINT, r.boff)
|
|
|
+ (t.imm - arrs [ai].lo [0])
|
|
|
* VAL (LONGINT, arrs [ai].elem)) ;
|
|
|
r.sz := arrs [ai].elem ;
|
|
|
r.cls := arrs [ai].ecls
|
|
|
+ ELSIF arrs [ai].n = 1 THEN
|
|
|
+ (* Run-time index, one dimension: AX := (i - lo) * elem,
|
|
|
+ then DI := base + AX. The element's address rides in DI
|
|
|
+ exactly as a string element's does, so LoadAtom,
|
|
|
+ Assignment, IoCall and SaveLeft already know the shape;
|
|
|
+ only the WIDTH is new (1 or 2 bytes, not always a char). *)
|
|
|
+ IF r.kind = 5 THEN
|
|
|
+ (* a second subscript on an element already addressed
|
|
|
+ through DI: 2-D run-time indexing is not implemented *)
|
|
|
+ Err (ENoLib) ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ LoadAtom (t) ;
|
|
|
+ EmMovCxi (W16 (arrs [ai].lo [0])) ;
|
|
|
+ EmSubAxCx () ;
|
|
|
+ IF arrs [ai].elem # 1 THEN
|
|
|
+ EmMovCxi (arrs [ai].elem) ;
|
|
|
+ EmMulAxCx ()
|
|
|
+ END ;
|
|
|
+ EmLeaDi (symtab [r.idx].local,
|
|
|
+ (symtab [r.idx].off + r.boff) MOD 10000H) ;
|
|
|
+ EmAddDiAx () ;
|
|
|
+ r.kind := 5 ;
|
|
|
+ r.sz := arrs [ai].elem ;
|
|
|
+ r.cls := arrs [ai].ecls
|
|
|
ELSE
|
|
|
- Err (ESimpType) ;
|
|
|
+ (* two or more dimensions and a run-time index: the row
|
|
|
+ stride is (hi1 - lo1 + 1) * elem, which is the next
|
|
|
+ increment; loud, not a wrong address. *)
|
|
|
+ Err (ENoLib) ;
|
|
|
RETURN
|
|
|
END
|
|
|
ELSIF t.kind # 0 THEN
|
|
|
@@ -3685,35 +3730,30 @@ BEGIN
|
|
|
RETURN
|
|
|
END ;
|
|
|
IF (r.kind = 5) OR (VarSize (r) > 2) THEN
|
|
|
- IF (r.cls # TChar) OR (r.kind = 1) THEN
|
|
|
- Err (ENoLib) ;
|
|
|
- RETURN
|
|
|
- END ;
|
|
|
- (* s[i] := c : one byte, either at off+boff (a constant index) or at [DI]
|
|
|
- (a variable one, r.kind = 5). The whole-string path above was skipped
|
|
|
- because r.cls is TChar, not TString, so this is the element store; a
|
|
|
- plain char variable has size 1 and takes the scalar path below
|
|
|
- instead.
|
|
|
-
|
|
|
- For a variable index the destination address is in DI, and the
|
|
|
- right-hand side is parsed next, so DI has to be saved first - the RHS
|
|
|
- may hold a subscript of its own, which reuses DI, or call a routine
|
|
|
- that clobbers it. This is TPSRC8 asnscal2/asnscal3 (758-760,
|
|
|
- 786-789), which set flgpshdi around the expression for the same
|
|
|
- reason. After the save, DI is free for the RHS, and the store reads
|
|
|
- it back. *)
|
|
|
- IF r.kind = 5 THEN
|
|
|
- EmPushDi ()
|
|
|
- END ;
|
|
|
- ParseExpr (src) ;
|
|
|
- LoadAtom (src) ;
|
|
|
IF r.kind = 5 THEN
|
|
|
+ (* An element addressed by DI: a string character (one byte) or an
|
|
|
+ array element (one or two). A wider element - a record - is
|
|
|
+ refused rather than stored as its first two bytes.
|
|
|
+
|
|
|
+ The destination address is in DI, and the right-hand side is
|
|
|
+ parsed next, so DI has to be saved first - the RHS may hold a
|
|
|
+ subscript of its own, which reuses DI, or call a routine that
|
|
|
+ clobbers it. This is TPSRC8 asnscal2/asnscal3 (758-760, 786-789),
|
|
|
+ which set flgpshdi around the expression for the same reason. *)
|
|
|
+ IF VarSize (r) > 2 THEN
|
|
|
+ Err (ENoLib) ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ EmPushDi () ;
|
|
|
+ ParseExpr (src) ;
|
|
|
+ LoadAtom (src) ;
|
|
|
EmPopDi () ; (* DI := the destination again *)
|
|
|
- EmStDiAl () (* [DI] := AL *)
|
|
|
- ELSE
|
|
|
- EmStoreVar (symtab [r.idx].local,
|
|
|
- (symtab [r.idx].off + r.boff) MOD 10000H, 1)
|
|
|
+ EmStoreInd (VarSize (r)) ; (* [DI] := AL or AX *)
|
|
|
+ RETURN
|
|
|
END ;
|
|
|
+ (* A value wider than a word with no address to store through: an
|
|
|
+ assignment to a whole string/record/array is not a scalar store. *)
|
|
|
+ Err (ENoLib) ;
|
|
|
RETURN
|
|
|
END ;
|
|
|
ParseExpr (src) ;
|
|
|
@@ -4832,7 +4872,12 @@ BEGIN
|
|
|
IF Search (wrd, idx) AND (symtab [idx].tag = KType) THEN
|
|
|
cls := symtab [idx].cls ;
|
|
|
size := symtab [idx].size ;
|
|
|
- elem := symtab [idx].size ;
|
|
|
+ (* The type's ELEMENT size, not its total size. They are equal for
|
|
|
+ a record, but not for an array (`Letters' is 6 bytes of 3
|
|
|
+ Integers) or a file. A named array typed constant used to get
|
|
|
+ typElem = 6, wrote six bytes per element and wrapped the
|
|
|
+ little-endian divider to zero: SIGFPE in DefConst. *)
|
|
|
+ elem := symtab [idx].elem ;
|
|
|
enumLo := symtab [idx].lo ;
|
|
|
enumHi := symtab [idx].hi ;
|
|
|
recFldFirst := symtab [idx].fldFirst ;
|