|
@@ -34,6 +34,7 @@ manual, not guessed.
|
|
|
| Multi-name declarations, both spellings — `var a, b, c : integer`, `procedure p (x, y : integer ; z : integer)` | `v-TP3-MULTIDECL` | done, **definitions and formal parameters read a comma-separated list of NAMES and then one `: type`, exactly TPSRC7 `rdvarlst`/`rdvloop` (VAR) and `prfcnt`/`ccomma` (parameters), with `;` between parameter groups. The older `name : type, name : type` spelling still parses, because both reach the same symbols; the names are created as placeholders and given the group's one type afterwards. One `GetWord` that did not `Skip` first attached the space after a comma to the next name (`" B"`), which is why the first name worked and the second did not; `t42_multidecl` prints each name's value to prove every one landed on its own slot (43/43 compile, 39/39 executed)** |
|
|
| Multi-name declarations, both spellings — `var a, b, c : integer`, `procedure p (x, y : integer ; z : integer)` | `v-TP3-MULTIDECL` | done, **definitions and formal parameters read a comma-separated list of NAMES and then one `: type`, exactly TPSRC7 `rdvarlst`/`rdvloop` (VAR) and `prfcnt`/`ccomma` (parameters), with `;` between parameter groups. The older `name : type, name : type` spelling still parses, because both reach the same symbols; the names are created as placeholders and given the group's one type afterwards. One `GetWord` that did not `Skip` first attached the space after a comma to the next name (`" B"`), which is why the first name worked and the second did not; `t42_multidecl` prints each name's value to prove every one landed on its own slot (43/43 compile, 39/39 executed)** |
|
|
|
| The 4 KiB code window enforced — TP3 error 98 instead of writing over the data | `v-TP3-CODEWINDOW` | done, **`dataBase` is `rtSz + 1000H`, so code and data share one 64 KiB `.COM` segment and code may not reach it. `Ebyte` now refuses past `dataBase` (guarded by `imgReady`, since `dataBase` is 0 until `Compile` measures it) and reports TP3's error 98, "Memory overflow" — the same number `DefVar` already uses when `dc` overflows. `t43_codewindow` emits more than 4 KiB of inline literal bytes and must report `ERR 98`; disabling the check turns the fixture green-as-`OK`, which is the bug (a silently corrupt image), so the matrix row is the proof (44/44 compile)** |
|
|
| The 4 KiB code window enforced — TP3 error 98 instead of writing over the data | `v-TP3-CODEWINDOW` | done, **`dataBase` is `rtSz + 1000H`, so code and data share one 64 KiB `.COM` segment and code may not reach it. `Ebyte` now refuses past `dataBase` (guarded by `imgReady`, since `dataBase` is 0 until `Compile` measures it) and reports TP3's error 98, "Memory overflow" — the same number `DefVar` already uses when `dc` overflows. `t43_codewindow` emits more than 4 KiB of inline literal bytes and must report `ERR 98`; disabling the check turns the fixture green-as-`OK`, which is the bug (a silently corrupt image), so the matrix row is the proof (44/44 compile)** |
|
|
|
| String subscripts — `s[i]` read, write, and `readln (s[i])` | `v-TP3-STRINDEX` | done, **a STRING is a length byte at `s[0]` followed by the characters, so `s[i]` is the single byte at `off+i`: reading it yields a `CHAR`, assigning to it stores one byte, and `readln (s[i])` reads one byte at `off+i`. A constant index folds into `boff` as an array's does and `r.cls` drops to `TChar`, so `LoadAtom`, `Assignment` and `IoCall` all see one byte. Only a constant index is accepted — a variable index is `ENoLib`, exactly as it already was for an array. The fix uncovered a latent bug: `ParseAtom` did `r.boff := 0` *after* `ParseVar`/`ParseSub`, discarding every subscript, so `s[i]` addressed `off+0` (the length byte). `ParseVar` already zeroes `boff`, so the reset was redundant and was removed. `t44_strindex` prints every indexed byte and `t45_strindex_read` feeds `readln (s[i])`; the indexed read is red before the parse fix and green after (46/46 compile, 41/41 executed)** |
|
|
| String subscripts — `s[i]` read, write, and `readln (s[i])` | `v-TP3-STRINDEX` | done, **a STRING is a length byte at `s[0]` followed by the characters, so `s[i]` is the single byte at `off+i`: reading it yields a `CHAR`, assigning to it stores one byte, and `readln (s[i])` reads one byte at `off+i`. A constant index folds into `boff` as an array's does and `r.cls` drops to `TChar`, so `LoadAtom`, `Assignment` and `IoCall` all see one byte. Only a constant index is accepted — a variable index is `ENoLib`, exactly as it already was for an array. The fix uncovered a latent bug: `ParseAtom` did `r.boff := 0` *after* `ParseVar`/`ParseSub`, discarding every subscript, so `s[i]` addressed `off+0` (the length byte). `ParseVar` already zeroes `boff`, so the reset was redundant and was removed. `t44_strindex` prints every indexed byte and `t45_strindex_read` feeds `readln (s[i])`; the indexed read is red before the parse fix and green after (46/46 compile, 41/41 executed)** |
|
|
|
|
|
+| Variable string subscripts — `s[i]` with a *computed* index | `v-TP3-STRIDX-VAR` | done, **the address of `s[i]` is now computed at run time, so a variable index, a computed one (`i+1`) and a nested one all work — `v-TP3-STRINDEX` accepted a constant only. `ParseSub` evaluates the index into `AX`, then `LEA DI,[base]` / `ADD DI,AX` puts the element's address in `DI` and `r.kind` drops to `5`; `LoadAtom` reads `[DI]`, `Assignment` `PUSH DI`es the destination across its right-hand side (so `g[i] := h[j]` stores where it read — TPSRC8 `asnscal2`/`asnscal3`'s `flgpshdi`, and `SaveLeft` materialises a `DI`-addressed left operand *before* parsing the right), and `IoCall` pushes `DI` for `readln (s[i])`. No runtime entry: the arithmetic is compile-time emitted, so the runtime image is unchanged. Five new one-line emitters are name-audited (`AddDiAx`, `LdAlDi`, `StDiAl`, `PushDi`, `PopDi`) and `LeaDi` is the one documented computed emitter. `t46_strindex_var` reads, writes, compares, passes as an argument and assigns both-indexed (`g[i] := h[j]`), globally and locally; `t47_strindex_var_read` is `readln (g[i])` (48/48 compile, 43/43 executed)** |
|
|
|
|
|
|
|
|
Every row that names a tag has one, and every tag points at a commit on
|
|
Every row that names a tag has one, and every tag points at a commit on
|
|
|
`master`; verified by diffing the rows against `git tag -l`, which is how
|
|
`master`; verified by diffing the rows against `git tag -l`, which is how
|
|
@@ -75,7 +76,7 @@ gm2 -fiso -fuse-module-list=modules.lst -o tpshell \
|
|
|
Shell.mod Compiler.mod Term.o TextBuf.o Posix.o Editor.o # phase B2
|
|
Shell.mod Compiler.mod Term.o TextBuf.o Posix.o Editor.o # phase B2
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-Current clean build: `make clean && make` → rc=0, `tpshell` **191104 bytes**.
|
|
|
|
|
|
|
+Current clean build: `make clean && make` → rc=0, `tpshell` **191272 bytes**.
|
|
|
The one diagnostic is `./Compiler.mod: ParseExpr: too many errors in pass 3`,
|
|
The one diagnostic is `./Compiler.mod: ParseExpr: too many errors in pass 3`,
|
|
|
which is the expected phase-1 rollup that the recipe tolerates — not a real
|
|
which is the expected phase-1 rollup that the recipe tolerates — not a real
|
|
|
error. `shell/Makefile` is the single authoritative build recipe.
|
|
error. `shell/Makefile` is the single authoritative build recipe.
|
|
@@ -127,11 +128,11 @@ needing a squint. It was checked for vacuousness by reverting the string
|
|
|
scanner fix: the suite went red with exit 1, and came back green only when the
|
|
scanner fix: the suite went red with exit 1, and came back green only when the
|
|
|
fix was restored.
|
|
fix was restored.
|
|
|
|
|
|
|
|
-**41 of 46 fixtures compile clean**, up from 1 (the empty program) when the
|
|
|
|
|
|
|
+**43 of 48 fixtures compile clean**, up from 1 (the empty program) when the
|
|
|
direct harness was first built.
|
|
direct harness was first built.
|
|
|
|
|
|
|
|
```
|
|
```
|
|
|
-compile matrix: 46 passed, 0 failed (of 46)
|
|
|
|
|
|
|
+compile matrix: 48 passed, 0 failed (of 48)
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
Compiling: `t01` minimal · `t04` var+assign+`writeln` · `t06` two args ·
|
|
Compiling: `t01` minimal · `t04` var+assign+`writeln` · `t06` two args ·
|
|
@@ -156,7 +157,10 @@ inside a procedure, so both address paths run ·
|
|
|
`t42` `var a, b, c : integer` and `procedure p (x, y : integer ; z : integer)`,
|
|
`t42` `var a, b, c : integer` and `procedure p (x, y : integer ; z : integer)`,
|
|
|
each name landing on its own slot ·
|
|
each name landing on its own slot ·
|
|
|
`t44` `s[i]` read and write on a global and a local string ·
|
|
`t44` `s[i]` read and write on a global and a local string ·
|
|
|
-`t45` `readln (s[i])` storing one character at position `i`.
|
|
|
|
|
|
|
+`t45` `readln (s[i])` storing one character at position `i` ·
|
|
|
|
|
+`t46` `s[i]` with a **variable** index — read, write, compare, an argument and
|
|
|
|
|
+`g[i] := h[j]`, globally and locally ·
|
|
|
|
|
+`t47` `readln (g[i])` with the index in a variable.
|
|
|
|
|
|
|
|
Failing, all deliberately: `t14` `array [1..5] of integer` at its point of use
|
|
Failing, all deliberately: `t14` `array [1..5] of integer` at its point of use
|
|
|
and `t25` a string literal assigned to an *integer* (`i := 'ab'`, the reverse
|
|
and `t25` a string literal assigned to an *integer* (`i := 'ab'`, the reverse
|
|
@@ -168,9 +172,9 @@ refuses the whole class because the runtime has no boolean reader at all; and
|
|
|
"Memory overflow", rather than a corrupt image; and
|
|
"Memory overflow", rather than a corrupt image; and
|
|
|
`uierror` is a deliberate syntax error (41) used by the UI test.
|
|
`uierror` is a deliberate syntax error (41) used by the UI test.
|
|
|
|
|
|
|
|
-`run_com_tests.sh` additionally links **all 41 that compile** to a real `.COM`
|
|
|
|
|
|
|
+`run_com_tests.sh` additionally links **all 43 that compile** to a real `.COM`
|
|
|
and re-verifies the bytes with an independent Python checker that *measures*
|
|
and re-verifies the bytes with an independent Python checker that *measures*
|
|
|
-the layout instead of restating it: `independent .COM check: 41 checked, 0
|
|
|
|
|
|
|
+the layout instead of restating it: `independent .COM check: 43 checked, 0
|
|
|
failed`. That last part was itself a bug fix — see "the two restated
|
|
failed`. That last part was itself a bug fix — see "the two restated
|
|
|
constants" below.
|
|
constants" below.
|
|
|
|
|
|
|
@@ -209,12 +213,12 @@ proves each one can go red.
|
|
|
|---|---|---|
|
|
|---|---|---|
|
|
|
| `probe/run_modrm19.py` | the mod=00/01/10 effective addresses, by **executing** 23 cases on a real 8086 under qemu and scanning for where the marker landed | mod=11 — see below |
|
|
| `probe/run_modrm19.py` | the mod=00/01/10 effective addresses, by **executing** 23 cases on a real 8086 under qemu and scanning for where the marker landed | mod=11 — see below |
|
|
|
| `probe/modrm11.py` | the mod=11 register identities, by **encoding** with GNU `as` and decoding with FCML, against hard-coded bytes | the table agreeing with itself |
|
|
| `probe/modrm11.py` | the mod=11 register identities, by **encoding** with GNU `as` and decoding with FCML, against hard-coded bytes | the table agreeing with itself |
|
|
|
-| `audit_helpers.py` | every one-line emitter in **both** `Runtime.mod` and `Compiler.mod` decodes to what its *name* says — **105/105**, from an inventory scanned independently of the parser | anything longer than one instruction |
|
|
|
|
|
|
|
+| `audit_helpers.py` | every one-line emitter in **both** `Runtime.mod` and `Compiler.mod` decodes to what its *name* says — **110/110**, from an inventory scanned independently of the parser | anything longer than one instruction |
|
|
|
| `check_comimage.py` | a linked image's layout is described in **exactly one file**: `comimage.py` defines each part once, every reader imports it, no second `find_header` exists anywhere in `tests/` | a check that *hand-rolls* the layout from literals (`hdr = 3 + rt_size`), which defines none of those names — the readers catch that a different way: each states the layout twice, from two independent sources, and requires the two to agree |
|
|
| `check_comimage.py` | a linked image's layout is described in **exactly one file**: `comimage.py` defines each part once, every reader imports it, no second `find_header` exists anywhere in `tests/` | a check that *hand-rolls* the layout from literals (`hdr = 3 + rt_size`), which defines none of those names — the readers catch that a different way: each states the layout twice, from two independent sources, and requires the two to agree |
|
|
|
| `check_runtime.py` + `runtime.golden` | the built runtime's code region (585 bytes, code 0..584) sweeps cleanly through FCML, every entry and all branch targets land on an instruction boundary, and the whole disassembly is byte-for-byte the committed golden | whether the golden is *right* |
|
|
| `check_runtime.py` + `runtime.golden` | the built runtime's code region (585 bytes, code 0..584) sweeps cleanly through FCML, every entry and all branch targets land on an instruction boundary, and the whole disassembly is byte-for-byte the committed golden | whether the golden is *right* |
|
|
|
| `check_framedisp.py` | `[BP+off]` uses disp8 iff `off <= 127`, for locals (negative) and far parameters (>127) | which of the two encodings was chosen, if the other also works |
|
|
| `check_framedisp.py` | `[BP+off]` uses disp8 iff `off <= 127`, for locals (negative) and far parameters (>127) | which of the two encodings was chosen, if the other also works |
|
|
|
| `run_com_exec.py` | the **emitted image executes** and prints exactly the expected bytes | semantics the fixture never exercises |
|
|
| `run_com_exec.py` | the **emitted image executes** and prints exactly the expected bytes | semantics the fixture never exercises |
|
|
|
-| `run_exec86.py` | the same image runs in a **second, independent 8086** and agrees with qemu byte for byte, 41/41 | the `.out` file it shares with `run_com_exec.py` — a wrong expectation fails both at once |
|
|
|
|
|
|
|
+| `run_exec86.py` | the same image runs in a **second, independent 8086** and agrees with qemu byte for byte, 43/43 | the `.out` file it shares with `run_com_exec.py` — a wrong expectation fails both at once |
|
|
|
| `rt_exec.py` | the **runtime entries themselves** are called directly, one qemu boot per call, 50 cases plus a pre-flight, 51/51 — plus a `check_bp_contract` pre-flight over the built blob: an entry that borrows BP must open with `55 8B EC` (exact) and contain a `5D` (a screen, because `5D` is also a displacement byte) | whether the *caller's* half of a contract is right, where the only witness is a case that happens to make two calls in a row |
|
|
| `rt_exec.py` | the **runtime entries themselves** are called directly, one qemu boot per call, 50 cases plus a pre-flight, 51/51 — plus a `check_bp_contract` pre-flight over the built blob: an entry that borrows BP must open with `55 8B EC` (exact) and contain a `5D` (a screen, because `5D` is also a displacement byte) | whether the *caller's* half of a contract is right, where the only witness is a case that happens to make two calls in a row |
|
|
|
|
|
|
|
|
Two of these deserve the detail, because the reason they exist is the reason
|
|
Two of these deserve the detail, because the reason they exist is the reason
|
|
@@ -347,7 +351,7 @@ compiler: **does the 8086 have this instruction at all?**
|
|
|
value conditions : = x6 <> x2 < x5 >= x3 <= x2 > x16
|
|
value conditions : = x6 <> x2 < x5 >= x3 <= x2 > x16
|
|
|
branch conditions : IF / REPEAT x9 CASE x2 FOR downto x1 FOR to x3
|
|
branch conditions : IF / REPEAT x9 CASE x2 FOR downto x1 FOR to x3
|
|
|
runtime: 616 bytes, 330 swept, 0 0F-prefixed
|
|
runtime: 616 bytes, 330 swept, 0 0F-prefixed
|
|
|
- program code: 41 of 41 fixtures swept end to end, 4963 bytes
|
|
|
|
|
|
|
+ program code: 43 of 43 fixtures swept end to end, 5697 bytes
|
|
|
t33_cmpops: 13 comparisons matched against their source operators, in order
|
|
t33_cmpops: 13 comparisons matched against their source operators, in order
|
|
|
clause H: 8 of 8 fixtures matched the branch conditions read off their source
|
|
clause H: 8 of 8 fixtures matched the branch conditions read off their source
|
|
|
```
|
|
```
|
|
@@ -590,7 +594,7 @@ checker.
|
|
|
compile to `.COM` images, are booted on a floppy by a 512-byte hand-assembled
|
|
compile to `.COM` images, are booted on a floppy by a 512-byte hand-assembled
|
|
|
boot sector, and are compared **byte for byte** against the exact output the
|
|
boot sector, and are compared **byte for byte** against the exact output the
|
|
|
fixture demands — `tests/run_com_exec.py`, wired into `run_all.sh`, 21/21 at
|
|
fixture demands — `tests/run_com_exec.py`, wired into `run_all.sh`, 21/21 at
|
|
|
-that tag and 41/41 now.
|
|
|
|
|
|
|
+that tag and 43/43 now.
|
|
|
|
|
|
|
|
Everything below is about establishing what *can* be believed, because the
|
|
Everything below is about establishing what *can* be believed, because the
|
|
|
first attempt at this used an emulator that was wrong, and a wrong oracle is
|
|
first attempt at this used an emulator that was wrong, and a wrong oracle is
|
|
@@ -920,7 +924,8 @@ position), and code/data size accounting. Emitted image is a byte array
|
|
|
Working subset (v0.5): integer/char/boolean/byte scalars, constants with
|
|
Working subset (v0.5): integer/char/boolean/byte scalars, constants with
|
|
|
folding, globals, locals, value parameters, procedures and scalar-result
|
|
folding, globals, locals, value parameters, procedures and scalar-result
|
|
|
functions, `ARRAY[const..const]` with constant indexing, `string [n]`
|
|
functions, `ARRAY[const..const]` with constant indexing, `string [n]`
|
|
|
-variables with literal assignment, string-to-string assignment and
|
|
|
|
|
|
|
+variables with literal assignment, string-to-string assignment, `s[i]`
|
|
|
|
|
+subscripting (constant **or** variable index) and
|
|
|
`readln`/`read` into a string, control flow,
|
|
`readln`/`read` into a string, control flow,
|
|
|
`GOTO`/`EXIT`, the standard procedures `WRITE`, `WRITELN`, `READ`,
|
|
`GOTO`/`EXIT`, the standard procedures `WRITE`, `WRITELN`, `READ`,
|
|
|
`READLN`, `HALT`, and **inline string literals** as `WRITE`/`WRITELN`
|
|
`READLN`, `HALT`, and **inline string literals** as `WRITE`/`WRITELN`
|
|
@@ -1161,10 +1166,12 @@ Details that are deliberate, not incidental:
|
|
|
The length is one byte, so 300 characters would go out behind a length of
|
|
The length is one byte, so 300 characters would go out behind a length of
|
|
|
44 and the runtime would print 44 of them and silently drop the rest. TP3
|
|
44 and the runtime would print 44 of them and silently drop the rest. TP3
|
|
|
strings are at most 255 characters, so refusing is the faithful answer.
|
|
strings are at most 255 characters, so refusing is the faithful answer.
|
|
|
-- **A string *variable* is a real store now, not a refusal.** `s := 'hi'` and
|
|
|
|
|
- `writeln(s)` compile (see `v-TP3-STRVAR`); what is still refused is
|
|
|
|
|
- `readln(s)`, `s := another_string`, `s [i]` indexing and a literal assigned
|
|
|
|
|
- to a non-string — all `ENoLib`, because none of them has an encoding yet.
|
|
|
|
|
|
|
+- **A string *variable* is a real store now, not a refusal.** `s := 'hi'`,
|
|
|
|
|
+ `writeln(s)`, `readln(s)`, `s := another_string` and `s[i]` indexing
|
|
|
|
|
+ (constant or variable) all compile (see `v-TP3-STRVAR`,
|
|
|
|
|
+ `v-TP3-STRREAD-ASSIGN`, `v-TP3-STRINDEX`, `v-TP3-STRIDX-VAR`); what is still
|
|
|
|
|
+ refused is the string `+` and comparison operators, and a literal assigned to
|
|
|
|
|
+ a non-string — `ENoLib`, because neither has an encoding yet.
|
|
|
|
|
|
|
|
|
|
|
|
|
## Honest limitations
|
|
## Honest limitations
|
|
@@ -1175,7 +1182,7 @@ Details that are deliberate, not incidental:
|
|
|
prove the *path* exists (compile → poke → run → report → no file written),
|
|
prove the *path* exists (compile → poke → run → report → no file written),
|
|
|
which it does with eight assertions. The other 37 are covered by
|
|
which it does with eight assertions. The other 37 are covered by
|
|
|
`run_exec86.py`, which calls the same interpreter directly.
|
|
`run_exec86.py`, which calls the same interpreter directly.
|
|
|
-- **Every fixture that compiles is now also run.** 41 of 46 execute; the 5 that
|
|
|
|
|
|
|
+- **Every fixture that compiles is now also run.** 43 of 48 execute; the 5 that
|
|
|
do not are `t14` and `t25` (`ENoLib`, by design), `t38` (a boolean read,
|
|
do not are `t14` and `t25` (`ENoLib`, by design), `t38` (a boolean read,
|
|
|
refused with TP3's error 66, by design), `t43` (a program whose code exceeds
|
|
refused with TP3's error 66, by design), `t43` (a program whose code exceeds
|
|
|
the 4 KiB window, refused with error 98, by design) and `uierror` (a
|
|
the 4 KiB window, refused with error 98, by design) and `uierror` (a
|
|
@@ -1301,9 +1308,11 @@ Details that are deliberate, not incidental:
|
|
|
input.** `program p(1;)` would loop forever. The fix needs a `BOOLEAN` flag
|
|
input.** `program p(1;)` would loop forever. The fix needs a `BOOLEAN` flag
|
|
|
and **must not** use `EXIT`, which ICEs gm2 in pass 3 (see the pitfalls
|
|
and **must not** use `EXIT`, which ICEs gm2 in pass 3 (see the pitfalls
|
|
|
list). Not yet done.
|
|
list). Not yet done.
|
|
|
-- **Not implemented** (all `ENoLib`): real, set, record, file, string
|
|
|
|
|
- *indexing* (`s[i]`), the `+`/comparison string
|
|
|
|
|
|
|
+- **Not implemented** (all `ENoLib`): real, set, record, file, the string
|
|
|
|
|
+ `+`/comparison
|
|
|
operators, and any declared type wider than 2 bytes other than `TString`.
|
|
operators, and any declared type wider than 2 bytes other than `TString`.
|
|
|
|
|
+ A string *subscript* `s[i]` — constant (`v-TP3-STRINDEX`) or variable
|
|
|
|
|
+ (`v-TP3-STRIDX-VAR`) — is implemented.
|
|
|
`with` is `ENoLib`. `case` *is*
|
|
`with` is `ENoLib`. `case` *is*
|
|
|
implemented (cascade `CMP`/`JNZ` per label, per RESUME-TP3.md §3.6) but only
|
|
implemented (cascade `CMP`/`JNZ` per label, per RESUME-TP3.md §3.6) but only
|
|
|
over scalar labels — subrange labels and label lists are untested.
|
|
over scalar labels — subrange labels and label lists are untested.
|
|
@@ -1995,10 +2004,12 @@ independently-scanned inventory at all.
|
|
|
|
|
|
|
|
1. The rest of the string language. `v-TP3-STRVAR`/`v-TP3-STRREAD-ASSIGN` cover
|
|
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)`
|
|
string variables, `s := 'literal'`, `writeln (s)`, `readln (s)`/`read (s)`
|
|
|
- and `s := t`; `v-TP3-STRINDEX` covers `s[i]` with a **constant** index —
|
|
|
|
|
- read, write and `readln (s[i])`. Still `ENoLib`: a *variable* index `s [i]`
|
|
|
|
|
- (the runtime address arithmetic TPSRC9 `indstr`/`ialoop` does), and the `+`
|
|
|
|
|
- / comparison operators (`cmpstr`/`xconcat`, TPSRC2).
|
|
|
|
|
|
|
+ and `s := t`; `v-TP3-STRINDEX` covers `s[i]` with a constant index and
|
|
|
|
|
+ `v-TP3-STRIDX-VAR` covers a **variable/computed** one — read, write,
|
|
|
|
|
+ `readln (s[i])`, comparison against a char, use as an argument, and
|
|
|
|
|
+ `g[i] := h[j]`. Still `ENoLib`: the `+` and the whole-string comparison
|
|
|
|
|
+ operators (`cmpstr`/`xconcat`, TPSRC2 — the latter needs a runtime entry,
|
|
|
|
|
+ the next selector is 18).
|
|
|
2. Nested procedures / recursion, `var` parameters (the `SEG:OFF` push from
|
|
2. Nested procedures / recursion, `var` parameters (the `SEG:OFF` push from
|
|
|
RESUME-TP3.md §3.11), range/index checks (`TU_RANGE_CHECK`,
|
|
RESUME-TP3.md §3.11), range/index checks (`TU_RANGE_CHECK`,
|
|
|
`TU_INDEX_CHECK`), typed constants (RESUME-TP3.md §3.14), `array` at its
|
|
`TU_INDEX_CHECK`), typed constants (RESUME-TP3.md §3.14), `array` at its
|