Browse Source

compiler+runtime: write field widths (writeln(I:2))

CALC.INC:135 is `writeln(I:2)'.  IoCall read the expression and then
demanded ',' or ')', so the ':' was ENoSemi.  A write argument may now
carry a width, and the width is an EXPRESSION - CALC passes FW, a
variable - so it is parsed and pushed after the value.

Runtime entry 20, wrintw: value at [BP+6], width at [BP+4].  It counts
the characters the signed decimal will occupy (the '-' included), prints
max(width - chars, 0) spaces, then the number.  The digit loop duplicates
wrint's rather than jumping into its frame: the two entries have
different argument offsets, and a hidden convention between them would
be worse than 40 bytes.  Only integers have a width entry yet; a
CHAR/BOOLEAN/STRING width is ENoLib, and `:decimals' (the REAL form,
CALC's Value:FW:DEC) is too.

The runtime grows 770 -> 878 bytes, so runtime.golden is re-blessed (the
new entry plus the expected shift of every later offset and data
address); tests/RtProbe reports the new entry, check_runtime gains a
semantic golden for wrintw (PUSH BP; MOV BP,SP; BX:=0; AX:=[BP+6]),
which a wrong argument offset would fail even though it decodes.

t76_width exercises widths 3/5/4, the negative sign, a width narrower
than the number, width from a variable, width 1, and no width.  A
non-vacuity case routes the width through plain wrint; the caller still
pushes both words, so it prints widths instead of numbers.

The ladder moves 14330 -> 15026, now `with Sheet[I,J]': the 2-D
variable subscript (row stride) and `with' over a DI-addressed record.
Eric Streit 2 days ago
parent
commit
099f8fd569

+ 31 - 2
shell/Compiler.mod

@@ -353,7 +353,8 @@ VAR
    TU_InitMem  : CARDINAL ;
    TU_InitMem  : CARDINAL ;
    TU_ProgEnd  : CARDINAL ;
    TU_ProgEnd  : CARDINAL ;
    TU_StackChk : CARDINAL ;
    TU_StackChk : CARDINAL ;
-   TU_WrInt    : CARDINAL ;  TU_WrChar : CARDINAL ;  TU_WrBool : CARDINAL ;
+   TU_WrInt    : CARDINAL ;  TU_WrIntW : CARDINAL ;
+   TU_WrChar   : CARDINAL ;  TU_WrBool : CARDINAL ;
    TU_WrReal   : CARDINAL ;  TU_WrLn   : CARDINAL ;
    TU_WrReal   : CARDINAL ;  TU_WrLn   : CARDINAL ;
    TU_RdInt    : CARDINAL ;  TU_RdChar : CARDINAL ;  TU_RdBool : CARDINAL ;
    TU_RdInt    : CARDINAL ;  TU_RdChar : CARDINAL ;  TU_RdBool : CARDINAL ;
    TU_RdLn     : CARDINAL ;  TU_Halt   : CARDINAL ;
    TU_RdLn     : CARDINAL ;  TU_Halt   : CARDINAL ;
@@ -3877,6 +3878,8 @@ PROCEDURE IoCall (idx : CARDINAL) ;
    cleans the argument off the stack. *)
    cleans the argument off the stack. *)
 VAR arg : ERes ;
 VAR arg : ERes ;
     nArgs, ent, which, acls : CARDINAL ;
     nArgs, ent, which, acls : CARDINAL ;
+    argBytes : CARDINAL ;       (* bytes pushed for this argument: 2, or 4 with
+                                   a field width *)
     reading : BOOLEAN ;
     reading : BOOLEAN ;
     pushed : BOOLEAN ;
     pushed : BOOLEAN ;
     skipArg : BOOLEAN ;
     skipArg : BOOLEAN ;
@@ -4006,6 +4009,7 @@ BEGIN
             END ;
             END ;
             IF NOT skipArg THEN
             IF NOT skipArg THEN
             pushed := TRUE ;      (* default: value is on the stack -> call + pop *)
             pushed := TRUE ;      (* default: value is on the stack -> call + pop *)
+            argBytes := 2 ;
             IF reading THEN
             IF reading THEN
                IF (arg.kind # 1) AND (arg.kind # 5) THEN
                IF (arg.kind # 1) AND (arg.kind # 5) THEN
                   Err (ETypeErr) ;                  (* READ needs a variable *)
                   Err (ETypeErr) ;                  (* READ needs a variable *)
@@ -4137,13 +4141,37 @@ BEGIN
                      ELSE
                      ELSE
                         Err (ETypeErr) ;
                         Err (ETypeErr) ;
                         RETURN
                         RETURN
+                     END ;
+                     IF MatchDelim (':') THEN
+                        (* Field width: `writeln(I:2)'.  TP3 evaluates the
+                           width (CALC passes `FW', a variable), so it is
+                           parsed and pushed AFTER the value: width at BP+4,
+                           value at BP+6.  Only an integer has a width entry
+                           yet - a CHAR/BOOLEAN/STRING width needs its own
+                           writer, and `:decimals' is the REAL form. *)
+                        IF (acls # TScalar) OR arg.chr THEN
+                           Err (ENoLib) ;
+                           RETURN
+                        END ;
+                        ParseExpr (dummy) ;
+                        IF NOT OK () THEN
+                           RETURN
+                        END ;
+                        LoadAtom (dummy) ;
+                        EmPushAx () ;
+                        IF MatchDelim (':') THEN
+                           Err (ENoLib) ;
+                           RETURN
+                        END ;
+                        ent := TU_WrIntW ;
+                        argBytes := 4
                      END
                      END
                   END
                   END
                END
                END
             END ;
             END ;
             IF pushed THEN
             IF pushed THEN
                DropC (EmCall (ent)) ;
                DropC (EmCall (ent)) ;
-               EmAddSp (2)                         (* one 16-bit argument *)
+               EmAddSp (argBytes)                  (* 2, or 4 with a width *)
             END ;
             END ;
                INC (nArgs)
                INC (nArgs)
             END ;
             END ;
@@ -5761,6 +5789,7 @@ BEGIN
    TU_CmpStr   := RT_Entry (18) ;      (* string compare: TPSRC9 vcompare,
    TU_CmpStr   := RT_Entry (18) ;      (* string compare: TPSRC9 vcompare,
                                           TPSRC2 cmpstr *)
                                           TPSRC2 cmpstr *)
    TU_StrCat   := RT_Entry (19) ;      (* string concatenation: TPSRC2 xconcat *)
    TU_StrCat   := RT_Entry (19) ;      (* string concatenation: TPSRC2 xconcat *)
+   TU_WrIntW   := RT_Entry (20) ;      (* width-aware integer: `I:2' *)
 END Inittur ;
 END Inittur ;
 
 
 PROCEDURE HeadWord (VAR slot : CARDINAL) ;
 PROCEDURE HeadWord (VAR slot : CARDINAL) ;

+ 4 - 0
shell/Runtime.def

@@ -46,6 +46,10 @@ CONST
                                exact shape; appends src to dest and leaves
                                exact shape; appends src to dest and leaves
                                exit code 16 (TP3's `String too long') if
                                exit code 16 (TP3's `String too long') if
                                dest[0]+src[0] exceeds CX; TPSRC2 xconcat *)
                                dest[0]+src[0] exceeds CX; TPSRC2 xconcat *)
+   E_WrIntW  = 20 ;         (* width-aware integer, for `writeln(I:2)': the
+                               value is at [BP+6] and the field width at
+                               [BP+4]; pads with spaces on the left when the
+                               number is shorter than the width *)
 
 
    (* Where a .COM's first byte ends up.  DOS loads a .COM at CS:0100 (the
    (* Where a .COM's first byte ends up.  DOS loads a .COM at CS:0100 (the
       100 bytes below are the PSP), and CS = DS, so an image offset K is at
       100 bytes below are the PSP), and CS = DS, so an image offset K is at

+ 75 - 3
shell/Runtime.mod

@@ -127,7 +127,7 @@ VAR
    dataAt : CARDINAL ;
    dataAt : CARDINAL ;
    rtBase : CARDINAL ;
    rtBase : CARDINAL ;
    built  : BOOLEAN ;
    built  : BOOLEAN ;
-   entNm  : ARRAY [0..19] OF ARRAY [0..MaxNm] OF CHAR ;
+   entNm  : ARRAY [0..20] OF ARRAY [0..MaxNm] OF CHAR ;
 
 
 (* ---------------------------------------------------------------- *)
 (* ---------------------------------------------------------------- *)
 (*  name helpers                                                     *)
 (*  name helpers                                                     *)
@@ -403,6 +403,7 @@ PROCEDURE CmpCxV  (v : CARDINAL ) ; BEGIN B (83H) ; B (0F9H) ; B (v) END CmpCxV
 
 
 PROCEDURE AddDl (v : CARDINAL ) ; BEGIN B (80H) ; B (0C2H) ; B (v) END AddDl ;
 PROCEDURE AddDl (v : CARDINAL ) ; BEGIN B (80H) ; B (0C2H) ; B (v) END AddDl ;
 PROCEDURE SubAl (v : CARDINAL ) ; BEGIN B (2CH) ; B (v) END SubAl ;
 PROCEDURE SubAl (v : CARDINAL ) ; BEGIN B (2CH) ; B (v) END SubAl ;
+PROCEDURE SubAxBx ; BEGIN B (2BH) ; B (0C3H) END SubAxBx ;  (* 2B C3: AX:=AX-BX *)
 PROCEDURE NegAx ; BEGIN B (0F7H) ; B (0D8H) END NegAx ;
 PROCEDURE NegAx ; BEGIN B (0F7H) ; B (0D8H) END NegAx ;
 PROCEDURE NegDi ; BEGIN B (0F7H) ; B (0DFH) END NegDi ;
 PROCEDURE NegDi ; BEGIN B (0F7H) ; B (0DFH) END NegDi ;
 PROCEDURE DivCx ; BEGIN B (0F7H) ; B (0F1H) END DivCx ;   (* 11 110 001 *)
 PROCEDURE DivCx ; BEGIN B (0F7H) ; B (0F1H) END DivCx ;   (* 11 110 001 *)
@@ -474,6 +475,7 @@ PROCEDURE MovDxSi2 ; BEGIN B (8BH) ; B (54H) ; B (2) END MovDxSi2 ;
    reads against the same header offsets it verifies the words at. *)
    reads against the same header offsets it verifies the words at. *)
 PROCEDURE MovDxSi4 ; BEGIN B (8BH) ; B (54H) ; B (4) END MovDxSi4 ;
 PROCEDURE MovDxSi4 ; BEGIN B (8BH) ; B (54H) ; B (4) END MovDxSi4 ;
 PROCEDURE MovAxBp4 ; BEGIN B (8BH) ; B (46H) ; B (4) END MovAxBp4 ;  (* AX:=[BP+4] *)
 PROCEDURE MovAxBp4 ; BEGIN B (8BH) ; B (46H) ; B (4) END MovAxBp4 ;  (* AX:=[BP+4] *)
+PROCEDURE MovAxBp6 ; BEGIN B (8BH) ; B (46H) ; B (6) END MovAxBp6 ;  (* AX:=[BP+6] *)
 PROCEDURE MovBxBp4 ; BEGIN B (8BH) ; B (5EH) ; B (4) END MovBxBp4 ;  (* BX:=[BP+4] *)
 PROCEDURE MovBxBp4 ; BEGIN B (8BH) ; B (5EH) ; B (4) END MovBxBp4 ;  (* BX:=[BP+4] *)
 PROCEDURE MovBxBp6 ; BEGIN B (8BH) ; B (5EH) ; B (6) END MovBxBp6 ;  (* BX:=[BP+6] *)
 PROCEDURE MovBxBp6 ; BEGIN B (8BH) ; B (5EH) ; B (6) END MovBxBp6 ;  (* BX:=[BP+6] *)
 PROCEDURE MovAlDh  ; BEGIN B (8AH) ; B (0C6H) END MovAlDh ;  (* 8A C6: AL:=DH *)
 PROCEDURE MovAlDh  ; BEGIN B (8AH) ; B (0C6H) END MovAlDh ;  (* 8A C6: AL:=DH *)
@@ -565,6 +567,7 @@ PROCEDURE Jne8 (nm : ARRAY OF CHAR ) ; BEGIN Jcc (75H, nm) END Jne8 ;
 PROCEDURE Jb8  (nm : ARRAY OF CHAR ) ; BEGIN Jcc (72H, nm) END Jb8 ;
 PROCEDURE Jb8  (nm : ARRAY OF CHAR ) ; BEGIN Jcc (72H, nm) END Jb8 ;
 PROCEDURE Jbe8 (nm : ARRAY OF CHAR ) ; BEGIN Jcc (76H, nm) END Jbe8 ;
 PROCEDURE Jbe8 (nm : ARRAY OF CHAR ) ; BEGIN Jcc (76H, nm) END Jbe8 ;
 PROCEDURE Jge8 (nm : ARRAY OF CHAR ) ; BEGIN Jcc (7DH, nm) END Jge8 ;
 PROCEDURE Jge8 (nm : ARRAY OF CHAR ) ; BEGIN Jcc (7DH, nm) END Jge8 ;
+PROCEDURE Jle8 (nm : ARRAY OF CHAR ) ; BEGIN Jcc (7EH, nm) END Jle8 ;
 PROCEDURE Ja8  (nm : ARRAY OF CHAR ) ; BEGIN Jcc (77H, nm) END Ja8 ;
 PROCEDURE Ja8  (nm : ARRAY OF CHAR ) ; BEGIN Jcc (77H, nm) END Ja8 ;
 PROCEDURE Jae8 (nm : ARRAY OF CHAR ) ; BEGIN Jcc (73H, nm) END Jae8 ;
 PROCEDURE Jae8 (nm : ARRAY OF CHAR ) ; BEGIN Jcc (73H, nm) END Jae8 ;
 PROCEDURE Jcxz8 (nm : ARRAY OF CHAR ) ; BEGIN Jcc (0E3H, nm) END Jcxz8 ;
 PROCEDURE Jcxz8 (nm : ARRAY OF CHAR ) ; BEGIN Jcc (0E3H, nm) END Jcxz8 ;
@@ -707,6 +710,74 @@ BEGIN
    MovSpBp ; PopBp ; RetR
    MovSpBp ; PopBp ; RetR
 END EmitWrInt ;
 END EmitWrInt ;
 
 
+PROCEDURE EmitWrIntW ;
+(* `writeln(I:2)': an integer in a field of `width' columns, right-justified.
+   The caller pushes the VALUE first and the WIDTH second, so the value is at
+   [BP+6] and the width at [BP+4].  The number of characters the signed
+   decimal will occupy is counted first (one extra when negative); the pad is
+   max(width - chars, 0) spaces.  The digit loop is wrint's, duplicated rather
+   than shared: the two entries have different argument offsets, and a jump
+   into the middle of the other entry's frame would be a convention nobody
+   could see from either name. *)
+BEGIN
+   M ("wrintw") ;
+   PushBp ; MovBpSp ;
+   (* BX := number of characters: sign + digits *)
+   MovBxImm (0) ;
+   MovAxBp6 ;
+   CmpAx0 ;
+   Jge8 ("wiw_abs") ;
+   IncBx ;                    (* the '-' counts as one column *)
+   NegAx ;
+   M ("wiw_abs") ;
+   MovCxImm (10) ;
+   M ("wiw_cnt") ;
+   IncBx ;
+   XorDxDx ;
+   DivCx ;
+   CmpAx0 ;
+   Jne8 ("wiw_cnt") ;
+   (* pad := width - chars; only a positive pad prints *)
+   MovAxBp4 ;
+   SubAxBx ;
+   CmpAx0 ;
+   Jle8 ("wiw_body") ;
+   MovCxAx ;
+   M ("wiw_pad") ;
+   MovAlD (ORD (' ')) ; MovAh (02H) ; Int21 ;
+   Loop8 ("wiw_pad") ;
+   M ("wiw_body") ;
+   (* the signed decimal, exactly as wrint prints it *)
+   MovAxBp6 ;
+   CmpAx0 ;
+   Jge8 ("wiw_pos") ;
+   PushAx ;
+   MovAlD (ORD ('-')) ; MovAh (2) ; Int21 ;
+   PopAx ;
+   NegAx ;
+   M ("wiw_pos") ;
+   MovCxImm (10) ;
+   MovBxVx (D_NUM + 8) ;
+   MovSiBx ;
+   M ("wiw_dig") ;
+   XorDxDx ;
+   DivCx ;
+   AddDl (ORD ('0')) ;
+   DecSi ;
+   StSiDl ;
+   CmpAx0 ;
+   Jne8 ("wiw_dig") ;
+   M ("wiw_out") ;
+   CmpSiBx ;
+   Je8 ("wiw_done") ;
+   MovAlSi ;
+   MovAh (02H) ; Int21 ;
+   IncSi ;
+   J8 ("wiw_out") ;
+   M ("wiw_done") ;
+   MovSpBp ; PopBp ; RetR
+END EmitWrIntW ;
+
 PROCEDURE EmitWrChar ;
 PROCEDURE EmitWrChar ;
 (* the low byte of the one 16-bit argument, which sits above the return
 (* the low byte of the one 16-bit argument, which sits above the return
    address.  There is no [SP] addressing in 16-bit mode, so BP stands in for
    address.  There is no [SP] addressing in 16-bit mode, so BP stands in for
@@ -1409,7 +1480,7 @@ BEGIN
    EmitInitMem ;
    EmitInitMem ;
    EmitEnd ;
    EmitEnd ;
    EmitStackChk ;
    EmitStackChk ;
-   EmitWrInt ; EmitWrChar ; EmitWrBool ; EmitWrReal ; EmitWrLn ;
+   EmitWrInt ; EmitWrIntW ; EmitWrChar ; EmitWrBool ; EmitWrReal ; EmitWrLn ;
    EmitWrInl ; EmitWrStr ;
    EmitWrInl ; EmitWrStr ;
    EmitRdInt ; EmitRdScan ; EmitRdByte ;
    EmitRdInt ; EmitRdScan ; EmitRdByte ;
    EmitRdChar ; EmitRdBool ; EmitRdLn ;
    EmitRdChar ; EmitRdBool ; EmitRdLn ;
@@ -1437,6 +1508,7 @@ BEGIN
    SetStr (entNm [17], "strstore") ;
    SetStr (entNm [17], "strstore") ;
    SetStr (entNm [18], "cmpstr") ;
    SetStr (entNm [18], "cmpstr") ;
    SetStr (entNm [19], "strcat") ;
    SetStr (entNm [19], "strcat") ;
+   SetStr (entNm [20], "wrintw") ;
    built := TRUE
    built := TRUE
 END RT_Build ;
 END RT_Build ;
 
 
@@ -1464,7 +1536,7 @@ BEGIN
    IF NOT built THEN
    IF NOT built THEN
       RT_Build (0)
       RT_Build (0)
    END ;
    END ;
-   IF i > 19 THEN
+   IF i > 20 THEN
       RETURN 0
       RETURN 0
    END ;
    END ;
    RETURN rtBase + LblOff (entNm [i])
    RETURN rtBase + LblOff (entNm [i])

+ 4 - 3
shell/tests/RtProbe.mod

@@ -108,7 +108,7 @@ END PENT ;
 
 
 PROCEDURE Main ;
 PROCEDURE Main ;
 VAR i, n, base : CARDINAL ;
 VAR i, n, base : CARDINAL ;
-    names : ARRAY [0..19] OF ARRAY [0..15] OF CHAR ;
+    names : ARRAY [0..20] OF ARRAY [0..15] OF CHAR ;
 BEGIN
 BEGIN
    base := GetBase () ;
    base := GetBase () ;
    RT_Build (base) ;
    RT_Build (base) ;
@@ -121,7 +121,7 @@ BEGIN
    PCARD (RT_Size ()) ; PS (" bytes") ; NL ;
    PCARD (RT_Size ()) ; PS (" bytes") ; NL ;
    PS ("code ends at ") ; PCARD (RT_CodeEnd ()) ; NL ;
    PS ("code ends at ") ; PCARD (RT_CodeEnd ()) ; NL ;
    i := 0 ;
    i := 0 ;
-   WHILE i <= 19 DO
+   WHILE i <= 20 DO
       names [i] := "" ;
       names [i] := "" ;
       INC (i)
       INC (i)
    END ;
    END ;
@@ -132,8 +132,9 @@ BEGIN
    names [12] := "halt" ;   names [13] := "wrtinl" ;  names [14] := "rdbyte" ;
    names [12] := "halt" ;   names [13] := "wrtinl" ;  names [14] := "rdbyte" ;
    names [15] := "wrstr" ;  names [16] := "rdstr" ;  names [17] := "strstore" ;
    names [15] := "wrstr" ;  names [16] := "rdstr" ;  names [17] := "strstore" ;
    names [18] := "cmpstr" ; names [19] := "strcat" ;
    names [18] := "cmpstr" ; names [19] := "strcat" ;
+   names [20] := "wrintw" ;
    i := 0 ;
    i := 0 ;
-   WHILE i <= 19 DO
+   WHILE i <= 20 DO
       PENT (i, names [i]) ;
       PENT (i, names [i]) ;
       INC (i)
       INC (i)
    END ;
    END ;

+ 5 - 0
shell/tests/check_runtime.py

@@ -123,6 +123,11 @@ GOLDEN = {
     "stackchk": "C3",                       # the no-op: a bare RET, by design
     "stackchk": "C3",                       # the no-op: a bare RET, by design
     "progend": "31 C0 B4 4C CD 21 C3",      # XOR AX,AX; AH:=$4C; INT 21h; RET
     "progend": "31 C0 B4 4C CD 21 C3",      # XOR AX,AX; AH:=$4C; INT 21h; RET
     "wrint": "55 8B EC 8B 46 04",           # PUSH BP; MOV BP,SP; AX:=[BP+4]
     "wrint": "55 8B EC 8B 46 04",           # PUSH BP; MOV BP,SP; AX:=[BP+4]
+    # wrintw reads the VALUE at [BP+6] (the width is at [BP+4]), because the
+    # caller pushes the value first and the width second.  BX starts at 0 and
+    # becomes the character count.  Wrong offsets here would print a width
+    # as a number and a value as a width, both plausible and both silent.
+    "wrintw": "55 8B EC BB 00 00 8B 46 06",  # PUSH BP; MOV BP,SP; BX:=0; AX:=[BP+6]
     # wrchar: AL, not DL.  DOS INT 21h AH=02h takes the character in AL, and
     # wrchar: AL, not DL.  DOS INT 21h AH=02h takes the character in AL, and
     # DL is the *other* 8086 convention (BIOS teletype).  This read DL, so
     # DL is the *other* 8086 convention (BIOS teletype).  This read DL, so
     # every write of a character printed whatever the *last* character read
     # every write of a character printed whatever the *last* character read

+ 6 - 5
shell/tests/fixtures/calc_ladder.tsv

@@ -25,8 +25,9 @@
 # positions shift — which is exactly why this must be a measured number, not a
 # positions shift — which is exactly why this must be a measured number, not a
 # remembered one.
 # remembered one.
 #
 #
-# Current rung (2026-10-21): `writeln(I:2)' in CALC.INC's DisplayP - a WRITE
-# FIELD WIDTH.  Variable array subscripts landed (t75_arrvar), moving
-# 14195 -> 14330.  The parser reads the expression and then demands ',' or
-# ')', so the ':' is ENoSemi.
-CALC.PAS	ERR	1	14330
+# Current rung (2026-10-21): `with Sheet[I,J] do' in CALC.INC's DisplayP.
+# Integer write field widths landed (t76_width + the wrintw runtime entry),
+# moving 14330 -> 15026.  The blocker is now `with' over a TWO-DIMENSIONAL
+# array element: Sheet[I,J] needs the variable-index row stride, and `with'
+# needs the record's field table to follow the DI-addressed element.
+CALC.PAS	ERR	102	15026

+ 4 - 0
shell/tests/fixtures/expected.tsv

@@ -581,3 +581,7 @@ t74_caselist	OK	579	8
 #                   indexed by Char, a LOCAL array, and a RHS that itself
 #                   indexed by Char, a LOCAL array, and a RHS that itself
 #                   subscripts (DI must survive the parse).
 #                   subscripts (DI must survive the parse).
 t75_arrvar	OK	452	23
 t75_arrvar	OK	452	23
+#   t76_width              write field widths (`writeln(I:2)'): the width is
+#                   an expression pushed after the value; wrintw pads with
+#                   spaces (sign counted); a narrow width does not truncate.
+t76_width	OK	258	9

+ 8 - 0
shell/tests/fixtures/t76_width.out

@@ -0,0 +1,8 @@
+  7|
+   42|
+  -7|
+123|
+ 0|
+     7|
+7|
+7|

+ 28 - 0
shell/tests/fixtures/t76_width.pas

@@ -0,0 +1,28 @@
+program t76_width;
+
+{ t76 -- write FIELD WIDTHS.
+
+  CALC.INC:135 is `writeln(I:2)'; DisplayCell later uses `Value:FW:DEC', the
+  REAL form, which waits for real support.  The width is an EXPRESSION (CALC
+  passes FW, a variable), and it is pushed after the value, so the runtime's
+  wrintw reads the value at [BP+6] and the width at [BP+4].
+
+  Right-justification: pad = width - characters, the sign counting as one; a
+  width narrower than the number does not truncate it.  The last two lines
+  are the no-width and width-1 cases, so a writer that always pads (or never
+  does) is caught as well. }
+
+var
+   i, w : integer;
+begin
+   i := 7;
+   writeln (i:3, '|');
+   writeln (42:5, '|');
+   writeln (-7:4, '|');
+   writeln (123:2, '|');
+   writeln (0:2, '|');
+   w := 6;
+   writeln (i:w, '|');
+   writeln (i:1, '|');
+   writeln (i, '|')
+end.

+ 18 - 0
shell/tests/nonvacuity.sh

@@ -1875,6 +1875,24 @@ else
 fi
 fi
 cp "$SAVED_C" Compiler.mod
 cp "$SAVED_C" Compiler.mod
 
 
+# --- a field width reaches the width-aware writer -------------------------
+# Call wrint instead of wrintw.  The caller still pushes the value and the
+# width and still cleans up four bytes, so wrint reads the WIDTH as its value
+# and the stack stays balanced: t76 prints the widths, not the numbers.
+cp "$SAVED_C" Compiler.mod
+if mutate_compiler 's|ent := TU_WrIntW ;|ent := TU_WrInt ;|'; then
+    if rebuild_compiler; then
+        expect_red "t76 red when a width calls the plain integer writer"             "FAIL" python3 tests/run_com_exec.py t76_width
+    else
+        echo "  FAIL: the compiler would not rebuild with the plain writer"
+        fail=$((fail + 1))
+    fi
+else
+    echo "  BROKEN CASE: the width-entry mutation did not apply"
+    fail=$((fail + 1))
+fi
+cp "$SAVED_C" Compiler.mod
+
 if rebuild_compiler; then
 if rebuild_compiler; then
     if python3 tests/run_com_exec.py >/dev/null 2>&1; then
     if python3 tests/run_com_exec.py >/dev/null 2>&1; then
         echo "  ok: every executed fixture passes on the restored sources"
         echo "  ok: every executed fixture passes on the restored sources"

+ 420 - 368
shell/tests/runtime.golden

@@ -41,7 +41,7 @@
 0036  58          pop ax
 0036  58          pop ax
 0037  F7 D8       neg ax
 0037  F7 D8       neg ax
 0039  B9 0A 00    mov cx,0ah
 0039  B9 0A 00    mov cx,0ah
-003C  BB EB 03    mov bx,3ebh
+003C  BB 57 04    mov bx,457h
 003F  89 DE       mov si,bx
 003F  89 DE       mov si,bx
 0041  31 D2       xor dx,dx
 0041  31 D2       xor dx,dx
 0043  F7 F1       div ax,cx
 0043  F7 F1       div ax,cx
@@ -62,371 +62,423 @@
 0060  C3          ret
 0060  C3          ret
 0061  55          push bp
 0061  55          push bp
 0062  8B EC       mov bp,sp
 0062  8B EC       mov bp,sp
-0064  8A 46 04    mov al,byte ptr [bp+4h]
-0067  89 EC       mov sp,bp
-0069  5D          pop bp
-006A  B4 02       mov ah,2h
-006C  CD 21       int 21h
-006E  C3          ret
-006F  55          push bp
-0070  8B EC       mov bp,sp
-0072  83 7E 04 00 cmp word ptr [bp+4h],0h
-0076  89 EC       mov sp,bp
-0078  75 05       jne 7fh
-007A  BA F0 03    mov dx,3f0h
-007D  EB 03       jmp 82h
-007F  BA EB 03    mov dx,3ebh
-0082  B4 09       mov ah,9h
-0084  CD 21       int 21h
-0086  5D          pop bp
-0087  C3          ret
-0088  BA F9 03    mov dx,3f9h
-008B  B4 09       mov ah,9h
-008D  CD 21       int 21h
-008F  C3          ret
-0090  BA F6 03    mov dx,3f6h
-0093  B4 09       mov ah,9h
-0095  CD 21       int 21h
-0097  C3          ret
-0098  5B          pop bx
-0099  31 C9       xor cx,cx
-009B  8A 0F       mov cl,byte ptr [bx]
-009D  43          inc bx
+0064  BB 00 00    mov bx,0h
+0067  8B 46 06    mov ax,word ptr [bp+6h]
+006A  83 F8 00    cmp ax,0h
+006D  7D 03       jnl 72h
+006F  43          inc bx
+0070  F7 D8       neg ax
+0072  B9 0A 00    mov cx,0ah
+0075  43          inc bx
+0076  31 D2       xor dx,dx
+0078  F7 F1       div ax,cx
+007A  83 F8 00    cmp ax,0h
+007D  75 F6       jne 75h
+007F  8B 46 04    mov ax,word ptr [bp+4h]
+0082  2B C3       sub ax,bx
+0084  83 F8 00    cmp ax,0h
+0087  7E 0A       jle 93h
+0089  89 C1       mov cx,ax
+008B  B0 20       mov al,20h
+008D  B4 02       mov ah,2h
+008F  CD 21       int 21h
+0091  E2 F8       loop 8bh
+0093  8B 46 06    mov ax,word ptr [bp+6h]
+0096  83 F8 00    cmp ax,0h
+0099  7D 0A       jnl 0a5h
+009B  50          push ax
+009C  B0 2D       mov al,2dh
 009E  B4 02       mov ah,2h
 009E  B4 02       mov ah,2h
-00A0  E3 07       jcxz 0a9h
-00A2  8A 07       mov al,byte ptr [bx]
-00A4  CD 21       int 21h
-00A6  43          inc bx
-00A7  E2 F9       loop 0a2h
-00A9  FF E3       jmp bx
-00AB  55          push bp
-00AC  8B EC       mov bp,sp
-00AE  53          push bx
-00AF  51          push cx
-00B0  50          push ax
-00B1  8B 5E 04    mov bx,word ptr [bp+4h]
-00B4  31 C9       xor cx,cx
-00B6  8A 0F       mov cl,byte ptr [bx]
-00B8  43          inc bx
-00B9  B4 02       mov ah,2h
-00BB  E3 07       jcxz 0c4h
-00BD  8A 07       mov al,byte ptr [bx]
-00BF  CD 21       int 21h
-00C1  43          inc bx
-00C2  E2 F9       loop 0bdh
-00C4  58          pop ax
-00C5  59          pop cx
-00C6  5B          pop bx
-00C7  89 EC       mov sp,bp
-00C9  5D          pop bp
-00CA  C3          ret
-00CB  55          push bp
-00CC  8B EC       mov bp,sp
-00CE  50          push ax
-00CF  53          push bx
-00D0  51          push cx
-00D1  52          push dx
-00D2  57          push di
-00D3  E8 13 00    call 0e9h
-00D6  83 F9 02    cmp cx,2h
-00D9  74 05       je 0e0h
-00DB  8B 7E 04    mov di,word ptr [bp+4h]
-00DE  89 05       mov word ptr [di],ax
-00E0  5F          pop di
-00E1  5A          pop dx
-00E2  59          pop cx
-00E3  5B          pop bx
-00E4  58          pop ax
-00E5  89 EC       mov sp,bp
-00E7  5D          pop bp
-00E8  C3          ret
-00E9  E8 C3 00    call 1afh
-00EC  3C 1A       cmp al,1ah
-00EE  74 42       je 132h
-00F0  3C 20       cmp al,20h
-00F2  76 F5       jbe 0e9h
-00F4  31 C9       xor cx,cx
-00F6  3C 2D       cmp al,2dh
-00F8  75 06       jne 100h
-00FA  41          inc cx
-00FB  E8 B1 00    call 1afh
-00FE  EB 07       jmp 107h
-0100  3C 2B       cmp al,2bh
-0102  75 03       jne 107h
-0104  E8 A8 00    call 1afh
-0107  31 FF       xor di,di
-0109  3C 30       cmp al,30h
-010B  72 18       jb 125h
-010D  3C 39       cmp al,39h
-010F  77 14       jnbe 125h
-0111  2C 30       sub al,30h
-0113  B4 00       mov ah,0h
-0115  87 C7       xchg di,ax
-0117  BB 0A 00    mov bx,0ah
-011A  F7 E3       mul bx
-011C  03 C7       add ax,di
-011E  89 C7       mov di,ax
-0120  E8 8C 00    call 1afh
-0123  EB E4       jmp 109h
-0125  E8 9E 00    call 1c6h
-0128  83 F9 00    cmp cx,0h
-012B  74 02       je 12fh
-012D  F7 DF       neg di
-012F  8B C7       mov ax,di
-0131  C3          ret
-0132  B9 02 00    mov cx,2h
-0135  C3          ret
-0136  55          push bp
-0137  8B EC       mov bp,sp
-0139  50          push ax
-013A  53          push bx
-013B  51          push cx
-013C  52          push dx
-013D  57          push di
-013E  E8 A8 FF    call 0e9h
-0141  83 F9 02    cmp cx,2h
-0144  74 05       je 14bh
-0146  8B 7E 04    mov di,word ptr [bp+4h]
-0149  88 05       mov byte ptr [di],al
-014B  5F          pop di
-014C  5A          pop dx
-014D  59          pop cx
-014E  5B          pop bx
-014F  58          pop ax
-0150  89 EC       mov sp,bp
-0152  5D          pop bp
-0153  C3          ret
-0154  55          push bp
-0155  8B EC       mov bp,sp
-0157  50          push ax
-0158  53          push bx
-0159  57          push di
-015A  E8 52 00    call 1afh
-015D  88 C2       mov dl,al
-015F  8B 7E 04    mov di,word ptr [bp+4h]
-0162  88 15       mov byte ptr [di],dl
-0164  5F          pop di
-0165  5B          pop bx
-0166  58          pop ax
-0167  89 EC       mov sp,bp
-0169  5D          pop bp
-016A  C3          ret
-016B  55          push bp
-016C  8B EC       mov bp,sp
-016E  50          push ax
-016F  53          push bx
-0170  51          push cx
-0171  57          push di
-0172  E8 3A 00    call 1afh
-0175  31 C9       xor cx,cx
-0177  3C 54       cmp al,54h
-0179  74 12       je 18dh
-017B  3C 74       cmp al,74h
-017D  74 0E       je 18dh
-017F  3C 59       cmp al,59h
-0181  74 0A       je 18dh
-0183  3C 79       cmp al,79h
-0185  74 06       je 18dh
-0187  3C 31       cmp al,31h
-0189  74 02       je 18dh
-018B  EB 01       jmp 18eh
-018D  41          inc cx
-018E  8B 7E 04    mov di,word ptr [bp+4h]
-0191  89 0D       mov word ptr [di],cx
-0193  5F          pop di
-0194  59          pop cx
-0195  5B          pop bx
-0196  58          pop ax
-0197  89 EC       mov sp,bp
-0199  5D          pop bp
-019A  C3          ret
-019B  50          push ax
-019C  E8 10 00    call 1afh
-019F  3C 0D       cmp al,0dh
-01A1  74 0A       je 1adh
-01A3  3C 0A       cmp al,0ah
-01A5  74 06       je 1adh
-01A7  3C 1A       cmp al,1ah
-01A9  74 02       je 1adh
-01AB  EB EF       jmp 19ch
-01AD  58          pop ax
-01AE  C3          ret
-01AF  8B 1E FF 03 mov bx,word ptr [3ffh]
-01B3  83 FB 00    cmp bx,0h
-01B6  74 09       je 1c1h
-01B8  8A C3       mov al,bl
-01BA  31 DB       xor bx,bx
-01BC  89 1E FF 03 mov word ptr [3ffh],bx
-01C0  C3          ret
-01C1  B4 08       mov ah,8h
-01C3  CD 21       int 21h
-01C5  C3          ret
-01C6  88 C2       mov dl,al
-01C8  BB 01 00    mov bx,1h
-01CB  8A DA       mov bl,dl
-01CD  89 1E FF 03 mov word ptr [3ffh],bx
-01D1  C3          ret
-01D2  55          push bp
-01D3  8B EC       mov bp,sp
-01D5  50          push ax
-01D6  53          push bx
-01D7  51          push cx
-01D8  52          push dx
-01D9  57          push di
-01DA  8B 7E 04    mov di,word ptr [bp+4h]
-01DD  8B 46 04    mov ax,word ptr [bp+4h]
-01E0  8B F0       mov si,ax
-01E2  46          inc si
-01E3  31 DB       xor bx,bx
-01E5  53          push bx
-01E6  E8 C6 FF    call 1afh
-01E9  5B          pop bx
-01EA  3C 0D       cmp al,0dh
-01EC  74 1D       je 20bh
-01EE  3C 0A       cmp al,0ah
-01F0  74 19       je 20bh
-01F2  3C 1A       cmp al,1ah
-01F4  74 15       je 20bh
-01F6  88 C2       mov dl,al
-01F8  43          inc bx
-01F9  88 14       mov byte ptr [si],dl
-01FB  46          inc si
-01FC  E2 E7       loop 1e5h
-01FE  8A C3       mov al,bl
-0200  88 05       mov byte ptr [di],al
-0202  5F          pop di
-0203  5A          pop dx
-0204  59          pop cx
-0205  5B          pop bx
-0206  58          pop ax
-0207  89 EC       mov sp,bp
-0209  5D          pop bp
-020A  C3          ret
-020B  53          push bx
-020C  E8 B7 FF    call 1c6h
-020F  5B          pop bx
-0210  EB EC       jmp 1feh
-0212  55          push bp
-0213  8B EC       mov bp,sp
-0215  50          push ax
-0216  53          push bx
-0217  51          push cx
-0218  52          push dx
-0219  8B 46 04    mov ax,word ptr [bp+4h]
-021C  8B F0       mov si,ax
-021E  8B 5E 06    mov bx,word ptr [bp+6h]
-0221  31 D2       xor dx,dx
-0223  8A 07       mov al,byte ptr [bx]
-0225  88 C2       mov dl,al
-0227  43          inc bx
-0228  39 D1       cmp cx,dx
-022A  72 04       jb 230h
-022C  8B CA       mov cx,dx
-022E  EB 02       jmp 232h
-0230  8A D1       mov dl,cl
-0232  88 14       mov byte ptr [si],dl
-0234  46          inc si
-0235  E3 0A       jcxz 241h
-0237  8A 07       mov al,byte ptr [bx]
-0239  88 C2       mov dl,al
-023B  88 14       mov byte ptr [si],dl
-023D  43          inc bx
-023E  46          inc si
-023F  E2 F6       loop 237h
-0241  5A          pop dx
-0242  59          pop cx
-0243  5B          pop bx
-0244  58          pop ax
-0245  89 EC       mov sp,bp
-0247  5D          pop bp
-0248  C3          ret
-0249  55          push bp
-024A  8B EC       mov bp,sp
-024C  53          push bx
-024D  51          push cx
-024E  52          push dx
-024F  31 C9       xor cx,cx
-0251  31 D2       xor dx,dx
-0253  8B 5E 06    mov bx,word ptr [bp+6h]
-0256  8A 0F       mov cl,byte ptr [bx]
-0258  8B 46 04    mov ax,word ptr [bp+4h]
-025B  8B F0       mov si,ax
-025D  8A 14       mov dl,byte ptr [si]
-025F  39 D1       cmp cx,dx
-0261  76 02       jbe 265h
-0263  8B CA       mov cx,dx
-0265  E3 0E       jcxz 275h
-0267  43          inc bx
-0268  46          inc si
-0269  8A 07       mov al,byte ptr [bx]
-026B  8A 14       mov dl,byte ptr [si]
-026D  3A C2       cmp al,dl
-026F  75 14       jne 285h
-0271  43          inc bx
-0272  46          inc si
-0273  E2 F4       loop 269h
-0275  8B 5E 06    mov bx,word ptr [bp+6h]
-0278  8A 0F       mov cl,byte ptr [bx]
-027A  8B 46 04    mov ax,word ptr [bp+4h]
-027D  8B F0       mov si,ax
-027F  31 D2       xor dx,dx
-0281  8A 14       mov dl,byte ptr [si]
-0283  39 D1       cmp cx,dx
-0285  B0 00       mov al,0h
-0287  B4 00       mov ah,0h
-0289  72 06       jb 291h
-028B  74 08       je 295h
-028D  B0 01       mov al,1h
-028F  EB 04       jmp 295h
-0291  B0 FF       mov al,0ffh
-0293  B4 FF       mov ah,0ffh
-0295  5A          pop dx
-0296  59          pop cx
-0297  5B          pop bx
-0298  89 EC       mov sp,bp
-029A  5D          pop bp
-029B  C3          ret
-029C  55          push bp
-029D  8B EC       mov bp,sp
-029F  50          push ax
-02A0  53          push bx
-02A1  51          push cx
-02A2  52          push dx
-02A3  56          push si
-02A4  57          push di
-02A5  8B 46 04    mov ax,word ptr [bp+4h]
-02A8  8B F0       mov si,ax
-02AA  8B 5E 06    mov bx,word ptr [bp+6h]
-02AD  31 D2       xor dx,dx
-02AF  8A 14       mov dl,byte ptr [si]
-02B1  31 C0       xor ax,ax
-02B3  8A 07       mov al,byte ptr [bx]
-02B5  01 C2       add dx,ax
-02B7  39 D1       cmp cx,dx
-02B9  73 06       jnb 2c1h
-02BB  B0 10       mov al,10h
-02BD  B4 4C       mov ah,4ch
-02BF  CD 21       int 21h
-02C1  8B CA       mov cx,dx
-02C3  88 0C       mov byte ptr [si],cl
-02C5  29 C2       sub dx,ax
-02C7  8B FE       mov di,si
-02C9  47          inc di
-02CA  01 D7       add di,dx
-02CC  43          inc bx
-02CD  89 C1       mov cx,ax
-02CF  E3 08       jcxz 2d9h
-02D1  8A 07       mov al,byte ptr [bx]
-02D3  88 05       mov byte ptr [di],al
-02D5  43          inc bx
-02D6  47          inc di
-02D7  E2 F8       loop 2d1h
-02D9  5F          pop di
-02DA  5E          pop si
-02DB  5A          pop dx
-02DC  59          pop cx
-02DD  5B          pop bx
-02DE  58          pop ax
-02DF  89 EC       mov sp,bp
-02E1  5D          pop bp
-02E2  C3          ret
+00A0  CD 21       int 21h
+00A2  58          pop ax
+00A3  F7 D8       neg ax
+00A5  B9 0A 00    mov cx,0ah
+00A8  BB 57 04    mov bx,457h
+00AB  89 DE       mov si,bx
+00AD  31 D2       xor dx,dx
+00AF  F7 F1       div ax,cx
+00B1  80 C2 30    add dl,30h
+00B4  4E          dec si
+00B5  88 14       mov byte ptr [si],dl
+00B7  83 F8 00    cmp ax,0h
+00BA  75 F1       jne 0adh
+00BC  39 DE       cmp si,bx
+00BE  74 09       je 0c9h
+00C0  8A 04       mov al,byte ptr [si]
+00C2  B4 02       mov ah,2h
+00C4  CD 21       int 21h
+00C6  46          inc si
+00C7  EB F3       jmp 0bch
+00C9  89 EC       mov sp,bp
+00CB  5D          pop bp
+00CC  C3          ret
+00CD  55          push bp
+00CE  8B EC       mov bp,sp
+00D0  8A 46 04    mov al,byte ptr [bp+4h]
+00D3  89 EC       mov sp,bp
+00D5  5D          pop bp
+00D6  B4 02       mov ah,2h
+00D8  CD 21       int 21h
+00DA  C3          ret
+00DB  55          push bp
+00DC  8B EC       mov bp,sp
+00DE  83 7E 04 00 cmp word ptr [bp+4h],0h
+00E2  89 EC       mov sp,bp
+00E4  75 05       jne 0ebh
+00E6  BA 5C 04    mov dx,45ch
+00E9  EB 03       jmp 0eeh
+00EB  BA 57 04    mov dx,457h
+00EE  B4 09       mov ah,9h
+00F0  CD 21       int 21h
+00F2  5D          pop bp
+00F3  C3          ret
+00F4  BA 65 04    mov dx,465h
+00F7  B4 09       mov ah,9h
+00F9  CD 21       int 21h
+00FB  C3          ret
+00FC  BA 62 04    mov dx,462h
+00FF  B4 09       mov ah,9h
+0101  CD 21       int 21h
+0103  C3          ret
+0104  5B          pop bx
+0105  31 C9       xor cx,cx
+0107  8A 0F       mov cl,byte ptr [bx]
+0109  43          inc bx
+010A  B4 02       mov ah,2h
+010C  E3 07       jcxz 115h
+010E  8A 07       mov al,byte ptr [bx]
+0110  CD 21       int 21h
+0112  43          inc bx
+0113  E2 F9       loop 10eh
+0115  FF E3       jmp bx
+0117  55          push bp
+0118  8B EC       mov bp,sp
+011A  53          push bx
+011B  51          push cx
+011C  50          push ax
+011D  8B 5E 04    mov bx,word ptr [bp+4h]
+0120  31 C9       xor cx,cx
+0122  8A 0F       mov cl,byte ptr [bx]
+0124  43          inc bx
+0125  B4 02       mov ah,2h
+0127  E3 07       jcxz 130h
+0129  8A 07       mov al,byte ptr [bx]
+012B  CD 21       int 21h
+012D  43          inc bx
+012E  E2 F9       loop 129h
+0130  58          pop ax
+0131  59          pop cx
+0132  5B          pop bx
+0133  89 EC       mov sp,bp
+0135  5D          pop bp
+0136  C3          ret
+0137  55          push bp
+0138  8B EC       mov bp,sp
+013A  50          push ax
+013B  53          push bx
+013C  51          push cx
+013D  52          push dx
+013E  57          push di
+013F  E8 13 00    call 155h
+0142  83 F9 02    cmp cx,2h
+0145  74 05       je 14ch
+0147  8B 7E 04    mov di,word ptr [bp+4h]
+014A  89 05       mov word ptr [di],ax
+014C  5F          pop di
+014D  5A          pop dx
+014E  59          pop cx
+014F  5B          pop bx
+0150  58          pop ax
+0151  89 EC       mov sp,bp
+0153  5D          pop bp
+0154  C3          ret
+0155  E8 C3 00    call 21bh
+0158  3C 1A       cmp al,1ah
+015A  74 42       je 19eh
+015C  3C 20       cmp al,20h
+015E  76 F5       jbe 155h
+0160  31 C9       xor cx,cx
+0162  3C 2D       cmp al,2dh
+0164  75 06       jne 16ch
+0166  41          inc cx
+0167  E8 B1 00    call 21bh
+016A  EB 07       jmp 173h
+016C  3C 2B       cmp al,2bh
+016E  75 03       jne 173h
+0170  E8 A8 00    call 21bh
+0173  31 FF       xor di,di
+0175  3C 30       cmp al,30h
+0177  72 18       jb 191h
+0179  3C 39       cmp al,39h
+017B  77 14       jnbe 191h
+017D  2C 30       sub al,30h
+017F  B4 00       mov ah,0h
+0181  87 C7       xchg di,ax
+0183  BB 0A 00    mov bx,0ah
+0186  F7 E3       mul bx
+0188  03 C7       add ax,di
+018A  89 C7       mov di,ax
+018C  E8 8C 00    call 21bh
+018F  EB E4       jmp 175h
+0191  E8 9E 00    call 232h
+0194  83 F9 00    cmp cx,0h
+0197  74 02       je 19bh
+0199  F7 DF       neg di
+019B  8B C7       mov ax,di
+019D  C3          ret
+019E  B9 02 00    mov cx,2h
+01A1  C3          ret
+01A2  55          push bp
+01A3  8B EC       mov bp,sp
+01A5  50          push ax
+01A6  53          push bx
+01A7  51          push cx
+01A8  52          push dx
+01A9  57          push di
+01AA  E8 A8 FF    call 155h
+01AD  83 F9 02    cmp cx,2h
+01B0  74 05       je 1b7h
+01B2  8B 7E 04    mov di,word ptr [bp+4h]
+01B5  88 05       mov byte ptr [di],al
+01B7  5F          pop di
+01B8  5A          pop dx
+01B9  59          pop cx
+01BA  5B          pop bx
+01BB  58          pop ax
+01BC  89 EC       mov sp,bp
+01BE  5D          pop bp
+01BF  C3          ret
+01C0  55          push bp
+01C1  8B EC       mov bp,sp
+01C3  50          push ax
+01C4  53          push bx
+01C5  57          push di
+01C6  E8 52 00    call 21bh
+01C9  88 C2       mov dl,al
+01CB  8B 7E 04    mov di,word ptr [bp+4h]
+01CE  88 15       mov byte ptr [di],dl
+01D0  5F          pop di
+01D1  5B          pop bx
+01D2  58          pop ax
+01D3  89 EC       mov sp,bp
+01D5  5D          pop bp
+01D6  C3          ret
+01D7  55          push bp
+01D8  8B EC       mov bp,sp
+01DA  50          push ax
+01DB  53          push bx
+01DC  51          push cx
+01DD  57          push di
+01DE  E8 3A 00    call 21bh
+01E1  31 C9       xor cx,cx
+01E3  3C 54       cmp al,54h
+01E5  74 12       je 1f9h
+01E7  3C 74       cmp al,74h
+01E9  74 0E       je 1f9h
+01EB  3C 59       cmp al,59h
+01ED  74 0A       je 1f9h
+01EF  3C 79       cmp al,79h
+01F1  74 06       je 1f9h
+01F3  3C 31       cmp al,31h
+01F5  74 02       je 1f9h
+01F7  EB 01       jmp 1fah
+01F9  41          inc cx
+01FA  8B 7E 04    mov di,word ptr [bp+4h]
+01FD  89 0D       mov word ptr [di],cx
+01FF  5F          pop di
+0200  59          pop cx
+0201  5B          pop bx
+0202  58          pop ax
+0203  89 EC       mov sp,bp
+0205  5D          pop bp
+0206  C3          ret
+0207  50          push ax
+0208  E8 10 00    call 21bh
+020B  3C 0D       cmp al,0dh
+020D  74 0A       je 219h
+020F  3C 0A       cmp al,0ah
+0211  74 06       je 219h
+0213  3C 1A       cmp al,1ah
+0215  74 02       je 219h
+0217  EB EF       jmp 208h
+0219  58          pop ax
+021A  C3          ret
+021B  8B 1E 6B 04 mov bx,word ptr [46bh]
+021F  83 FB 00    cmp bx,0h
+0222  74 09       je 22dh
+0224  8A C3       mov al,bl
+0226  31 DB       xor bx,bx
+0228  89 1E 6B 04 mov word ptr [46bh],bx
+022C  C3          ret
+022D  B4 08       mov ah,8h
+022F  CD 21       int 21h
+0231  C3          ret
+0232  88 C2       mov dl,al
+0234  BB 01 00    mov bx,1h
+0237  8A DA       mov bl,dl
+0239  89 1E 6B 04 mov word ptr [46bh],bx
+023D  C3          ret
+023E  55          push bp
+023F  8B EC       mov bp,sp
+0241  50          push ax
+0242  53          push bx
+0243  51          push cx
+0244  52          push dx
+0245  57          push di
+0246  8B 7E 04    mov di,word ptr [bp+4h]
+0249  8B 46 04    mov ax,word ptr [bp+4h]
+024C  8B F0       mov si,ax
+024E  46          inc si
+024F  31 DB       xor bx,bx
+0251  53          push bx
+0252  E8 C6 FF    call 21bh
+0255  5B          pop bx
+0256  3C 0D       cmp al,0dh
+0258  74 1D       je 277h
+025A  3C 0A       cmp al,0ah
+025C  74 19       je 277h
+025E  3C 1A       cmp al,1ah
+0260  74 15       je 277h
+0262  88 C2       mov dl,al
+0264  43          inc bx
+0265  88 14       mov byte ptr [si],dl
+0267  46          inc si
+0268  E2 E7       loop 251h
+026A  8A C3       mov al,bl
+026C  88 05       mov byte ptr [di],al
+026E  5F          pop di
+026F  5A          pop dx
+0270  59          pop cx
+0271  5B          pop bx
+0272  58          pop ax
+0273  89 EC       mov sp,bp
+0275  5D          pop bp
+0276  C3          ret
+0277  53          push bx
+0278  E8 B7 FF    call 232h
+027B  5B          pop bx
+027C  EB EC       jmp 26ah
+027E  55          push bp
+027F  8B EC       mov bp,sp
+0281  50          push ax
+0282  53          push bx
+0283  51          push cx
+0284  52          push dx
+0285  8B 46 04    mov ax,word ptr [bp+4h]
+0288  8B F0       mov si,ax
+028A  8B 5E 06    mov bx,word ptr [bp+6h]
+028D  31 D2       xor dx,dx
+028F  8A 07       mov al,byte ptr [bx]
+0291  88 C2       mov dl,al
+0293  43          inc bx
+0294  39 D1       cmp cx,dx
+0296  72 04       jb 29ch
+0298  8B CA       mov cx,dx
+029A  EB 02       jmp 29eh
+029C  8A D1       mov dl,cl
+029E  88 14       mov byte ptr [si],dl
+02A0  46          inc si
+02A1  E3 0A       jcxz 2adh
+02A3  8A 07       mov al,byte ptr [bx]
+02A5  88 C2       mov dl,al
+02A7  88 14       mov byte ptr [si],dl
+02A9  43          inc bx
+02AA  46          inc si
+02AB  E2 F6       loop 2a3h
+02AD  5A          pop dx
+02AE  59          pop cx
+02AF  5B          pop bx
+02B0  58          pop ax
+02B1  89 EC       mov sp,bp
+02B3  5D          pop bp
+02B4  C3          ret
+02B5  55          push bp
+02B6  8B EC       mov bp,sp
+02B8  53          push bx
+02B9  51          push cx
+02BA  52          push dx
+02BB  31 C9       xor cx,cx
+02BD  31 D2       xor dx,dx
+02BF  8B 5E 06    mov bx,word ptr [bp+6h]
+02C2  8A 0F       mov cl,byte ptr [bx]
+02C4  8B 46 04    mov ax,word ptr [bp+4h]
+02C7  8B F0       mov si,ax
+02C9  8A 14       mov dl,byte ptr [si]
+02CB  39 D1       cmp cx,dx
+02CD  76 02       jbe 2d1h
+02CF  8B CA       mov cx,dx
+02D1  E3 0E       jcxz 2e1h
+02D3  43          inc bx
+02D4  46          inc si
+02D5  8A 07       mov al,byte ptr [bx]
+02D7  8A 14       mov dl,byte ptr [si]
+02D9  3A C2       cmp al,dl
+02DB  75 14       jne 2f1h
+02DD  43          inc bx
+02DE  46          inc si
+02DF  E2 F4       loop 2d5h
+02E1  8B 5E 06    mov bx,word ptr [bp+6h]
+02E4  8A 0F       mov cl,byte ptr [bx]
+02E6  8B 46 04    mov ax,word ptr [bp+4h]
+02E9  8B F0       mov si,ax
+02EB  31 D2       xor dx,dx
+02ED  8A 14       mov dl,byte ptr [si]
+02EF  39 D1       cmp cx,dx
+02F1  B0 00       mov al,0h
+02F3  B4 00       mov ah,0h
+02F5  72 06       jb 2fdh
+02F7  74 08       je 301h
+02F9  B0 01       mov al,1h
+02FB  EB 04       jmp 301h
+02FD  B0 FF       mov al,0ffh
+02FF  B4 FF       mov ah,0ffh
+0301  5A          pop dx
+0302  59          pop cx
+0303  5B          pop bx
+0304  89 EC       mov sp,bp
+0306  5D          pop bp
+0307  C3          ret
+0308  55          push bp
+0309  8B EC       mov bp,sp
+030B  50          push ax
+030C  53          push bx
+030D  51          push cx
+030E  52          push dx
+030F  56          push si
+0310  57          push di
+0311  8B 46 04    mov ax,word ptr [bp+4h]
+0314  8B F0       mov si,ax
+0316  8B 5E 06    mov bx,word ptr [bp+6h]
+0319  31 D2       xor dx,dx
+031B  8A 14       mov dl,byte ptr [si]
+031D  31 C0       xor ax,ax
+031F  8A 07       mov al,byte ptr [bx]
+0321  01 C2       add dx,ax
+0323  39 D1       cmp cx,dx
+0325  73 06       jnb 32dh
+0327  B0 10       mov al,10h
+0329  B4 4C       mov ah,4ch
+032B  CD 21       int 21h
+032D  8B CA       mov cx,dx
+032F  88 0C       mov byte ptr [si],cl
+0331  29 C2       sub dx,ax
+0333  8B FE       mov di,si
+0335  47          inc di
+0336  01 D7       add di,dx
+0338  43          inc bx
+0339  89 C1       mov cx,ax
+033B  E3 08       jcxz 345h
+033D  8A 07       mov al,byte ptr [bx]
+033F  88 05       mov byte ptr [di],al
+0341  43          inc bx
+0342  47          inc di
+0343  E2 F8       loop 33dh
+0345  5F          pop di
+0346  5E          pop si
+0347  5A          pop dx
+0348  59          pop cx
+0349  5B          pop bx
+034A  58          pop ax
+034B  89 EC       mov sp,bp
+034D  5D          pop bp
+034E  C3          ret