Просмотр исходного кода

calc: accept the untyped file type (ladder 22280)

CALC.INC's Exist declares `var F : file;'.  ParseType's FILE arm required
`of T' and reported ENoSemi at the declaration's semicolon; the previous
ladder row blamed that on function declarations, but the function itself
parses (t36 already exercises one).  Make OF optional and give the untyped
form its own TUntyp class, so Read/Write of data through it remains refused
rather than being treated as a one-byte typed file.

t87_untypedfile is the red/green fixture (red: ERR 1 at the `;'), and runs
under qemu and Exec86.  The CALC ladder moves 22253 -> 22280; the next
blocker is the file-operation call `assign(F, FileN)'.

Verified: compile matrix 88/88, ladder 1/1, 79 .COM linked, 77 executed
under both oracles, nonvacuity 121/121, run_all ALL PASS.
Eric Streit 10 часов назад
Родитель
Сommit
41fa76bf6d

+ 13 - 10
CALC-COMPILE.md

@@ -97,7 +97,7 @@ Current rung (measured today, normalised position):
 
 | position | blocker |
 |---|---|
-| **22253** | `function Exist(FileN : AnyString): boolean;` — function declarations/returns (`ERR 1`) |
+| **22280** | `assign(F, FileN)` in `Exist` — file operations (`ERR 41`) |
 
 Rungs behind it (now passed):
 
@@ -127,12 +127,13 @@ Rungs behind it (now passed):
 | 18267 | `Write(Value:FW:DEC)` — REAL output | `real_write` (`t84`) |
 | 19847 | run-time set algebra / `Succ` / `Pred` | `set_op`/`set_cmp`/`copy` (`t85`, `t86`) |
 | 20912 | the fixed 4 KiB code window | original layout: code-only `.COM`, high zeroed data base (§3.2) |
+| 22253 | `var F : file;` — the untyped file type in `Exist` | optional `of T`; the parser reported ENoSemi at the semicolon |
 
 Rungs ahead:
 
 | position | blocker |
 |---|---|
-| 22253 | function declarations/returns (`Exist`), then the rest of CALC's functions |
+| 22280 | file operations (`Assign`, `Reset`, `Rewrite`, `Close`, `IoResult`, `EndOfFile`) |
 
 Corrections the measurements force, worth stating plainly because the stage list
 below was written before them:
@@ -423,7 +424,7 @@ The file is runtime + code, exactly the shape we now emit; the data is in the
 separate DS described by the inline parameters. Our CALC image will be smaller
 in runtime (3,667 B instead of 11,341 B) but has the same code-only, high-data
 shape. The ladder moved **20,912 → 22,253** on this change; the next blocker is
-not layout but `function Exist(FileN : AnyString): boolean;`.
+not layout but the untyped `file` declaration; that is fixed in the next rung.
 
 ---
 
@@ -452,9 +453,9 @@ calling convention and string value parameters, `Length`, the CRT identifiers,
 subscripts, write field widths, WITH with n-dimensional subscripts, set-field
 assignment, string fields through DI, REAL constants, UpCase, run-time set
 membership, string fields in WRITE, real output, run-time set algebra,
-`Succ`/`Pred`, and the original memory layout). The ladder has moved from the
-first typed constant at 7,791 to **22,253**, where the first **function**
-declaration appears.
+`Succ`/`Pred`, the original memory layout, and the untyped file type). The
+ladder has moved from the first typed constant at 7,791 to **22,280**, where
+`assign(F, FileN)` is the first file operation.
 
 The rung commits and their tags, in order (each is one rung with its own
 fixture, red proof, and — where the harness allows — execution under qemu and
@@ -489,7 +490,8 @@ Exec86):
 | `0946e80` | `v-TP3-CALC-REALCONST` | `ERR 41 15911` (`Upcase`) |
 | `17f7f7c` | `v-TP3-CALC-UPCASE` | **`ERR 102 18267`** (real output) |
 | `203f77e` | `v-TP3-CALC-SETOPS` | `ERR 98 20912` (layout limit reached) |
-| *(this commit)* | `v-TP3-CALC-LAYOUT` | **`ERR 1 22253`** (function declarations) |
+| `ff05141` | `v-TP3-CALC-LAYOUT` | `ERR 1 22253` (untyped file, initially misread as a function) |
+| *(this commit)* | `v-TP3-CALC-UNTYPEDFILE` | **`ERR 41 22280`** (`assign`) |
 
 - **Code HEAD** is the layout rung (`v-TP3-CALC-LAYOUT`).  Nothing is pushed.
   The terminal-config work (`v-TP3-TERMCFG`) and the editor key map
@@ -1085,10 +1087,11 @@ currently reserves a fresh **256-byte** global scratch (`NewScratchStr`), which
 for CALC's concat sites buys ~2 KiB of the budget in §3 — it needs to be sized
 to the operand, or reused.
 
-**Stage 13 — files. Types DONE; operations next.**
+**Stage 13 — files. Types DONE, including untyped `file`; operations next.**
 
-Done: `text` and `file of T`.  A file variable is our own control block
-(`FileVarSize = 4`: the DOS handle word and a mode word), because this runtime
+Done: `text`, `file of T`, and untyped `file` (`t87_untypedfile`).  A file
+variable is our own control block (`FileVarSize = 4`: the DOS handle word and a
+mode word), because this runtime
 does unbuffered `INT 21h` I/O where TP3 keeps a 128-byte buffer inside the
 variable - a recorded divergence.  `file of T` parses its element type so the
 RECORD size a Read/Write must move is known.  Fixture `t66_files`; this let the

+ 24 - 13
shell/Compiler.mod

@@ -5856,18 +5856,27 @@ BEGIN
       size := FileVarSize ;
       elem := 1
    ELSIF tok = TkFile THEN
-      (* file of T.  The element type is parsed for its SIZE, which is what a
-         Read/Write moves per record; the variable itself is the control
-         block. *)
-      IF NOT (MatchKey (tok) AND (tok = TkOf)) THEN
-         Err (ENoSemi) ;
-         RETURN
-      END ;
-      ParseType (subcls, s2, e2) ;
-      IF OK () THEN
-         cls := TFile ;
+      (* `file' (untyped) or `file of T'.  The element type is parsed for its
+         SIZE, which is what a Read/Write moves per record; the variable
+         itself is always the control block.  CALC.INC's Exist declares
+         `F : file', so the OF must be optional: requiring it produced ENoSemi
+         at the declaration's semicolon, which was misread as the function
+         declaration being unsupported.  TUntyp keeps the untyped file
+         distinguishable, because a Read/Write through it has no element size
+         and must stay refused. *)
+      PeekKw (tok) ;
+      IF tok = TkOf THEN
+         DropB (MatchKey (tok)) ;
+         ParseType (subcls, s2, e2) ;
+         IF OK () THEN
+            cls := TFile ;
+            size := FileVarSize ;
+            elem := s2
+         END
+      ELSE
+         cls := TUntyp ;
          size := FileVarSize ;
-         elem := s2
+         elem := 1
       END
    ELSE
       IF consumed THEN
@@ -5956,7 +5965,8 @@ BEGIN
       IF OK () THEN
          IF lexnest = 0 THEN
             IF (size > 2) AND (cls # TString) AND (cls # TRecord)
-               AND (cls # TArray) AND (cls # TFile) AND (cls # TText) THEN
+               AND (cls # TArray) AND (cls # TFile) AND (cls # TText)
+               AND (cls # TUntyp) THEN
                (* Still the catch-all for a type whose storage this compiler does
                   not lay out yet (an ARRAY at its point of use, a RECORD, ...).
                   A STRING is the exception now: its layout is length byte +
@@ -6001,7 +6011,8 @@ BEGIN
             varspc := varspc + size * (symTop - first)
          ELSE
             IF (size > 2) AND (cls # TString) AND (cls # TRecord)
-               AND (cls # TArray) AND (cls # TFile) AND (cls # TText) THEN
+               AND (cls # TArray) AND (cls # TFile) AND (cls # TText)
+               AND (cls # TUntyp) THEN
                Err (ENoLib) ;
                RETURN
             END ;

+ 9 - 10
shell/tests/fixtures/calc_ladder.tsv

@@ -25,13 +25,12 @@
 # positions shift — which is exactly why this must be a measured number, not a
 # remembered one.
 #
-# Current rung (2026-10-21): `Write(Value:FW:DEC)' in CALC.INC's GotoCell - a
-# REAL write with a field width and decimals.  UpCase (t81_upcase), run-time
-# set membership (t82_setin) and a string field written through DI (t79
-# extended) moved the ladder 15911 -> 18267 -> 19847 -> 20912 -> 22253.  Real
-# output, string comparisons, run-time set algebra, Succ/Pred and the ORIGINAL
-# MEMORY LAYOUT (code-only .COM, globals at a fixed high data base zeroed by
-# initmem, as the original's separate DS segment) now work.  The blocker is now
-# FUNCTION declarations/returns: `function Exist(FileN : AnyString): boolean;'
-# is not parsed (TP3 error 1, pos 22253).
-CALC.PAS	ERR	1	22253
+# Current rung (2026-10-22): the untyped `file' type in CALC.INC's Exist
+# (`var F : file;').  UpCase, run-time set membership, string fields through
+# DI, the original memory layout and now untyped-file declarations moved the
+# ladder 15911 -> 18267 -> 19847 -> 20912 -> 22253 -> 22280.  The function
+# declaration itself was never the blocker: the parser required `of T' after
+# FILE and reported ENoSemi at the semicolon inside Exist's var block.  The
+# next blocker is the file-operation call `assign(F, FileN)', which is not a
+# builtin yet (TP3 error 41).
+CALC.PAS	ERR	41	22280

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

@@ -621,3 +621,11 @@ t84_realwrite	OK	160	15
 #   t85/t86 are the run-time-set rung and the Succ/Pred builtins.
 t85_setops	OK	1355	17
 t86_succ	OK	115	8
+
+#   t87_untypedfile       the untyped `file' type: CALC.INC's Exist declares
+#                   `var F : file;' and the parser used to require `of T',
+#                   reporting ENoSemi at the declaration's semicolon.  The
+#                   variable is the same four-byte control block as a typed
+#                   file but carries no element size; data Read/Write through
+#                   it remains refused.
+t87_untypedfile	OK	62	9

+ 1 - 0
shell/tests/fixtures/t87_untypedfile.out

@@ -0,0 +1 @@
+untyped file declared

+ 17 - 0
shell/tests/fixtures/t87_untypedfile.pas

@@ -0,0 +1,17 @@
+program t87_untypedfile;
+
+{ t87 -- the untyped `file' type.  CALC.INC's Exist declares
+
+      var F : file;
+
+  and this compiler only accepted `file of T' (it required the OF and failed
+  with ENoSemi at the `;` after `file').  An untyped file is still a typed
+  file variable as far as storage goes - the four-byte control block - but it
+  carries no element type, so Read/Write of data through it must stay
+  rejected; Assign/Reset/Close are what CALC uses it for. }
+
+var
+  F : file;
+begin
+  writeln ('untyped file declared')
+end.