Browse Source

calc: CALC.PAS compiles (code 25908, data 19694)

Move the fixed data base from image 0x8000 to 0xA000 (memory 0xA100) and
raise CodeMax/MaxCode to 0xA000.  This gives the large generated program room
below the data base while keeping the .COM code-only.  comimage.py and the
layout notes are updated to the new fixed base.

The last source blockers were CHAR-subrange handling for ColumnName
('A'..'G' now has class TChar, so `string + FX` works), the CASE/ELSE trailing
semicolon, and string-vs-CHAR comparison.

The CALC ladder now reports:

    CALC.PAS  OK  25908  19694

so the front-end reaches the final '.'.  This is a compile milestone, not a
run milestone: the boot harness still places stdin at memory 7000h, below the
larger image, so running CALC.COM needs the loader moved.

Verified: compile matrix 113/113, ladder 1/1 (OK), 99 .COM executions under
both oracles, rt_exec 276/276, nonvacuity 121/121, run_all ALL PASS.
Eric Streit 3 ngày trước cách đây
mục cha
commit
a65e0aec2d
5 tập tin đã thay đổi với 55 bổ sung và 46 xóa
  1. 13 10
      CALC-COMPILE.md
  2. 12 11
      SUMMARY.md
  3. 19 9
      shell/Compiler.mod
  4. 3 3
      shell/tests/comimage.py
  5. 8 13
      shell/tests/fixtures/calc_ladder.tsv

+ 13 - 10
CALC-COMPILE.md

@@ -97,7 +97,7 @@ Current rung (measured today, normalised position):
 
 | position | blocker |
 |---|---|
-| **56540** | code-image ceiling — runtime + generated code reaches the `0x8000` data base (`ERR 98`) |
+| **compiles** | `CALC.PAS` reaches its final `.` — code **25,908** B, data **19,694** B |
 
 Rungs behind it (now passed):
 
@@ -163,7 +163,8 @@ Rungs ahead:
 | 50744 | `Insert` string builtin - DONE |
 | 51322 | CASE/ELSE closing `end;` - DONE |
 | 52316 | string vs CHAR comparison (`S <> Chr($FF)`) - DONE |
-| 56540 | code-image ceiling (`ERR 98`) |
+| 56540 | code-image ceiling - DONE (DataStart moved to 0xA000) |
+| **OK** | **CALC.PAS compiles: code 25,908, data 19,694** |
 
 Corrections the measurements force, worth stating plainly because the stage list
 below was written before them:
@@ -423,9 +424,9 @@ properties that matter for the compile goal are preserved:
 |---|---|---|
 | `.COM` contents | runtime + program code (CS), no data | runtime + program code, no data |
 | entry | `E9 rel16` over the runtime | `E9 rel16` over the runtime + 16-byte header |
-| globals | separate DS, offsets from `dc` | fixed image `DataStart = 8000h` (memory `8100h`) |
+| globals | separate DS, offsets from `dc` | fixed image `DataStart = 0A000h` (memory `0A100h`) |
 | globals zeroed | DS data area | `initmem` zeroes `[hdrDS,hdrHeap)` |
-| code limit | CS capacity | `MaxCode = 24,000` (and `CodeMax = 6F00h` before the stdin descriptor) |
+| code limit | CS capacity | `MaxCode = 0A000h` and `CodeMax = 0A000h` (data base) |
 | data limit | DS capacity | address space below the stack |
 | heap/stack | above DS | above `hdrHeap`, down from `SP=FFFEh` |
 
@@ -1256,11 +1257,13 @@ and TEXT file output is done (`t91_textout`), both compile-only because the
 harness has no filesystem.  `Str` real formatting is done (`t92_strreal`),
 pointer types with `New`/`Dispose`/dereference are done (`t93_pointer`), and
 text `Eof`/`Readln` plus integer `Str` are done (`t94_textread`/`t95_strint`).
-The next blocker is image capacity: runtime plus generated code reaches the
-`0x8000` data base.  The runtime is 9,373 bytes; `rt_exec` is at HDR=0x4000 /
-data 0x5000, and the compiler's code ceiling is 0x8000.  The next change must
-be a deliberate layout move (data base/code ceiling) or a further runtime
-reduction.
+**CALC.PAS compiles.**  The runtime is 9,373 bytes; the generated program is
+25,908 bytes of code and 19,694 bytes of data, with `DataStart=0xA000` and
+`CodeMax=0xA000`.  The next task is execution, not front-end coverage: the
+current boot harness still places stdin at memory `7000h`, below the larger
+image, so the loader must be moved before CALC.COM can run under qemu.  The
+original CALC.COM is 27,901 bytes; ours is larger because the runtime and
+code layout differ.
 
 **Stage 14 — the CRT identifiers.** `GotoXY` (25), `LowVideo`/`NormVideo`
 (16 + 16), `ClrEol` (10), `ClrScr` (6), `KeyPressed` (3), `Delay` (1),
@@ -1305,7 +1308,7 @@ remaining run-time capacity note.
 |---|---|---|---|
 | `TextLimit` (source buffer) | 62,903 | `CALC.PAS` + `CALC.INC`, normalised = **62,415** | **488 bytes of slack** |
 | `MaxCode` | 24,000 | 16,560 B program + 4,384 B runtime = **20,944 B** | **OK, 3,056 B spare** (§3.2) |
-| code window | `CodeMax = 6F00h`, capped by `MaxCode` | 20,227 B | **OK**; no data gap (§3.2) |
+| code window | `CodeMax = 0A000h`, capped by `MaxCode` | 25,908 B | **OK**; no data gap (§3.2) |
 | data area | fixed image `8000h`, zeroed by `initmem` | **12,032 B** (measured, §3.1) | **OK for compile**; see the run-time cargo note (§3.2) |
 | stack | 16,384 min / 655,360 max | 16,384 min | matches the original's `minstk`/`maxstk` |
 | `MaxSym` | 3,000 | 47 routines + locals + params | **inferred** OK, verify |

+ 12 - 11
SUMMARY.md

@@ -1126,12 +1126,12 @@ assertion, rather than asking the compiler where it thinks the header is.
 `CmdCompile` honours the Destination option: 0 = memory, 1 = `.COM`, 2 = `.CHN`
 (refused). A `.COM` is named after its source with the extension swapped at the
 last dot and contains **exactly the runtime and the program's code**; the
-globals are at image `8000h` (memory `8100h`), outside the file, and `initmem`
+globals are at image `0A000h` (memory `0A100h`), outside the file, and `initmem`
 zeroes them. Its stack sits at the segment top (`SS = SP = CS:FFFE`), which is
 where DOS puts it.
 
-**Layout:** the old fixed `rtSz + 1000H` data base is gone. `DataStart = 8000h`,
-`CodeMax = 6F00h`, and `MaxCode = 24,000` bound the code image; the `.COM`
+**Layout:** the old fixed `rtSz + 1000H` data base is gone. `DataStart = 0A000h`,
+`CodeMax = 0A000h`, and `MaxCode = 0A000h` bound the code image; the `.COM`
 writer emits `ImageBytes()` and no padding. This is the flat-segment equivalent
 of the original's separate CS/DS layout (see `CALC-COMPILE.md` §3.2). It is
 enough to compile CALC; running CALC with its full 16,384-byte stack and
@@ -1298,9 +1298,9 @@ Details that are deliberate, not incidental:
 - **Code above 4 KiB no longer overruns the data area.** The layout rung
   (`v-TP3-CALC-LAYOUT`) moved the globals to image `8000h`, made the `.COM`
   code-only, and left `initmem` to zero the data. The effective code bound is
-  `MaxCode = 24,000` (with `CodeMax = 6F00h` before the boot harness's stdin
-  descriptor), not a 4 KiB window. The remaining capacity question is running
-  CALC with its original stack and heap, deferred in `CALC-COMPILE.md` §3.2.
+  `MaxCode = 0A000h` (with `CodeMax = 0A000h` before the data base), not a
+  4 KiB window. The remaining capacity question is running CALC with its
+  original stack and heap, deferred in `CALC-COMPILE.md` §3.2.
 - **`[SP]` cannot be encoded on an 8086, and the fix is a shape change.**
   `EmMovAxSp`/`EmMovCxSp` now emit `POP reg` / `PUSH reg` — two instructions
   where there used to be one, so anything that assumed a one-instruction
@@ -2044,7 +2044,7 @@ the compiler *emitting* a 16,560-byte program). The ratchet and front-end
 features through **file control-block operations and the original memory
 layout** are landed: the ladder (`tests/calc_ladder.sh` +
 `tests/fixtures/calc_ladder.tsv`, run by `run_all.sh`; CALC.PAS now stops at
-`ERR 98` at pos 56540, the code-image ceiling), the `{$I}` include,
+**CALC.PAS compiles** (code 25,908, data 19,694), the `{$I}` include,
 `^X`/`#nn`, scalar typed constants, sets, enums, records (CellRec = 80),
 subranges, arrays, element/field access, file types, string value parameters,
 `Length`, the CRT identifiers (`ClrScr`/`GotoXY`/`ClrEol`/`LowVideo`/
@@ -2070,10 +2070,11 @@ standard functions (`Abs`, `Sqr`, `Sqrt`, `Ln`, `Exp`, `Sin`, `Cos`,
 landed, along with `Delete` and local `set of Char` variables.  The math runtime
 was compacted to guest Horner/square loops, reducing it from 14,063 to 9,203
 bytes.  `Insert`, CASE/ELSE trailing semicolons and string-vs-CHAR comparisons
-are also landed; the ladder now stops at the code-image ceiling
-(`ERR 98 56540`).  The runtime is 9,373 bytes / 56 entries; the rt_exec
-scaffold is at HDR=0x4000 / data 0x5000.  Items 1-4 below are independent of
-both tracks.
+are also landed.  **CALC.PAS now compiles to its final `.`** with code 25,908
+and data 19,694.  The runtime is 9,373 bytes / 56 entries; the rt_exec
+scaffold is at HDR=0x4000 / data 0x5000.  The next task is running the larger
+image, not front-end coverage.  Items 1-4 below are independent of both
+tracks.
 
 1. The rest of the string language. `v-TP3-STRVAR`/`v-TP3-STRREAD-ASSIGN` cover
    string variables, `s := 'literal'`, `writeln (s)`, `readln (s)`/`read (s)`

+ 19 - 9
shell/Compiler.mod

@@ -75,17 +75,19 @@ CONST
       displacement is relative to the END of the jump, so every offset in the
       image is EntSize further along than it was before the jump existed. *)
    EntSize   = 3 ;
-   MaxCode   = 8000H ;
+   MaxCode   = 0A000H ;
    (* Program layout, image offsets.  The original puts the runtime and the
       program's code in CS and the globals in a SEPARATE DS segment, so the
       .COM contains no data and the code is not limited by a data gap.  We
       have one flat segment (our boot loader), so the same property is
       obtained by putting the globals at a fixed high image offset: the .COM
       is code-only, hdrDS points at DataStart, and initmem zeroes it.  The
-      code must end below CodeMax, where the boot harness puts the stdin
-      descriptor (memory 7000h). *)
-   DataStart = 8000H ;       (* image offset of the first global (memory 8100h) *)
-   CodeMax   = 8000H ;       (* code must end below memory 7000h *)
+      code must end below CodeMax.  DataStart is now 0xA000h so the large CALC
+      image fits; the current boot harness still puts its input descriptor at
+      memory 7000h, so a .COM above that is compile-only until the loader is
+      moved. *)
+   DataStart = 0A000H ;      (* image offset of the first global (memory 0A100h) *)
+   CodeMax   = 0A000H ;       (* code must end below the 0A000h data base *)
 
    MaxSym    = 3000 ;
    MaxPatch  = 2000 ;
@@ -357,7 +359,7 @@ VAR
 
    (* Image layout, all image-absolute.  rtSz is where the runtime ends and
       the program header begins; dataBase is the fixed high global area
-      (DataStart = 8000H image, 8100H memory), which is NOT part of the .COM
+      (DataStart = 0A000H image, 0A100H memory), which is NOT part of the .COM
       image: initmem zeroes it at startup, as the original's separate DS
       segment is zeroed.  codeSz and dataSz are PROGRAM sizes - the runtime is
       excluded. *)
@@ -799,7 +801,7 @@ BEGIN
          (CodeMax).  Globals no longer sit immediately above the code - they
          live at DataStart and initmem zeroes them - so this is purely a
          capacity check: cbuf cannot hold another byte, or the image would
-         reach the stdin descriptor at memory 7000h.  Reported as TP3's error
+         reach the configured data base.  Reported as TP3's error
          98 (memory overflow) rather than a silent truncation. *)
       Err (EMemOvf)
    ELSE
@@ -6890,6 +6892,7 @@ VAR tok : CARDINAL ;
     s2, e2 : CARDINAL ;
     subcls : CARDINAL ;
     strf : BOOLEAN ;
+    isCharRange : BOOLEAN ;
     consumed : BOOLEAN ;
     running, groupFirst, i, an, recStart : CARDINAL ;
     alo, ahi : ARRAY [0..3] OF LONGINT ;
@@ -7196,13 +7199,20 @@ BEGIN
             are inside 0..255, else two (RESUME-TP3.md §2).  `0..20' and
             `'A'..'G'' are one byte - which is what makes CellRec 80 and not
             82, and `Sheet' 147*80.  The bounds are kept for `set of T'. *)
+         Skip () ;
+         isCharRange := (ORD (CurCh ()) = AposC) OR (CurCh () = '^')
+                        OR (CurCh () = '#') ;
          RdConst (lo, subcls, strf) ;
          IF NOT MatchRange () THEN
             Err (ESimpType) ;
             RETURN
          END ;
          RdConst (hi, subcls, strf) ;
-         cls := TScalar ;
+         IF isCharRange THEN
+            cls := TChar
+         ELSE
+            cls := TScalar
+         END ;
          IF (lo >= 0) AND (hi <= 255) AND (lo <= hi) THEN
             size := 1
          ELSE
@@ -8466,7 +8476,7 @@ BEGIN
 END ImageBytes ;
 
 PROCEDURE DataBase () : CARDINAL ;
-(* image-absolute offset at which the data area begins (DataStart = 8000H).
+(* image-absolute offset at which the data area begins (DataStart = 0A000H).
    The data is outside the .COM; initmem zeroes [dataBase, dataBase+dataSz)
    through the header's hdrDS/hdrHeap words. *)
 BEGIN

+ 3 - 3
shell/tests/comimage.py

@@ -65,7 +65,7 @@ HDR_SZ = 16                   # 5 header words + 3 buffer words (Compiler)
 # both of their operands shift together.
 # Restated, not asked of the code under test.  See Runtime.LoadBias.
 LOAD_BIAS = 0x100
-DATA_IMAGE = 0x8000         # image offset of the globals; memory 8100h
+DATA_IMAGE = 0xA000         # image offset of the globals; memory 0A100h
 
 # initmem's prologue, which is the runtime's only reader of the program header.
 # The displacements +4 and +6 below are the whole point of this constant: the
@@ -96,7 +96,7 @@ def find_header(d):
 
         +0  1                 hdrFlag, always 1
         +2  code end + bias   hdrCS
-        +4  data base + bias  hdrDS = 8000h + bias, a FIXED high area
+        +4  data base + bias  hdrDS = 0A000h + bias, a FIXED high area
         +6  data end  + bias  hdrHeap, which is hdrDS + dataBytes
 
     The .COM is code-only: hdrDS is above the file and initmem zeroes it at
@@ -119,7 +119,7 @@ def find_header(d):
         return None
     # The program header sits immediately before the first instruction, and the
     # entry jump names that instruction.  The data base is now a FIXED high
-    # area (DataStart = 8000h image, 8100h memory), not header+1000h: the .COM
+    # area (DataStart = 0A000h image, 0A100h memory), not header+1000h: the .COM
     # is code-only, as the original's separate DS segment made it.
     target = ENT_SZ + int.from_bytes(d[1:ENT_SZ], "little", signed=True)
     off = target - HDR_SZ

+ 8 - 13
shell/tests/fixtures/calc_ladder.tsv

@@ -25,16 +25,11 @@
 # positions shift — which is exactly why this must be a measured number, not a
 # remembered one.
 #
-# Current rung (2026-10-23): the code image reaches the 0x8000 data boundary.
-# UpCase, run-time set membership, string fields through DI, the original memory
-# layout, untyped-file declarations, file control-block operations, VAR string
-# parameters, Chr, typed-file block I/O, text-file output, Str,
-# pointers/New/dereference, text Eof/Readln, Str(integer), Val(integer), VAR/
-# value REAL and REAL function results, REAL literals/comparisons/arithmetic,
-# self-recursion, enum-indexed arrays, string-array typed constants, local REAL
-# variables, Copy, real Val, Abs/Sqr/Sqrt, Ln/Exp/Sin/Cos/Arctan, Int(REAL),
-# forward definitions, Delete, local set of Char variables, the compact
-# Horner/square runtime, Insert, CASE/ELSE trailing semicolons and
-# string-vs-CHAR comparisons moved the ladder 15911 -> ... -> 51322 -> 56540.
-# The next blocker is the image layout/code ceiling (TP3 error 98).
-CALC.PAS	ERR	98	56540
+# Current rung (2026-10-24): CALC.PAS COMPILES.
+# The compiler now reaches the final '.', with code=25908 and data=19694.
+# The layout was moved deliberately: DataStart=0xA000 image (0xA100 memory)
+# and CodeMax=0xA000, so the runtime plus the generated program fit below the
+# data base.  UpCase, set membership, strings, pointers, files, REAL
+# expressions/functions, recursion, forward definitions, Copy/Val/Delete/
+# Insert, local sets and the compact math runtime are all landed.
+CALC.PAS	OK	25908	19694