Sfoglia il codice sorgente

Complete Nova128 pass-3 sizing and MAP records (E04-S07).

main
Daniel Covington 4 giorni fa
parent
commit
1d30db1843
25 ha cambiato i file con 476 aggiunte e 85 eliminazioni
  1. +18
    -6
      newLang/docs/architecture.md
  2. +2
    -1
      newLang/docs/decisions.md
  3. +1
    -0
      newLang/docs/diagnostics.md
  4. +11
    -7
      newLang/docs/memory-map.md
  5. +46
    -48
      newLang/planning/claims/E04-S07.md
  6. +1
    -0
      newLang/scripts/build-calls-test.ps1
  7. +1
    -0
      newLang/scripts/build-hello-test.ps1
  8. +2
    -0
      newLang/scripts/build-parser-test.ps1
  9. +1
    -0
      newLang/scripts/build-statements-test.ps1
  10. +1
    -0
      newLang/scripts/demo-write-check.ps1
  11. +4
    -1
      newLang/scripts/verify-class-test.ps1
  12. +1
    -0
      newLang/scripts/verify-counter-test.ps1
  13. +1
    -0
      newLang/src/common/diagcat.inc
  14. +1
    -0
      newLang/src/common/emit.inc
  15. +3
    -0
      newLang/src/common/formats.inc
  16. +10
    -3
      newLang/src/compiler/diagnostics.s
  17. +24
    -1
      newLang/src/compiler/emit.s
  18. +134
    -1
      newLang/src/compiler/output.s
  19. +44
    -3
      newLang/src/compiler/parser.s
  20. +120
    -2
      newLang/src/compiler/sizing.s
  21. +4
    -7
      newLang/tests/compiler/counter-test.s
  22. +2
    -1
      newLang/tests/parser/parser-test.s
  23. +3
    -0
      newLang/tests/parser/unresolved.expect
  24. +9
    -0
      newLang/tests/parser/unresolved.n8
  25. +32
    -4
      newLang/tests/runtime/class-test.s

+ 18
- 6
newLang/docs/architecture.md Vedi File

@@ -308,7 +308,8 @@ memory.


- Load address `$1C01`; BASIC 7 stub `10 SYS 7181`; entry `$1C0D`. - Load address `$1C01`; BASIC 7 stub `10 SYS 7181`; entry `$1C0D`.
- Sections are contiguous and ascending; gaps are zero-filled. - Sections are contiguous and ascending; gaps are zero-filled.
- `NAME.MAP` records `ENTRY` and every `SECTION name start size` in hex.
- `NAME.MAP` records `ENTRY`, every `SECTION name start size`, and optional
`CLASS`/`METHOD` records in hex.
- The E04-S01 startup writes the mailbox with producer `$03`, then PASS, and - The E04-S01 startup writes the mailbox with producer `$03`, then PASS, and
returns to BASIC. E04-S02 supplies the frame runtime separately; code returns to BASIC. E04-S02 supplies the frame runtime separately; code
generation will switch to CR `$0E` and initialize frames when it emits user generation will switch to CR `$0E` and initialize frames when it emits user
@@ -607,7 +608,7 @@ prologue, and sizing/pass-3 addresses remain unimplemented. `for` currently
requires a constant byte end and step 1 and leaves the loop variable one past requires a constant byte end and step 1 and leaves the loop variable one past
the end value. E04-S07 owns those limits and the 255-byte code buffer. the end value. E04-S07 owns those limits and the 255-byte code buffer.


### 7.12 Pass-3 relocation and counter (E04-S07, partial)
### 7.12 Pass-3 relocation and sizing (E04-S07)


`sizing.s` computes the final CODE base from `PRG_ENTRY_ADDR` plus the bytes `sizing.s` computes the final CODE base from `PRG_ENTRY_ADDR` plus the bytes
before the section and installs it through `parse_file_base`. `flow.s` resolves before the section and installs it through `parse_file_base`. `flow.s` resolves
@@ -615,6 +616,14 @@ absolute `JMP` and `JSR` operands against that base; relative branches remain
offset-based. Normal `parse_file` clears the base request, so the in-place offset-based. Normal `parse_file` clears the base request, so the in-place
statement and call fixtures keep using `cg_code`. statement and call fixtures keep using `cg_code`.


`parse_file_sized` selects count mode with `em_count`, captures the count
pass with `sz_capture`, then reruns with emission enabled and diagnostics
suppressed. `sz_verify` compares the code length, entry offset, routine sizes,
and all 64 label offsets; any difference raises `RES_SIZE_MISMATCH` (E228).
Routine lengths are recorded by `em_end_func` in `em_routine_sizes`.
`output.s` appends `METHOD name address` records after `CLASS` records, so
descriptor and method entry addresses appear in the deterministic MAP.

`counter.n8` is a two-local program: `total = 0`, then `for i = 1 to 5` adds `counter.n8` is a two-local program: `total = 0`, then `for i = 1 to 5` adds
`i` to `total`. Its fixture emits `COUNTER.PRG` and `COUNTB.PRG` with final `i` to `total`. Its fixture emits `COUNTER.PRG` and `COUNTB.PRG` with final
`STUB`, `START`, and `CODE` addresses, checks the two files are byte-identical, `STUB`, `START`, and `CODE` addresses, checks the two files are byte-identical,
@@ -622,9 +631,11 @@ and runs `COUNTER.PRG` in a second x128 session. The fixture-owned wrapper
selects CR `$0E`, points `FRAME_FP` at the software frame area, calls the code, selects CR `$0E`, points `FRAME_FP` at the software frame area, calls the code,
reports `total`, and restores the entry mapping. The observed result is 15. reports `total`, and restores the entry mapping. The observed result is 15.


This closes final code relocation and the first real source-to-PRG run, but not
E04-S07's count-mode routine sizing, method/class MAP records, or a single
unresolved-reference diagnostic.
The counter fixture also verifies a zero sizing-mismatch counter. The parser's
`unresolved.n8` fixture produces exactly one `SEM_UNKNOWN_NAME` (E61) for an
unknown method, with no bad-operand follow-up. The class fixture checks
`METHOD DESTROY` and `METHOD STUB` MAP records, and the output fixture
reconfirms the E202 overwrite refusal.


## 8. Heap and Ownership ## 8. Heap and Ownership


@@ -680,10 +691,11 @@ MAP lines after the section records:


```text ```text
CLASS name size destroy interface-count interface-directory CLASS name size destroy interface-count interface-directory
METHOD name address
``` ```


All numeric fields are four hex digits except the interface count, which is All numeric fields are four hex digits except the interface count, which is
two. Empty classes and no destructor are written as `0000`; records keep the
two. METHOD records follow all CLASS records in `out_method` call order. Empty classes and no destructor are written as `0000`; records keep the
caller's order. The class test reads the emitted MAP back and compares it with caller's order. The class test reads the emitted MAP back and compares it with
the descriptor's actual destructor and directory addresses. the descriptor's actual destructor and directory addresses.




+ 2
- 1
newLang/docs/decisions.md Vedi File

@@ -66,7 +66,8 @@ documented default. `Proposed` means a later change still needs approval.
| D137 | E04-S06 emission is driven from parser pass 2: with `em_on` set, the parser calls `emit.s` as it type-checks each statement, and `parse_file` resets the emitter (and the code buffer) at the start of pass 2; pass 1 only assigns the same slots. Parameters take `FP+2` upward in declaration order, locals `FP-1` downward, one byte for byte-sized types and two for words. A slot is reached by emitting `EM_LP = FRAME_FP + offset` with the offset's sign byte, because `(FP),Y` cannot address below `FP`; `EM_LP` is `$F5-$F6` and the combine temp `EM_TMP` is `$F7`. Byte `+`/`-` keep the left operand on the hardware stack. Print calls go through the `em_pr_text/byte/cr` cells and three `JMP (cell)` trampolines, so a fixture can record output without CHROUT. Emitter failures set `em_bad` (`EM_ERR_SIZE`, `EM_ERR_TARGET`, `EM_ERR_OP`, `EM_ERR_STATE`) and stop emitting; nothing is written outside the code buffer. | Gives the first parser-to-codegen path a testable shape without freezing pass 3: the fixture executes the emitted bytes in place and checks locals and recorded output. The 255-byte buffer, one captured string literal, and the fixture-owned frame prologue are known limits for E04-S07, which owns sizing, section addresses, and `frame_enter`. Control flow, calls, fields, word values, arrays, and diagnostic reporting remain E04-S06 work. Implemented by `emit.s`, `emit.inc`, the `parser.s` hooks, `codegen.s`, and the statements fixture. | | D137 | E04-S06 emission is driven from parser pass 2: with `em_on` set, the parser calls `emit.s` as it type-checks each statement, and `parse_file` resets the emitter (and the code buffer) at the start of pass 2; pass 1 only assigns the same slots. Parameters take `FP+2` upward in declaration order, locals `FP-1` downward, one byte for byte-sized types and two for words. A slot is reached by emitting `EM_LP = FRAME_FP + offset` with the offset's sign byte, because `(FP),Y` cannot address below `FP`; `EM_LP` is `$F5-$F6` and the combine temp `EM_TMP` is `$F7`. Byte `+`/`-` keep the left operand on the hardware stack. Print calls go through the `em_pr_text/byte/cr` cells and three `JMP (cell)` trampolines, so a fixture can record output without CHROUT. Emitter failures set `em_bad` (`EM_ERR_SIZE`, `EM_ERR_TARGET`, `EM_ERR_OP`, `EM_ERR_STATE`) and stop emitting; nothing is written outside the code buffer. | Gives the first parser-to-codegen path a testable shape without freezing pass 3: the fixture executes the emitted bytes in place and checks locals and recorded output. The 255-byte buffer, one captured string literal, and the fixture-owned frame prologue are known limits for E04-S07, which owns sizing, section addresses, and `frame_enter`. Control flow, calls, fields, word values, arrays, and diagnostic reporting remain E04-S06 work. Implemented by `emit.s`, `emit.inc`, the `parser.s` hooks, `codegen.s`, and the statements fixture. |
| D138 | E04-S06 completes the pass-2 emission path above D137. `flow.s` grows to 64 labels and 128 fixups; `if`/`else`, `while`, a constant-byte-end positive-step-1 `for`, and `return` emit through five-byte branches, `JMP` back edges, and `JSR` fixups. `fl_release` remains a successful no-op because released labels could still have unresolved fixups. Each method gets a stable entry label allocated by member row, so a call written before the method body resolves forward; `em_entry` records the program body's offset in `cg_code` so a fixture runs the program rather than a class method. `em_bad` is converted to `E_RES_EMIT_FAILED` (E227) after pass 2. The three print vectors are absolute zero-page cells at `$C0-$C5` (`em_pr_text`, `em_pr_byte`, `em_pr_cr`), so their low byte is never `$FF` and the `JMP (cell)` trampolines avoid the 6502 indirect-JMP page bug; six reserved BSS bytes preserve the existing layout of later emitter state. | Closes the E04-S06 byte-code path without changing the generated container. `for` ends one past its end value and currently requires a constant byte end and step 1; `return` is a bare `RTS` because the frame prologue is still fixture-owned. Word values, call arguments, arrays, method result forwarding, and the sizing/pass-3 address pass remain explicitly unimplemented and belong to E04-S07. Implemented by `emit.s`, `flow.s`, `parser.s`, `codegen.s`, `diagcat.inc`, the statements fixture, and the calls fixture. | | D138 | E04-S06 completes the pass-2 emission path above D137. `flow.s` grows to 64 labels and 128 fixups; `if`/`else`, `while`, a constant-byte-end positive-step-1 `for`, and `return` emit through five-byte branches, `JMP` back edges, and `JSR` fixups. `fl_release` remains a successful no-op because released labels could still have unresolved fixups. Each method gets a stable entry label allocated by member row, so a call written before the method body resolves forward; `em_entry` records the program body's offset in `cg_code` so a fixture runs the program rather than a class method. `em_bad` is converted to `E_RES_EMIT_FAILED` (E227) after pass 2. The three print vectors are absolute zero-page cells at `$C0-$C5` (`em_pr_text`, `em_pr_byte`, `em_pr_cr`), so their low byte is never `$FF` and the `JMP (cell)` trampolines avoid the 6502 indirect-JMP page bug; six reserved BSS bytes preserve the existing layout of later emitter state. | Closes the E04-S06 byte-code path without changing the generated container. `for` ends one past its end value and currently requires a constant byte end and step 1; `return` is a bare `RTS` because the frame prologue is still fixture-owned. Word values, call arguments, arrays, method result forwarding, and the sizing/pass-3 address pass remain explicitly unimplemented and belong to E04-S07. Implemented by `emit.s`, `flow.s`, `parser.s`, `codegen.s`, `diagcat.inc`, the statements fixture, and the calls fixture. |


| D139 | E04-S07 begins the pass-3 address path. `flow.s` resolves absolute `JMP`/`JSR` operands against `fl_code_base`, which defaults to `cg_code`; `sizing.s` computes the final code base as `PRG_ENTRY_ADDR + bytes before CODE` and installs it with `em_set_base` before pass 2. `counter.n8` aliases two local bytes, loops `i = 1 to 5`, and sums into `total`; its fixture writes `COUNTER.PRG`/`COUNTB.PRG` with STUB, START, and CODE sections. The generated wrapper selects CR `$0E`, sets `FRAME_FP` to `$BF80`, calls the code base, reads `total`, restores CR, and reports PASS. | Proves final section addresses and generated-code relocation in a real x128 run while keeping existing in-place emitter fixtures unchanged. Count-mode routine sizing/mismatch accounting, method and class records in the MAP, unresolved-reference diagnostics, and general pass-3 scheduling remain E04-S07 work. Implemented by `flow.s`, `emit.s`, `sizing.s`, `counter.n8`, the counter fixture, and its scripts. |
| D139 | E04-S07 begins the pass-3 address path. `flow.s` resolves absolute `JMP`/`JSR` operands against `fl_code_base`, which defaults to `cg_code`; `sizing.s` computes the final code base as `PRG_ENTRY_ADDR + bytes before CODE` and installs it with `em_set_base` before pass 2. `counter.n8` aliases two local bytes, loops `i = 1 to 5`, and sums into `total`; its fixture writes `COUNTER.PRG`/`COUNTB.PRG` with STUB, START, and CODE sections. The generated wrapper selects CR `$0E`, sets `FRAME_FP` to `$BF80`, calls the code base, reads `total`, restores CR, and reports PASS. | Proves final section addresses and generated-code relocation in a real x128 run while keeping existing in-place emitter fixtures unchanged. D140 completes the count-mode and MAP work for E04-S07. Implemented by `flow.s`, `emit.s`, `sizing.s`, `counter.n8`, the counter fixture, and its scripts. |
| D140 | E04-S07 completes count-mode sizing and the MAP/diagnostic evidence. `em_count` selects the count pass; `em_end_func` records each routine length in `em_routine_sizes`; `sz_capture` snapshots code length, entry, routine sizes, and all 64 label offsets; the emitting pass runs with `diag_suppress`; `sz_verify` counts every difference and raises `RES_SIZE_MISMATCH` (E228) after the pass. The counter fixture requires `sz_mismatch = 0`, 175 code bytes, `CODE 1C4F`, deterministic PRGs, and `total = 15`. `output.s` adds `METHOD name address` records after `CLASS` records, proven by `METHOD DESTROY`/`METHOD STUB` in the class MAP. `tests/parser/unresolved.n8` proves one unknown method produces exactly one `SEM_UNKNOWN_NAME` (E61), and the output suite still proves E202 in the pass-3-adjacent writer path. | Closes the E04-S07 acceptance evidence without changing ordinary in-place fixtures: `parse_file` clears `em_count`, `diag_suppress`, and the base request, while `parse_file_sized` opts into the counted path. The code buffer remains 255 bytes and `em_entry` remains an offset; general program startup and frame sizing are separate work. Implemented by `parser.s`, `emit.s`, `emit.inc`, `sizing.s`, `diagnostics.s`, `diagcat.inc`, `output.s`, `formats.inc`, the counter/class/output/parser fixtures, and their scripts. |


## Deferred ## Deferred




+ 1
- 0
newLang/docs/diagnostics.md Vedi File

@@ -131,3 +131,4 @@ After 20 errors the next one is replaced by E221 and compilation stops.
| E225 | `RES_EXPR_TOO_DEEP` | EXPRESSION NESTED TOO DEEPLY | | E225 | `RES_EXPR_TOO_DEEP` | EXPRESSION NESTED TOO DEEPLY |
| E226 | `RES_TOO_MANY_IMPLEMENTS` | MORE THAN 255 IMPLEMENTED INTERFACES | | E226 | `RES_TOO_MANY_IMPLEMENTS` | MORE THAN 255 IMPLEMENTED INTERFACES |
| E227 | `RES_EMIT_FAILED` | CANNOT EMIT THIS CODE YET | | E227 | `RES_EMIT_FAILED` | CANNOT EMIT THIS CODE YET |
| E228 | `RES_SIZE_MISMATCH` | CODE SIZE CHANGED BETWEEN PASSES |

+ 11
- 7
newLang/docs/memory-map.md Vedi File

@@ -19,7 +19,7 @@ later stories.
| BASIC 7 stub | 12 bytes, `10 SYS 7181` | | BASIC 7 stub | 12 bytes, `10 SYS 7181` |
| Entry | `$1C0D` | | Entry | `$1C0D` |
| Sections | ascending addresses, zero-filled gaps | | Sections | ascending addresses, zero-filled gaps |
| MAP | `NOVA128 MAP 1`, `ENTRY hhhh`, `SECTION name start size`, `CLASS name size destroy count ifdir` |
| MAP | `NOVA128 MAP 1`, `ENTRY hhhh`, `SECTION name start size`, `CLASS name size destroy count ifdir`, `METHOD name address` |
| Startup | clears mailbox, producer `$03`, status PASS, then `RTS` | | Startup | clears mailbox, producer `$03`, status PASS, then `RTS` |


The fixed startup is copied from `src/runtime/startup.s`; `output.s` refuses The fixed startup is copied from `src/runtime/startup.s`; `output.s` refuses
@@ -71,6 +71,8 @@ the first field at +2, so generated code needs no runtime translation.
| Program entry | `em_entry` = offset of the program body in `cg_code` | | Program entry | `em_entry` = offset of the program body in `cg_code` |
| Code buffer | `cg_code`, 255 bytes (E04-S03) | | Code buffer | `cg_code`, 255 bytes (E04-S03) |
| Final code base | `fl_code_base`, default `cg_code`; pass 3 uses `PRG_ENTRY_ADDR + pre-CODE bytes` | | Final code base | `fl_code_base`, default `cg_code`; pass 3 uses `PRG_ENTRY_ADDR + pre-CODE bytes` |
| Routine sizes | `em_routine_sizes`, one byte per routine, recorded by `em_end_func` |
| Sizing mismatch | `sz_mismatch`; nonzero raises E228 after the emitting pass |
| Print entries | `em_pr_text`/`em_pr_byte`/`em_pr_cr` cells at `$C0-$C5`, with `JMP (cell)` trampolines | | Print entries | `em_pr_text`/`em_pr_byte`/`em_pr_cr` cells at `$C0-$C5`, with `JMP (cell)` trampolines |


`EM_LP` and `EM_TMP` sit below `MB_SELF` (`$F9-$FA`) and clear of the frame `EM_LP` and `EM_TMP` sit below `MB_SELF` (`$F9-$FA`) and clear of the frame
@@ -83,8 +85,9 @@ Control-flow labels use the `flow.s` pool; `if`/`while`/`for` labels are
released only after their fixups resolve. Method entry labels are allocated by released only after their fixups resolve. Method entry labels are allocated by
member row, so a forward self-call can target a method body parsed later. The member row, so a forward self-call can target a method body parsed later. The
255-byte code buffer and the one-byte `em_entry` still bound the current 255-byte code buffer and the one-byte `em_entry` still bound the current
emitted program; pass 3 currently relocates absolute targets but does not yet
replace either limit with count-mode sizing.
emitted program. Count-mode sizing checks that the emitting pass keeps the
same length and label offsets; a mismatch raises E228 instead of producing a
shifted program.


## Heap Fixture (E05-S01) ## Heap Fixture (E05-S01)


@@ -113,13 +116,14 @@ wired.
| Destructor | `$0000` means none | | Destructor | `$0000` means none |
| Interface directory | 4-byte entries: interface descriptor, method table | | Interface directory | 4-byte entries: interface descriptor, method table |
| Flags | reserved, must be 0; no parent-class slot | | Flags | reserved, must be 0; no parent-class slot |
| MAP | `CLASS name size destroy count ifdir` after sections |
| MAP | `CLASS name size destroy count ifdir` and `METHOD name address` after sections |


The ABI is fixed in `src/common/class.inc`; D134 records the provisional The ABI is fixed in `src/common/class.inc`; D134 records the provisional
decision. `src/runtime/objects.s` reads descriptors and objects without decision. `src/runtime/objects.s` reads descriptors and objects without
allocating. `output.s` writes class MAP records in `out_class` call order; the
E05-S02 fixture checks a no-destructor/no-interface class and a destructor plus
one interface entry. Interface dispatch remains E06 work.
allocating. `output.s` writes class MAP records in `out_class` call order and method MAP
records in `out_method` call order; the E05-S02 fixture checks a
no-destructor/no-interface class, a destructor plus one interface entry, and
two method addresses. Interface dispatch remains E06 work.


## Construction and Deletion (E05-S03) ## Construction and Deletion (E05-S03)




+ 46
- 48
newLang/planning/claims/E04-S07.md Vedi File

@@ -1,8 +1,9 @@
--- ---
story: E04-S07 story: E04-S07
owner: codebuff owner: codebuff
status: in-progress
status: done
started: 2026-11-10 started: 2026-11-10
completed: 2026-11-10
depends-on: [E04-S06] depends-on: [E04-S06]
--- ---


@@ -10,65 +11,62 @@ depends-on: [E04-S06]


## Intended change ## Intended change


Begin the pass-3 address path: relocate absolute flow targets against the
final CODE base, add `sizing.s` address planning, and prove a real source file
compiles to deterministic PRGs and runs in x128.
Finish the pass-3 address path: count-mode sizing with zero mismatch, final
section and method addresses in the MAP, unresolved-reference diagnostics,
deterministic PRGs, and a real source file running in x128.


## File area ## File area


- `src/compiler/flow.s`, `src/compiler/emit.s`, `src/compiler/sizing.s`
- `src/compiler/flow.s`, `emit.s`, `sizing.s`, `parser.s`, `diagnostics.s`
- `src/compiler/output.s`, `src/common/formats.inc`, `diagcat.inc`
- `tests/compiler/counter.n8`, `tests/compiler/counter-test.s` - `tests/compiler/counter.n8`, `tests/compiler/counter-test.s`
- `scripts/build-counter-test.ps1`, `scripts/verify-counter-test.ps1`
- `docs/decisions.md`, `docs/architecture.md`, `docs/memory-map.md`
- `tests/runtime/class-test.s`, `tests/parser/unresolved.n8`
- `scripts/build-*.ps1`, `scripts/verify-*.ps1`
- `docs/decisions.md`, `docs/architecture.md`, `docs/memory-map.md`,
`docs/diagnostics.md`


## Acceptance evidence ## Acceptance evidence


- [x] Pass 3 can patch absolute labels/JMP/JSR against a final CODE base:
`counter.n8`'s 175-byte routine runs from `CODE 1C4F`.
- [x] `counter.n8` compiles from source and runs in x128: the generated PRG
reports `total = 15` through the mailbox.
- [x] `sizing.s` measures each routine in count mode so pass 2 and pass 3
produce identical lengths and label offsets; `sz_mismatch` is 0.
- [x] Pass 3 patches absolute `JMP`/`JSR` label fixups; relative branches stay
offset-based. `counter.n8` runs from `CODE 1C4F` with `total = 15`.
- [x] MAP `ENTRY` and `SECTION` records carry final addresses; class records
and `METHOD` entry addresses are emitted and checked by the class fixture.
- [x] Forward references resolve; `tests/parser/unresolved.n8` reports exactly
one `SEM_UNKNOWN_NAME` (E61) and no bad-operand follow-up.
- [x] Recompiling the same source is byte-identical: `COUNTER.PRG` and - [x] Recompiling the same source is byte-identical: `COUNTER.PRG` and
`COUNTB.PRG` compare equal. `COUNTB.PRG` compare equal.
- [x] MAP `ENTRY` and SECTION records carry final addresses for STUB, START,
and CODE.
- [ ] Count-mode sizing for every routine with a zero mismatch counter.
- [ ] MAP class-descriptor and method-entry address records.
- [ ] One diagnostic for an unresolved method/class reference.
- [ ] Reconfirm E202 overwrite refusal in the pass-3 path.

## Coordination notes

- This is intentionally a partial claim; the story is not marked done.
- Existing statement/call fixtures still use `cg_code` as the base, so their
in-place execution behavior is unchanged.
- The counter fixture owns its startup wrapper and frame base, like the
E04-S05 hello fixture. General runtime startup remains open.
- [x] E202 overwrite refusal still holds; the output suite leaves
`COLLIDE.PRG`/`COLLIDE.MAP` unchanged and leaves no output after abort.
- [x] `counter.n8` compiles from source and runs in x128 with `total = 15`.


## Work log ## Work log


- Added `fl_set_base`; absolute fixups now add the selected base instead of
hard-coding `cg_code`.
- Added `em_set_base`/`em_base_set`, applied at `em_reset`.
- Added `sizing.s` to compute `PRG_ENTRY_ADDR + bytes-before-CODE`.
- Added `counter.n8` and a compiler fixture that writes two PRGs and a MAP.
- The first output attempt had `out_load`/`out_entry` zero, producing a 7 KB
padded file; initializing them fixed the container and MAP entry.
- The first run used `$CF80` as a frame while BASIC ROM was mapped; switched
to CR `$0E` with `$BF80`, matching the D129 frame ABI.
- Added `parse_file_base`: ordinary `parse_file` clears the requested base so
existing in-place fixtures never see uninitialized BSS, while the counter
installs its final code base explicitly.
- Made repeated definition of a label at the same offset harmless; this keeps
the forward-call fixture stable across BSS layout changes.
- Counter verification passes with 175 code bytes and `total = 15`.
- `flow.s` now resolves absolute `JMP`/`JSR` operands against `fl_code_base`;
ordinary fixtures keep the default `cg_code` base.
- `sizing.s` computes `PRG_ENTRY_ADDR + bytes-before-CODE` and installs it for
the emitting pass. `sz_capture`/`sz_verify` compare code length, entry
offset, per-routine sizes, and all label offsets.
- `emit.s` records routine sizes in `em_routine_sizes` and selects count mode
through `em_count`. `parse_file` clears count mode, diagnostic suppression,
and any base request; `parse_file_sized` opts into the counted path.
- `diag_suppress` prevents duplicate diagnostics during the emitting pass.
`RES_SIZE_MISMATCH` (E228) reports a count/emit disagreement.
- `output.s`/`formats.inc` add bounded `METHOD name address` MAP records after
class records. The class fixture checks `METHOD DESTROY` and `METHOD STUB`.
- Added the one-reference `unresolved.n8` parser fixture and the matching
`SEM_UNKNOWN_NAME` expectation.


## Completion ## Completion


- Tests run: statements, calls, member, control, scalar, hello, parser, and
counter suites all PASS after the BSS-layout move.
- Results: counter emits 175 bytes; `COUNTER.PRG` and `COUNTB.PRG` are
byte-identical; MAP contains `ENTRY 1C0D`, `START 1C0D 0042`, and
`CODE 1C4F 00AF`; the generated PRG reports `total = 15`.
- Remaining risks: code buffer remains 255 bytes, `em_entry` remains an
offset, and the MAP still lacks method/class address records. No unresolved
reference path or count-mode mismatch ledger exists yet.
- Tests run: statements, calls, member, control, scalar, hello, parser,
counter, output; class test separately. All PASS.
- Parser: 42 fixtures, including `unresolved.n8` with exactly one diagnostic.
- Counter: 175 code bytes; `sz_mismatch = 0`; MAP `ENTRY 1C0D`,
`START 1C0D 0042`, `CODE 1C4F 00AF`; `COUNTER.PRG` and `COUNTB.PRG`
byte-identical; generated PRG reports `total = 15`.
- Class MAP: `CLASS EMPTY`, `CLASS BOX`, `METHOD DESTROY 2A56`,
`METHOD STUB 2A57`; all descriptor/MAP flags pass.
- Remaining risks: the code buffer remains 255 bytes and `em_entry` remains an
offset; general runtime startup and frame sizing remain separate work.

+ 1
- 0
newLang/scripts/build-calls-test.ps1 Vedi File

@@ -22,6 +22,7 @@ $link = Invoke-Nova128Link -Name "calls-test" -BuildDir $out `
(Join-Path $project "src\compiler\codegen.s"), (Join-Path $project "src\compiler\codegen.s"),
(Join-Path $project "src\compiler\flow.s"), (Join-Path $project "src\compiler\flow.s"),
(Join-Path $project "src\compiler\members.s"), (Join-Path $project "src\compiler\members.s"),
(Join-Path $project "src\compiler\sizing.s"),
(Join-Path $project "src\compiler\emit.s"), (Join-Path $project "src\compiler\emit.s"),
(Join-Path $project "src\runtime\startup.s"), (Join-Path $project "src\runtime\startup.s"),
(Join-Path $project "tests\compiler\calls-test.s")) (Join-Path $project "tests\compiler\calls-test.s"))


+ 1
- 0
newLang/scripts/build-hello-test.ps1 Vedi File

@@ -20,6 +20,7 @@ $link = Invoke-Nova128Link -Name "hello-test" -BuildDir $out `
(Join-Path $project "src\compiler\codegen.s"), (Join-Path $project "src\compiler\codegen.s"),
(Join-Path $project "src\compiler\flow.s"), (Join-Path $project "src\compiler\flow.s"),
(Join-Path $project "src\compiler\members.s"), (Join-Path $project "src\compiler\members.s"),
(Join-Path $project "src\compiler\sizing.s"),
(Join-Path $project "src\compiler\emit.s"), (Join-Path $project "src\compiler\emit.s"),
(Join-Path $project "src\compiler\interfaces.s"), (Join-Path $project "src\compiler\interfaces.s"),
(Join-Path $project "src\compiler\types.s"), (Join-Path $project "src\compiler\types.s"),


+ 2
- 0
newLang/scripts/build-parser-test.ps1 Vedi File

@@ -55,6 +55,7 @@ $script:ParserFixtures = [ordered]@{
"toobig.n8" = @("$t\too_big.n8", "rejected", "$t\too_big.expect") "toobig.n8" = @("$t\too_big.n8", "rejected", "$t\too_big.expect")
"interfaces.n8" = @("$t\interfaces.n8", "iface", "$t\interfaces.expect") "interfaces.n8" = @("$t\interfaces.n8", "iface", "$t\interfaces.expect")
"ifacebad.n8" = @("$t\iface_bad.n8", "exact", "$t\iface_bad.expect") "ifacebad.n8" = @("$t\iface_bad.n8", "exact", "$t\iface_bad.expect")
"unresolved.n8" = @("$p\unresolved.n8", "exact", "$p\unresolved.expect")
} }


$link = Invoke-Nova128Link -Name "parser-test" -BuildDir $out ` $link = Invoke-Nova128Link -Name "parser-test" -BuildDir $out `
@@ -69,6 +70,7 @@ $link = Invoke-Nova128Link -Name "parser-test" -BuildDir $out `
(Join-Path $project "src\compiler\codegen.s"), (Join-Path $project "src\compiler\codegen.s"),
(Join-Path $project "src\compiler\flow.s"), (Join-Path $project "src\compiler\flow.s"),
(Join-Path $project "src\compiler\members.s"), (Join-Path $project "src\compiler\members.s"),
(Join-Path $project "src\compiler\sizing.s"),
(Join-Path $project "src\compiler\emit.s"), (Join-Path $project "src\compiler\emit.s"),
(Join-Path $project "src\compiler\interfaces.s"), (Join-Path $project "src\compiler\interfaces.s"),
(Join-Path $project "src\compiler\types.s"), (Join-Path $project "src\compiler\types.s"),


+ 1
- 0
newLang/scripts/build-statements-test.ps1 Vedi File

@@ -22,6 +22,7 @@ $link = Invoke-Nova128Link -Name "statements-test" -BuildDir $out `
(Join-Path $project "src\compiler\codegen.s"), (Join-Path $project "src\compiler\codegen.s"),
(Join-Path $project "src\compiler\flow.s"), (Join-Path $project "src\compiler\flow.s"),
(Join-Path $project "src\compiler\members.s"), (Join-Path $project "src\compiler\members.s"),
(Join-Path $project "src\compiler\sizing.s"),
(Join-Path $project "src\compiler\emit.s"), (Join-Path $project "src\compiler\emit.s"),
(Join-Path $project "src\runtime\startup.s"), (Join-Path $project "src\runtime\startup.s"),
(Join-Path $project "tests\compiler\statements-test.s")) (Join-Path $project "tests\compiler\statements-test.s"))


+ 1
- 0
newLang/scripts/demo-write-check.ps1 Vedi File

@@ -39,6 +39,7 @@ $link = Invoke-Nova128Link -Name "n8check" -BuildDir $out `
(Join-Path $project "src\compiler\names.s"), (Join-Path $project "src\compiler\names.s"),
(Join-Path $project "src\compiler\diagnostics.s"), (Join-Path $project "src\compiler\diagnostics.s"),
(Join-Path $project "src\compiler\parser.s"), (Join-Path $project "src\compiler\parser.s"),
(Join-Path $project "src\compiler\sizing.s"),
(Join-Path $project "src\compiler\interfaces.s"), (Join-Path $project "src\compiler\interfaces.s"),
(Join-Path $project "src\compiler\types.s"), (Join-Path $project "src\compiler\types.s"),
(Join-Path $project "demo\n8check.s")) (Join-Path $project "demo\n8check.s"))


+ 4
- 1
newLang/scripts/verify-class-test.ps1 Vedi File

@@ -53,6 +53,7 @@ $mapPath = Join-Path $out "CLASSTEST.MAP"
Read-DiskFile "classtest.map" $mapPath $true Read-DiskFile "classtest.map" $mapPath $true
$mapLines = ([IO.File]::ReadAllText($mapPath)).TrimEnd("`r", "`n") -split "`r`n|`r|`n" $mapLines = ([IO.File]::ReadAllText($mapPath)).TrimEnd("`r", "`n") -split "`r`n|`r|`n"
$destroy = Get-Nova128Label $labels "destroy_b" $destroy = Get-Nova128Label $labels "destroy_b"
$stub = Get-Nova128Label $labels "method_stub"
$ifdir = Get-Nova128Label $labels "iface_dir" $ifdir = Get-Nova128Label $labels "iface_dir"
$expectedMap = @( $expectedMap = @(
"NOVA128 MAP 1", "NOVA128 MAP 1",
@@ -60,7 +61,9 @@ $expectedMap = @(
"SECTION STUB 1C01 000C", "SECTION STUB 1C01 000C",
"SECTION START 1C0D 004A", "SECTION START 1C0D 004A",
("CLASS EMPTY 0007 0000 00 0000"), ("CLASS EMPTY 0007 0000 00 0000"),
("CLASS BOX 0023 {0:X4} 01 {1:X4}" -f $destroy, $ifdir))
("CLASS BOX 0023 {0:X4} 01 {1:X4}" -f $destroy, $ifdir),
("METHOD DESTROY {0:X4}" -f $destroy),
("METHOD STUB {0:X4}" -f $stub))
if (($mapLines -join "`n") -ne ($expectedMap -join "`n")) { if (($mapLines -join "`n") -ne ($expectedMap -join "`n")) {
$failures += ("CLASSTEST.MAP differs:`n got: " + ($mapLines -join "`n ") + $failures += ("CLASSTEST.MAP differs:`n got: " + ($mapLines -join "`n ") +
"`n want: " + ($expectedMap -join "`n ")) "`n want: " + ($expectedMap -join "`n "))


+ 1
- 0
newLang/scripts/verify-counter-test.ps1 Vedi File

@@ -31,6 +31,7 @@ if ($mb[10] -eq 0) { $failures += "no generated code" }
if ($mb[11] -ne 0) { $failures += "codegen error: $($mb[11])" } if ($mb[11] -ne 0) { $failures += "codegen error: $($mb[11])" }
if ($mb[12] -ne 0) { $failures += "flow error: $($mb[12])" } if ($mb[12] -ne 0) { $failures += "flow error: $($mb[12])" }
if ($mb[13] -ne 0) { $failures += "output error: $($mb[13])" } if ($mb[13] -ne 0) { $failures += "output error: $($mb[13])" }
if ($mb[14] -ne 0) { $failures += "sizing mismatch count: $($mb[14])" }


$c1541 = Get-ViceTool "c1541" $c1541 = Get-ViceTool "c1541"
$prg = Join-Path $out "counter.prg" $prg = Join-Path $out "counter.prg"


+ 1
- 0
newLang/src/common/diagcat.inc Vedi File

@@ -105,3 +105,4 @@
DIAGNOSTIC RES_EXPR_TOO_DEEP, 225, "EXPRESSION NESTED TOO DEEPLY" DIAGNOSTIC RES_EXPR_TOO_DEEP, 225, "EXPRESSION NESTED TOO DEEPLY"
DIAGNOSTIC RES_TOO_MANY_IMPLEMENTS, 226, "MORE THAN 255 IMPLEMENTED INTERFACES" DIAGNOSTIC RES_TOO_MANY_IMPLEMENTS, 226, "MORE THAN 255 IMPLEMENTED INTERFACES"
DIAGNOSTIC RES_EMIT_FAILED, 227, "CANNOT EMIT THIS CODE YET" DIAGNOSTIC RES_EMIT_FAILED, 227, "CANNOT EMIT THIS CODE YET"
DIAGNOSTIC RES_SIZE_MISMATCH, 228, "CODE SIZE CHANGED BETWEEN PASSES"

+ 1
- 0
newLang/src/common/emit.inc Vedi File

@@ -22,6 +22,7 @@ EM_ERR_LABEL = 7 ; no control-flow label available


EM_KIND_LOCAL = 0 EM_KIND_LOCAL = 0
EM_KIND_PARAM = 1 EM_KIND_PARAM = 1
EM_MAX_ROUTINES = 24


EM_LAST_LOCAL = 1 EM_LAST_LOCAL = 1
EM_LAST_SELF = 2 EM_LAST_SELF = 2


+ 3
- 0
newLang/src/common/formats.inc Vedi File

@@ -17,6 +17,8 @@ OUT_SECTION_NAME_MAX = 12
OUT_RECORD_SIZE = 7 ; name ptr(2), name len(1), start(2), size(2) OUT_RECORD_SIZE = 7 ; name ptr(2), name len(1), start(2), size(2)
OUT_MAX_CLASSES = 8 OUT_MAX_CLASSES = 8
OUT_CLASS_RECORD_SIZE = 10 ; name ptr(2), len(1), size(2), destroy(2), count(1), dir(2) OUT_CLASS_RECORD_SIZE = 10 ; name ptr(2), len(1), size(2), destroy(2), count(1), dir(2)
OUT_MAX_METHODS = 16
OUT_METHOD_RECORD_SIZE = 5 ; name ptr(2), len(1), address(2)


; out_begin/out_finish/out_abort result codes (out_err). ; out_begin/out_finish/out_abort result codes (out_err).
OUT_OK = 0 OUT_OK = 0
@@ -27,5 +29,6 @@ OUT_ERR_NAME = 4 ; base or section name too long
OUT_ERR_DISK = 5 ; KERNAL or DOS failure OUT_ERR_DISK = 5 ; KERNAL or DOS failure
OUT_ERR_STATE = 6 ; byte emitted outside a section OUT_ERR_STATE = 6 ; byte emitted outside a section
OUT_ERR_CLASSES = 7 ; more than OUT_MAX_CLASSES OUT_ERR_CLASSES = 7 ; more than OUT_MAX_CLASSES
OUT_ERR_METHODS = 8 ; more than OUT_MAX_METHODS


.endif .endif

+ 10
- 3
newLang/src/compiler/diagnostics.s Vedi File

@@ -27,7 +27,7 @@
.import dio_open_cmd, dio_open_out, dio_read_status, dio_chkout, dio_putc .import dio_open_cmd, dio_open_out, dio_read_status, dio_chkout, dio_putc
.import dio_clrchn, dio_close, dio_command, dio_dos_code .import dio_clrchn, dio_close, dio_command, dio_dos_code


.export diag_init, diag_report, diag_finish
.export diag_init, diag_report, diag_finish, diag_suppress
.export diag_line, diag_col, diag_arg1, diag_arg1_len, diag_arg2, diag_arg2_len .export diag_line, diag_col, diag_arg1, diag_arg1_len, diag_arg2, diag_arg2_len
.export diag_count, diag_limit, diag_screen, diag_file_state, diag_buf .export diag_count, diag_limit, diag_screen, diag_file_state, diag_buf


@@ -59,6 +59,7 @@ diag_init:
lda #$00 lda #$00
sta diag_count sta diag_count
sta diag_stopped sta diag_stopped
sta diag_suppress
sta diag_file_state sta diag_file_state
sta diag_arg1_len sta diag_arg1_len
sta diag_arg2_len sta diag_arg2_len
@@ -149,6 +150,12 @@ append_base_to_open:
rts rts


diag_report: diag_report:
sta diag_code
lda diag_suppress
beq :+
clc
rts
:
ldx diag_stopped ldx diag_stopped
beq :+ beq :+
sec ; already stopped: report nothing more sec ; already stopped: report nothing more
@@ -166,8 +173,7 @@ diag_report:
jsr emit jsr emit
sec sec
rts rts
@count: sta diag_code
inc diag_count
@count: inc diag_count
jsr emit jsr emit
clc clc
rts rts
@@ -537,3 +543,4 @@ hdr_len: .res 1
msg_start: .res 1 msg_start: .res 1
buf_len: .res 1 buf_len: .res 1
diag_buf: .res DIAG_BUF_MAX diag_buf: .res DIAG_BUF_MAX
diag_suppress: .res 1

+ 24
- 1
newLang/src/compiler/emit.s Vedi File

@@ -26,6 +26,7 @@
.include "../common/frames.inc" .include "../common/frames.inc"
.include "../common/emit.inc" .include "../common/emit.inc"
.include "../common/members.inc" .include "../common/members.inc"
.include "../common/flow.inc"


.import cg_init, cg_put, cg_lda_imm, cg_ldx_imm, cg_ldy_imm, cg_lda_zp, cg_lda_zpy, cg_sta_zpy .import cg_init, cg_put, cg_lda_imm, cg_ldx_imm, cg_ldy_imm, cg_lda_zp, cg_lda_zpy, cg_sta_zpy
.import cg_sta_zp, cg_adc_zp, cg_sbc_zp, cg_cmp_zp, cg_adc_imm, cg_clc, cg_sec, cg_jsr_abs, cg_rts .import cg_sta_zp, cg_adc_zp, cg_sbc_zp, cg_cmp_zp, cg_adc_imm, cg_clc, cg_sec, cg_jsr_abs, cg_rts
@@ -37,7 +38,8 @@
.import sc_base, sc_val, sc_len .import sc_base, sc_val, sc_len


.export em_on, em_ctx, em_bad, em_last_kind .export em_on, em_ctx, em_bad, em_last_kind
.export em_reset, em_set_base, em_base_set, em_begin_func, em_begin_params, em_local, em_param
.export em_reset, em_set_base, em_base_set, em_count, em_begin_func, em_begin_params, em_local, em_param
.export em_n_routines, em_routine_sizes, em_routine_start
.export em_expr_name, em_expr_const, em_push_left, em_bin .export em_expr_name, em_expr_const, em_push_left, em_bin
.export em_stmt_begin, em_stmt_end, em_expr_off, em_begin_print .export em_stmt_begin, em_stmt_end, em_expr_off, em_begin_print
.export em_target, em_store_target, em_print, em_end_func .export em_target, em_store_target, em_print, em_end_func
@@ -60,7 +62,13 @@


; Pass 2 start: empty code buffer, no errors, no function, no slots. ; Pass 2 start: empty code buffer, no errors, no function, no slots.
em_reset: em_reset:
lda em_count
beq @emit_mode
lda #FL_MODE_COUNT
jmp @init_flow
@emit_mode:
lda #$00 lda #$00
@init_flow:
jsr fl_init jsr fl_init
lda em_base_set lda em_base_set
beq @base_done beq @base_done
@@ -82,6 +90,7 @@ em_reset:
sta em_locals sta em_locals
sta em_par_bytes sta em_par_bytes
sta em_entry sta em_entry
sta em_n_routines
lda #$FF lda #$FF
sta em_loc_next sta em_loc_next
ldx #$FF ldx #$FF
@@ -104,6 +113,8 @@ em_set_base:
; A body starts: fresh local slots. Parameter offsets were assigned while the ; A body starts: fresh local slots. Parameter offsets were assigned while the
; signature was parsed and are kept. ; signature was parsed and are kept.
em_begin_func: em_begin_func:
lda cg_len
sta em_routine_start
lda #$FF lda #$FF
sta em_loc_next sta em_loc_next
lda #$00 lda #$00
@@ -558,6 +569,14 @@ em_end_func:
beq @done beq @done
jsr cg_rts jsr cg_rts
bcs @fail bcs @fail
ldx em_n_routines
cpx #EM_MAX_ROUTINES
bcs @done
lda cg_len
sec
sbc em_routine_start
sta em_routine_sizes,x
inc em_n_routines
@done: clc @done: clc
rts rts
@fail: jmp em_fail @fail: jmp em_fail
@@ -1142,3 +1161,7 @@ em_meth_label: .res 256
em_entry: .res 1 em_entry: .res 1
em_code_base: .res 2 em_code_base: .res 2
em_base_set: .res 1 em_base_set: .res 1
em_count: .res 1
em_n_routines: .res 1
em_routine_start: .res 1
em_routine_sizes: .res EM_MAX_ROUTINES

+ 134
- 1
newLang/src/compiler/output.s Vedi File

@@ -39,7 +39,7 @@


.export out_begin, out_startup, out_section, out_end_section .export out_begin, out_startup, out_section, out_end_section
.export out_byte, out_bytes, out_finish, out_abort .export out_byte, out_bytes, out_finish, out_abort
.export out_class
.export out_class, out_method, out_method_addr
.export out_class_size, out_class_destroy, out_class_ifaces, out_class_ifdir .export out_class_size, out_class_destroy, out_class_ifaces, out_class_ifdir
.export out_load, out_entry, out_start, out_err .export out_load, out_entry, out_start, out_err


@@ -150,6 +150,24 @@ set_class_ptr:
bne @add bne @add
@done: rts @done: rts


; out_rec_ptr = out_methods + out_index * OUT_METHOD_RECORD_SIZE.
set_method_ptr:
lda #<out_methods
sta out_rec_ptr
lda #>out_methods
sta out_rec_ptr+1
ldx out_index
beq @done
@add: clc
lda out_rec_ptr
adc #OUT_METHOD_RECORD_SIZE
sta out_rec_ptr
bcc :+
inc out_rec_ptr+1
: dex
bne @add
@done: rts

; Build and send "S0:name" on the command channel. ; Build and send "S0:name" on the command channel.
out_scratch: out_scratch:
sta out_scratch_ptr sta out_scratch_ptr
@@ -235,6 +253,7 @@ out_begin:
lda #$00 lda #$00
sta out_count sta out_count
sta out_class_count sta out_class_count
sta out_method_count
sta out_in_section sta out_in_section
sta out_prg_created sta out_prg_created
sta out_map_created sta out_map_created
@@ -611,6 +630,49 @@ out_class:
sec sec
rts rts


; A/X = method name, Y = length. out_method_addr supplies the final address.
out_method:
sta out_tmp
stx out_tmp+1
sty out_tmp_len
lda out_method_count
cmp #OUT_MAX_METHODS
bcs @too_many
lda out_tmp_len
cmp #OUT_SECTION_NAME_MAX + 1
bcs @bad_name
lda out_method_count
sta out_index
jsr set_method_ptr
ldy #0
lda out_tmp
sta (out_rec_ptr),y
iny
lda out_tmp+1
sta (out_rec_ptr),y
iny
lda out_tmp_len
sta (out_rec_ptr),y
iny
lda out_method_addr
sta (out_rec_ptr),y
iny
lda out_method_addr+1
sta (out_rec_ptr),y
inc out_method_count
clc
rts
@too_many:
lda #OUT_ERR_METHODS
sta out_err
sec
rts
@bad_name:
lda #OUT_ERR_NAME
sta out_err
sec
rts

out_finish: out_finish:
jsr out_end_section jsr out_end_section
jsr out_close_prg jsr out_close_prg
@@ -812,6 +874,8 @@ out_write_map:
inc out_index inc out_index
jmp @section jmp @section
@done: jsr out_write_classes @done: jsr out_write_classes
bcs @out
jsr out_write_methods
bcs @out bcs @out
clc clc
@out: rts @out: rts
@@ -921,6 +985,70 @@ out_write_classes:
@done: clc @done: clc
@out: rts @out: rts


; Write METHOD records after the CLASS records, in out_method call order.
out_write_methods:
lda #$00
sta out_index
@method:
lda out_index
cmp out_method_count
bne @body
jmp @done
@body:
jsr set_method_ptr
lda #<method_prefix
ldx #>method_prefix
ldy #method_prefix_len
jsr out_text
bcc @prefix_ok
jmp @out
@prefix_ok:
ldy #0
lda (out_rec_ptr),y
sta out_srcp
iny
lda (out_rec_ptr),y
sta out_srcp+1
iny
lda (out_rec_ptr),y
sta out_text_len
ldy #0
@name: cpy out_text_len
beq @named
lda (out_srcp),y
sty out_y
jsr out_char
bcc @name_ok
jmp @out
@name_ok:
ldy out_y
iny
bne @name
@named:
lda #' '
jsr out_char
bcc @space_ok
jmp @out
@space_ok:
ldy #3
lda (out_rec_ptr),y
sta out_num
iny
lda (out_rec_ptr),y
sta out_num+1
jsr out_hex4
bcc @addr_ok
jmp @out
@addr_ok:
jsr out_cr
bcc @line_ok
jmp @out
@line_ok:
inc out_index
jmp @method
@done: clc
@out: rts

; A/X = text, Y = length. ; A/X = text, Y = length.
out_text: out_text:
sta out_srcp sta out_srcp
@@ -1002,6 +1130,8 @@ section_prefix: .byte "SECTION "
section_prefix_len = * - section_prefix section_prefix_len = * - section_prefix
class_prefix: .byte "CLASS " class_prefix: .byte "CLASS "
class_prefix_len = * - class_prefix class_prefix_len = * - class_prefix
method_prefix: .byte "METHOD "
method_prefix_len = * - method_prefix
hex_digits: .byte "0123456789ABCDEF" hex_digits: .byte "0123456789ABCDEF"


.segment "BSS" .segment "BSS"
@@ -1039,6 +1169,9 @@ out_map_is_open: .res 1
out_err: .res 1 out_err: .res 1
out_sections: .res OUT_MAX_SECTIONS * OUT_RECORD_SIZE out_sections: .res OUT_MAX_SECTIONS * OUT_RECORD_SIZE
out_classes: .res OUT_MAX_CLASSES * OUT_CLASS_RECORD_SIZE out_classes: .res OUT_MAX_CLASSES * OUT_CLASS_RECORD_SIZE
out_methods: .res OUT_MAX_METHODS * OUT_METHOD_RECORD_SIZE
out_method_count: .res 1
out_method_addr: .res 2
out_class_size: .res 2 out_class_size: .res 2
out_class_destroy: .res 2 out_class_destroy: .res 2
out_class_ifaces: .res 1 out_class_ifaces: .res 1


+ 44
- 3
newLang/src/compiler/parser.s Vedi File

@@ -47,7 +47,7 @@
.import src_line .import src_line
.import name_intern, name_find, name_declare .import name_intern, name_find, name_declare
.import names_count .import names_count
.import diag_report, diag_line, diag_col, diag_arg1, diag_arg1_len
.import diag_report, diag_line, diag_col, diag_arg1, diag_arg1_len, diag_suppress, diag_count
.import mmu_peek1, mmu_poke1 .import mmu_peek1, mmu_poke1
.importzp mmu_ptr .importzp mmu_ptr
.import diag_arg2_len .import diag_arg2_len
@@ -56,7 +56,7 @@
.import ty_assign, ty_binary, ty_unary .import ty_assign, ty_binary, ty_unary
.import ty_arg_sc1, ty_arg_sc2, ty_arg_name1, ty_arg_num2 .import ty_arg_sc1, ty_arg_sc2, ty_arg_name1, ty_arg_num2
.import assign_slots, check_interfaces .import assign_slots, check_interfaces
.import em_reset, em_set_base, em_base_set, em_on, em_ctx, em_bad, em_last_kind
.import em_reset, em_set_base, em_base_set, em_count, em_on, em_ctx, em_bad, em_last_kind
.import em_begin_func, em_begin_params, em_local, em_param .import em_begin_func, em_begin_params, em_local, em_param
.import em_stmt_begin, em_stmt_end, em_expr_off, em_begin_print .import em_stmt_begin, em_stmt_end, em_expr_off, em_begin_print
.import em_expr_name, em_expr_const, em_push_left, em_bin .import em_expr_name, em_expr_const, em_push_left, em_bin
@@ -65,8 +65,9 @@
.import em_open_block, em_cond_false, em_else, em_close_block .import em_open_block, em_cond_false, em_else, em_close_block
.import em_for_var, em_for_save_end, em_for_save_step, em_for_default_step, em_for_setup .import em_for_var, em_for_save_end, em_for_save_step, em_for_default_step, em_for_setup
.import em_return, em_method_begin, em_program_begin .import em_return, em_method_begin, em_program_begin
.import sz_capture, sz_verify


.export parse_file, parse_file_base, tb_get, tb_set, mem_count, par_count
.export parse_file, parse_file_base, parse_file_sized, tb_get, tb_set, mem_count, par_count
.export gen_text, gen_text_len, gen_print_count, gen_bad .export gen_text, gen_text_len, gen_print_count, gen_bad
.export ex_trace_on, ex_min_sp .export ex_trace_on, ex_min_sp
.exportzp ex_tp .exportzp ex_tp
@@ -97,12 +98,26 @@ ex_tp: .res 2 ; test trace pointer (ex_trace_on)
parse_file: parse_file:
lda #$00 lda #$00
sta em_base_set sta em_base_set
sta em_count
sta diag_suppress
jmp parse_start jmp parse_start


; A/X = final code base for pass-3 absolute fixups. Clears any pending base ; A/X = final code base for pass-3 absolute fixups. Clears any pending base
; before installing this one, so BSS garbage cannot affect ordinary fixtures. ; before installing this one, so BSS garbage cannot affect ordinary fixtures.
parse_file_base: parse_file_base:
jsr em_set_base jsr em_set_base
lda #$00
sta em_count
sta diag_suppress
jmp parse_start

; Count pass, snapshot, then an emitting pass. The caller installs the final
; code base first. Diagnostics are reported only by the count pass.
parse_file_sized:
lda #$01
sta em_count
lda #$00
sta diag_suppress
parse_start: parse_start:
tsx tsx
stx parse_sp stx parse_sp
@@ -137,7 +152,33 @@ parse_start:
beq :+ beq :+
lda #E_RES_EMIT_FAILED lda #E_RES_EMIT_FAILED
jsr err2 jsr err2
rts
:
lda em_count
beq @done
lda diag_count
bne @done
jsr sz_capture
lda #$00
sta em_count
lda #$01
sta diag_suppress
jsr em_reset
jsr parse_pass
jsr em_finish
lda #$00
sta diag_suppress
lda em_bad
beq :+
lda #E_RES_EMIT_FAILED
jsr err2
rts
: :
jsr sz_verify
bcc @done
lda #E_RES_SIZE_MISMATCH
jsr diag_report
@done:
rts rts


; Error limit reached: return straight to parse_file's caller. ; Error limit reached: return straight to parse_file's caller.


+ 120
- 2
newLang/src/compiler/sizing.s Vedi File

@@ -7,10 +7,14 @@


.setcpu "6502" .setcpu "6502"
.include "../common/formats.inc" .include "../common/formats.inc"
.include "../common/flow.inc"
.include "../common/emit.inc"


.import em_set_base
.import em_set_base, em_entry, em_n_routines, em_routine_sizes
.import cg_len, fl_get_label, fl_err


.export sz_plan_code, sz_code_base .export sz_plan_code, sz_code_base
.export sz_capture, sz_verify, sz_mismatch


.segment "CODE" .segment "CODE"


@@ -27,5 +31,119 @@ sz_plan_code:
ldx sz_code_base+1 ldx sz_code_base+1
jmp em_set_base jmp em_set_base


; Snapshot the count-mode pass before the emitting pass resets the buffer.
sz_capture:
lda #$00
sta fl_err
lda cg_len
sta sz_len
lda em_entry
sta sz_entry
lda em_n_routines
sta sz_nr
ldx #$00
@routine:
cpx sz_nr
beq @labels
lda em_routine_sizes,x
sta sz_sizes,x
inx
bne @routine
@labels:
lda #$00
sta sz_i
@label:
lda sz_i
cmp #FL_LABELS
beq @done
jsr fl_get_label
bcs @undefined
txa
ldy sz_i
sta sz_labels,y
jmp @next
@undefined:
ldy sz_i
lda #$FF
sta sz_labels,y
@next: inc sz_i
jmp @label
@done: rts

; Compare the count-mode snapshot with the emitting pass. Every difference
; increments sz_mismatch; C=1 when anything differs.
sz_verify:
lda #$00
sta sz_mismatch
sta fl_err
lda cg_len
cmp sz_len
beq @entry
inc sz_mismatch
@entry:
lda em_entry
cmp sz_entry
beq @count
inc sz_mismatch
@count:
lda em_n_routines
cmp sz_nr
beq @routines
inc sz_mismatch
@routines:
ldx #$00
@routine:
cpx sz_nr
beq @labels
lda em_routine_sizes,x
cmp sz_sizes,x
beq @next_routine
inc sz_mismatch
@next_routine:
inx
bne @routine
@labels:
lda #$00
sta sz_i
@label:
lda sz_i
cmp #FL_LABELS
beq @done
jsr fl_get_label
bcs @undefined
txa
sta sz_off
ldy sz_i
lda sz_labels,y
cmp sz_off
beq @next
inc sz_mismatch
jmp @next
@undefined:
ldy sz_i
lda sz_labels,y
cmp #$FF
beq @next
inc sz_mismatch
@next: inc sz_i
jmp @label
@done:
lda #$00
sta fl_err
lda sz_mismatch
beq @ok
sec
rts
@ok: clc
rts

.segment "BSS" .segment "BSS"
sz_code_base: .res 2
sz_code_base: .res 2
sz_len: .res 1
sz_entry: .res 1
sz_nr: .res 1
sz_i: .res 1
sz_off: .res 1
sz_mismatch: .res 1
sz_sizes: .res EM_MAX_ROUTINES
sz_labels: .res FL_LABELS

+ 4
- 7
newLang/tests/compiler/counter-test.s Vedi File

@@ -13,11 +13,12 @@
.import src_load, src_dos_code, src_kernal_err .import src_load, src_dos_code, src_kernal_err
.import names_init .import names_init
.import diag_init, diag_finish, diag_screen .import diag_init, diag_finish, diag_screen
.import parse_file_base
.import parse_file_sized
.import em_on, em_bad .import em_on, em_bad
.import cg_code, cg_len, cg_err .import cg_code, cg_len, cg_err
.import fl_err .import fl_err
.import sz_plan_code, sz_code_base .import sz_plan_code, sz_code_base
.import sz_mismatch
.import out_begin, out_section, out_end_section, out_byte, out_bytes .import out_begin, out_section, out_end_section, out_byte, out_bytes
.import out_finish, out_abort, out_load, out_entry, out_start, out_err .import out_finish, out_abort, out_load, out_entry, out_start, out_err
.import gen_stub .import gen_stub
@@ -101,9 +102,7 @@ test_entry:
lda #WRAPPER_LEN lda #WRAPPER_LEN
jsr sz_plan_code ; final code base for absolute fixups jsr sz_plan_code ; final code base for absolute fixups


lda sz_code_base
ldx sz_code_base+1
jsr parse_file_base
jsr parse_file_sized
jsr diag_finish jsr diag_finish
sta diag_count sta diag_count
lda diag_count lda diag_count
@@ -116,10 +115,8 @@ test_entry:
sta MB_DATA+3 sta MB_DATA+3
lda fl_err lda fl_err
sta MB_DATA+4 sta MB_DATA+4
lda sz_code_base
lda sz_mismatch
sta MB_DATA+6 sta MB_DATA+6
lda sz_code_base+1
sta MB_DATA+7


lda diag_count lda diag_count
ON_NONZERO fail_diag ON_NONZERO fail_diag


+ 2
- 1
newLang/tests/parser/parser-test.s Vedi File

@@ -577,7 +577,8 @@ fixtures:
FIXTURE "TOOBIG.N8" FIXTURE "TOOBIG.N8"
FIXTURE "INTERFACES.N8" FIXTURE "INTERFACES.N8"
FIXTURE "IFACEBAD.N8" FIXTURE "IFACEBAD.N8"
FIXTURE_COUNT = 41
FIXTURE "UNRESOLVED.N8"
FIXTURE_COUNT = 42
TRACE_INDEX = 28 ; PREC.N8 TRACE_INDEX = 28 ; PREC.N8


messages: messages:


+ 3
- 0
newLang/tests/parser/unresolved.expect Vedi File

@@ -0,0 +1,3 @@
// One unresolved method reference; it must be reported once, not emitted as a
// bad operand or a second error.
SEM_UNKNOWN_NAME 3 10

+ 9
- 0
newLang/tests/parser/unresolved.n8 Vedi File

@@ -0,0 +1,9 @@
class Box
public method run()
self.missing()
end method
end class

program Main
var b as Box
end program

+ 32
- 4
newLang/tests/runtime/class-test.s Vedi File

@@ -16,10 +16,11 @@
.import out_begin, out_startup, out_finish, out_abort .import out_begin, out_startup, out_finish, out_abort
.import out_load, out_entry, out_err .import out_load, out_entry, out_err
.import out_class, out_class_size, out_class_destroy .import out_class, out_class_size, out_class_destroy
.import out_method, out_method_addr
.import out_class_ifaces, out_class_ifdir .import out_class_ifaces, out_class_ifdir
.import obj_class, obj_size, obj_destroy, obj_iface_dir .import obj_class, obj_size, obj_destroy, obj_iface_dir


.export destroy_b, iface_dir
.export destroy_b, iface_dir, method_stub


.segment "LOADADDR" .segment "LOADADDR"
.word $1C01 .word $1C01
@@ -197,9 +198,12 @@ test_entry:
ldx #>name_source ldx #>name_source
ldy #name_source_len ldy #name_source_len
jsr out_begin jsr out_begin
bcs @p7_abort
jsr out_startup
bcs @p7_abort
bcc :+
jmp @p7_abort
: jsr out_startup
bcc :+
jmp @p7_abort
:


lda #7 ; EMPTY: size 7, no destructor/interface lda #7 ; EMPTY: size 7, no destructor/interface
sta out_class_size sta out_class_size
@@ -236,6 +240,26 @@ test_entry:
jsr out_class jsr out_class
bcs @p7_abort bcs @p7_abort


lda #<destroy_b
sta out_method_addr
lda #>destroy_b
sta out_method_addr+1
lda #<name_destroy
ldx #>name_destroy
ldy #name_destroy_len
jsr out_method
bcs @p7_abort

lda #<method_stub
sta out_method_addr
lda #>method_stub
sta out_method_addr+1
lda #<name_stub
ldx #>name_stub
ldy #name_stub_len
jsr out_method
bcs @p7_abort

jsr out_finish jsr out_finish
bcs @p7_fail bcs @p7_fail
lda #$01 lda #$01
@@ -331,6 +355,10 @@ name_empty: .byte "EMPTY"
name_empty_len = * - name_empty name_empty_len = * - name_empty
name_box: .byte "BOX" name_box: .byte "BOX"
name_box_len = * - name_box name_box_len = * - name_box
name_destroy: .byte "DESTROY"
name_destroy_len = * - name_destroy
name_stub: .byte "STUB"
name_stub_len = * - name_stub
messages: messages:
ok_message: .byte "NOVA128 CLASS TEST OK", $0D, $00 ok_message: .byte "NOVA128 CLASS TEST OK", $0D, $00
fail_message: .byte "NOVA128 CLASS TEST FAIL", $0D, $00 fail_message: .byte "NOVA128 CLASS TEST FAIL", $0D, $00


Loading…
Annulla
Salva

Powered by TurnKey Linux.