|
|
@@ -115,6 +115,13 @@ CONST
|
|
|
(* which standard procedure a KBuiltin symbol denotes *)
|
|
|
BI_Write = 0 ; BI_WriteLn = 1 ; BI_Read = 2 ;
|
|
|
BI_ReadLn = 3 ; BI_Halt = 4 ; BI_Length = 5 ;
|
|
|
+ (* CRT identifiers. There is no unit system, so these are builtins. They
|
|
|
+ are statements (except Length), dispatched in IoCall; each one that is
|
|
|
+ not implemented yet is a loud ENoLib, never a silent no-op. *)
|
|
|
+ BI_ClrScr = 6 ; BI_GotoXY = 7 ; BI_LowVideo = 8 ;
|
|
|
+ BI_NormVideo = 9 ; BI_ClrEol = 10 ; BI_Delay = 11 ;
|
|
|
+ (* the sub-codes EmCrtSeq takes *)
|
|
|
+ CrtClr = 0 ; CrtDl = 1 ; CrtDh = 2 ; CrtCaret = 3 ;
|
|
|
|
|
|
(* keyword tokens *)
|
|
|
TkNone = 0 ; TkProgram = 1 ; TkBegin = 2 ; TkEnd = 3 ;
|
|
|
@@ -979,6 +986,11 @@ BEGIN
|
|
|
Ebyte (5EH) (* POP SI *)
|
|
|
END EmPopSi ;
|
|
|
|
|
|
+PROCEDURE EmPopAx () ;
|
|
|
+BEGIN
|
|
|
+ Ebyte (58H) (* POP AX *)
|
|
|
+END EmPopAx ;
|
|
|
+
|
|
|
(* 91 = XCHG AX,CX, and NOT 93. LoadPair hands the operator the left
|
|
|
operand in CX and the right in AX (in the original, and still the
|
|
|
commonest, shape: it pushes the left, loads the right, then pops the
|
|
|
@@ -3613,6 +3625,40 @@ BEGIN
|
|
|
END
|
|
|
END Compound ;
|
|
|
|
|
|
+PROCEDURE EmCrtSeq (which : CARDINAL) ;
|
|
|
+(* The CRT byte sequences, in one parameterised helper. Every one is a fixed
|
|
|
+ BIOS call:
|
|
|
+ CrtClr - INT 10h AH=06 blank the whole window, then AH=02 home the cursor
|
|
|
+ CrtDl - DEC AX ; MOV DL,AL (a 1-based column -> 0-based)
|
|
|
+ CrtDh - DEC AX ; MOV DH,AL (a 1-based row)
|
|
|
+ CrtCaret - INT 10h AH=02, page 0, cursor at DH,DL
|
|
|
+ It takes a parameter on purpose: audit_helpers audits helpers with an EMPTY
|
|
|
+ parameter list byte-for-byte, and these multi-instruction sequences have no
|
|
|
+ single name grammar. Listed as COMP in NON_ONE_LINE, like SetBlob. *)
|
|
|
+BEGIN
|
|
|
+ IF which = CrtClr THEN
|
|
|
+ Ebyte (0B8H) ; Ebyte (00H) ; Ebyte (06H) ; (* MOV AX,0600h *)
|
|
|
+ Ebyte (0B7H) ; Ebyte (07H) ; (* MOV BH,07h *)
|
|
|
+ Ebyte (0B9H) ; Ebyte (00H) ; Ebyte (00H) ; (* MOV CX,0000h *)
|
|
|
+ Ebyte (0BAH) ; Ebyte (4FH) ; Ebyte (18H) ; (* MOV DX,184Fh *)
|
|
|
+ Ebyte (0CDH) ; Ebyte (10H) ; (* INT 10h *)
|
|
|
+ Ebyte (0B8H) ; Ebyte (00H) ; Ebyte (02H) ; (* MOV AX,0200h *)
|
|
|
+ Ebyte (0B7H) ; Ebyte (00H) ; (* MOV BH,00h *)
|
|
|
+ Ebyte (0BAH) ; Ebyte (00H) ; Ebyte (00H) ; (* MOV DX,0000h *)
|
|
|
+ Ebyte (0CDH) ; Ebyte (10H) (* INT 10h *)
|
|
|
+ ELSIF which = CrtDl THEN
|
|
|
+ Ebyte (48H) ; (* DEC AX *)
|
|
|
+ Ebyte (88H) ; Ebyte (0C2H) (* MOV DL,AL *)
|
|
|
+ ELSIF which = CrtDh THEN
|
|
|
+ Ebyte (48H) ; (* DEC AX *)
|
|
|
+ Ebyte (88H) ; Ebyte (0C6H) (* MOV DH,AL *)
|
|
|
+ ELSE
|
|
|
+ Ebyte (0B4H) ; Ebyte (02H) ; (* MOV AH,02h *)
|
|
|
+ Ebyte (0B7H) ; Ebyte (00H) ; (* MOV BH,00h *)
|
|
|
+ Ebyte (0CDH) ; Ebyte (10H) (* INT 10h *)
|
|
|
+ END
|
|
|
+END EmCrtSeq ;
|
|
|
+
|
|
|
PROCEDURE IoCall (idx : CARDINAL) ;
|
|
|
(* WRITE / WRITELN / READ / READLN / HALT.
|
|
|
|
|
|
@@ -3640,6 +3686,43 @@ BEGIN
|
|
|
DropC (EmCall (TU_Halt)) ;
|
|
|
RETURN
|
|
|
END ;
|
|
|
+ IF which = BI_ClrScr THEN
|
|
|
+ EmCrtSeq (CrtClr) ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ IF which = BI_GotoXY THEN
|
|
|
+ (* GotoXY (x, y): 1-based; evaluate x first and park it, then y, so the
|
|
|
+ code for y cannot clobber DL. *)
|
|
|
+ IF MatchDelim ('(') THEN
|
|
|
+ ParseExpr (dummy) ;
|
|
|
+ IF OK () THEN
|
|
|
+ LoadAtom (dummy) ;
|
|
|
+ EmPushAx ()
|
|
|
+ END ;
|
|
|
+ ExpectDelim (',', ENoSemi) ;
|
|
|
+ ParseExpr (dummy) ;
|
|
|
+ IF OK () THEN
|
|
|
+ LoadAtom (dummy) ;
|
|
|
+ EmCrtSeq (CrtDh)
|
|
|
+ END ;
|
|
|
+ ExpectDelim (')', ENoSemi) ;
|
|
|
+ EmPopAx () ;
|
|
|
+ EmCrtSeq (CrtDl) ;
|
|
|
+ EmCrtSeq (CrtCaret)
|
|
|
+ ELSE
|
|
|
+ Err (ENoSemi)
|
|
|
+ END ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
+ IF (which = BI_LowVideo) OR (which = BI_NormVideo) OR
|
|
|
+ (which = BI_ClrEol) OR (which = BI_Delay) THEN
|
|
|
+ (* Catalogued, and LOUD. Their screen behaviour is a later question
|
|
|
+ (CALC-COMPILE.md Stage 14: a compiling CALC needs them to resolve, a
|
|
|
+ RUNNING one needs them right), but a silent no-op would be exactly the
|
|
|
+ §7 bug - a construct that parses and emits nothing. *)
|
|
|
+ Err (ENoLib) ;
|
|
|
+ RETURN
|
|
|
+ END ;
|
|
|
reading := (which = BI_Read) OR (which = BI_ReadLn) ;
|
|
|
nArgs := 0 ;
|
|
|
IF MatchDelim ('(') THEN
|
|
|
@@ -5115,7 +5198,22 @@ BEGIN
|
|
|
symtab [i].goPos := TU_Halt ;
|
|
|
i := NewSym ("LENGTH" , KBuiltin, BI_Length , 0, 0, 0, 0, FALSE) ;
|
|
|
symtab [i].defnd := TRUE ;
|
|
|
- symtab [i].goPos := 0 (* inline: the length byte, no entry *)
|
|
|
+ symtab [i].goPos := 0 ; (* inline: the length byte, no entry *)
|
|
|
+ (* The CRT identifiers. ClrScr and GotoXY emit real INT 10h code; the other
|
|
|
+ four are registered so they are recognised, and IoCall refuses them with
|
|
|
+ ENoLib - loud, not inert. *)
|
|
|
+ i := NewSym ("CLRSCR" , KBuiltin, BI_ClrScr , 0, 0, 0, 0, FALSE) ;
|
|
|
+ symtab [i].defnd := TRUE ;
|
|
|
+ i := NewSym ("GOTOXY" , KBuiltin, BI_GotoXY , 0, 0, 0, 0, FALSE) ;
|
|
|
+ symtab [i].defnd := TRUE ;
|
|
|
+ i := NewSym ("LOWVIDEO", KBuiltin, BI_LowVideo, 0, 0, 0, 0, FALSE) ;
|
|
|
+ symtab [i].defnd := TRUE ;
|
|
|
+ i := NewSym ("NORMVIDEO", KBuiltin, BI_NormVideo, 0, 0, 0, 0, FALSE) ;
|
|
|
+ symtab [i].defnd := TRUE ;
|
|
|
+ i := NewSym ("CLREOL" , KBuiltin, BI_ClrEol , 0, 0, 0, 0, FALSE) ;
|
|
|
+ symtab [i].defnd := TRUE ;
|
|
|
+ i := NewSym ("DELAY" , KBuiltin, BI_Delay , 0, 0, 0, 0, FALSE) ;
|
|
|
+ symtab [i].defnd := TRUE
|
|
|
END DefBuiltins ;
|
|
|
|
|
|
PROCEDURE Inittur () ;
|