Kaynağa Gözat

newLang: add the write-and-check demo

scripts/demo-write-check.ps1 types each demo program into the Vim clone
on x64sc (fresh copy of vim/work.d81), confirms the saved SEQ file matches
its ASCII mirror, then runs demo/n8check.s on x128: a DEMO driver (not
N128C) that asks for a file name and runs the current front end (source
reader, lexer, names, parser) with on-screen diagnostics and NAME.ERR.
good.n8 checks clean; bad.n8 reports its four intended errors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main
Daniel Covington 6 gün önce
ebeveyn
işleme
bdb3987305
5 değiştirilmiş dosya ile 446 ekleme ve 0 silme
  1. +26
    -0
      newLang/demo/README.md
  2. +15
    -0
      newLang/demo/bad.n8
  3. +22
    -0
      newLang/demo/good.n8
  4. +248
    -0
      newLang/demo/n8check.s
  5. +135
    -0
      newLang/scripts/demo-write-check.ps1

+ 26
- 0
newLang/demo/README.md Dosyayı Görüntüle

@@ -0,0 +1,26 @@
# Write-and-check demo

Shows the Nova128 workflow as far as it exists today: a program is typed
into the Vim clone on the C64, saved to disk, and checked on the C128 by
the compiler front end. No code is generated yet (epic E04), so nothing
runs.

```powershell
pwsh -File scripts/demo-write-check.ps1 # good.n8 and bad.n8
pwsh -File scripts/demo-write-check.ps1 -Programs bad.n8
```

| File | Purpose |
|---|---|
| `good.n8` | Valid program: interface, class with private field, `init`, interface call |
| `bad.n8` | Four errors: `init` with a result, `destroy` with a parameter, private field used from the program, undeclared name |
| `n8check.s` | DEMO driver (not `N128C`): asks for a file name, runs source reader, lexer, names, and parser, shows diagnostics, writes `NAME.ERR` |

The script works on `build/demo/demo.d81`, a fresh copy of `vim/work.d81`
(the original is never written). x64sc and x128 run one after the other,
never together. Demo sources must be lowercase with no quotes or
backslashes, because they are typed through VICE's `-keybuf`.

Outputs in `build/demo/`: `NAME-vim.png` (the editor after `:w`),
`NAME-check.png` (the C128 screen), `NAME.seq` (the file Vim wrote), and
`NAME.err.txt` (the error file, when there are errors).

+ 15
- 0
newLang/demo/bad.n8 Dosyayı Görüntüle

@@ -0,0 +1,15 @@
class square
private word side
public method init(s as word) as word
self.side = s
end method
public method destroy(x as byte)
end method
end class

program main
var sq as square
sq = new square(4)
print sq.side
print total
end program

+ 22
- 0
newLang/demo/good.n8 Dosyayı Görüntüle

@@ -0,0 +1,22 @@
interface shape
method area() as word
end interface

class square implements shape
private word side
public method init(s as word)
self.side = s
end method
public method area() as word
return self.side * self.side
end method
end class

program main
var sq as square
var s as shape
sq = new square(4)
s = sq
print s.area()
delete s
end program

+ 248
- 0
newLang/demo/n8check.s Dosyayı Görüntüle

@@ -0,0 +1,248 @@
; n8check.s - DEMO driver: check one Nova128 source file on the C128.
;
; This is not the Nova128 compiler (N128C, still to come). It runs the
; front end that exists today - source reader, lexer, name table, and the
; declaration/member/scope parser (E02, E03-S01, E03-S02) - on a file named
; at the prompt, shows any diagnostics on screen, and writes NAME.ERR. It
; generates no code: the code generator is epic E04.
;
; Mailbox: producer $02, status PASS (no errors) or FAIL, code = errors.

.setcpu "6502"
.include "../src/common/c128.inc"
.include "../src/common/mailbox.inc"
.include "../src/common/source.inc"
.include "../src/common/errors.inc"

.import mmu_init, mmu_bank0, mmu_shutdown, kcall_inline
.import src_load, src_err_line, src_err_col, src_dos_code
.import names_init
.import diag_init, diag_report, diag_finish, diag_line, diag_col
.import diag_arg1, diag_arg1_len
.import parse_file

NAME_MAX = 16

.segment "LOADADDR"
.word $1C01

.segment "EXEHDR"
.word basic_end
.word 10
.byte $9E
.byte "7181"
.byte $00
basic_end:
.word $0000

.segment "MAILBOX"
.res MB_SIZE

.segment "STARTUP"
entry:
php
sei
ldx #MB_SIZE - 1
lda #$00
@clr: sta MB_BASE,x
dex
bpl @clr
lda #MB_MAGIC0_VALUE
sta MB_MAGIC0
lda #MB_MAGIC1_VALUE
sta MB_MAGIC1
lda #MB_PROD_COMPILER
sta MB_PRODUCER
lda #MB_ST_RUNNING
sta MB_STATUS
jsr mmu_init
jsr mmu_bank0
jsr main
jsr mmu_shutdown
plp
rts

.segment "CODE"
main: ldx #msg_title - msgs
jsr print
ldx #msg_prompt - msgs
jsr print
jsr read_name
lda name_len
bne :+
rts ; empty name: nothing to do
: ldx #msg_checking - msgs
jsr print

jsr names_init
lda #<name_buf
ldx #>name_buf
ldy name_len
jsr diag_init ; scratches a stale NAME.ERR
lda #<name_buf
ldx #>name_buf
ldy name_len
jsr src_load
bcc @parse
jsr report_load ; A = SRC_ERR_*
jmp @done
@parse: jsr parse_file
@done: jsr diag_finish ; A = errors reported
sta errors
sta MB_CODE
cmp #$00
bne @bad
ldx #msg_ok - msgs
jsr print
lda #MB_ST_PASS
sta MB_STATUS
rts
@bad: lda errors
jsr print_dec
ldx #msg_errors - msgs
jsr print
ldx #$00 ; base name, then .ERR
@base: cpx base_len
beq :+
lda name_buf,x
stx save_x
jsr chrout
ldx save_x
inx
bne @base
: ldx #msg_errfile - msgs
jsr print
lda #MB_ST_FAIL
sta MB_STATUS
rts

; Map a source-reader failure (A = SRC_ERR_*) to its diagnostic.
report_load:
cmp #SRC_ERR_DISK
bne @limit
lda src_dos_code ; "DOS nn"
ldx #$00
@tens: cmp #10
bcc :+
sbc #10
inx
bne @tens
: ora #'0'
sta dos_text+1
txa
ora #'0'
sta dos_text
lda #<dos_text
sta diag_arg1
lda #>dos_text
sta diag_arg1+1
lda #2
sta diag_arg1_len
lda #$00
sta diag_line
sta diag_line+1
sta diag_col
lda #E_DSK_SOURCE_UNREADABLE
jmp diag_report
@limit: tax ; 2/3/4 -> E002/E001/E003
lda load_codes-2,x
pha
lda src_err_line
sta diag_line
lda src_err_line+1
sta diag_line+1
lda src_err_col
sta diag_col
pla
jmp diag_report

; Read a line from the keyboard into name_buf (screen editor input).
read_name:
lda #$00
sta name_len
@key: jsr kcall_inline
.word CHRIN
cmp #$0D
beq @end
ldx name_len
cpx #NAME_MAX
bcs @key
sta name_buf,x
inc name_len
bne @key
@end: lda #$0D
jsr chrout
lda name_len ; base_len = length without ".N8"
sta base_len
cmp #3
bcc @out
tax
lda name_buf-3,x
cmp #'.'
bne @out
lda name_buf-2,x
and #$7F
cmp #'N'
bne @out
lda name_buf-1,x
cmp #'8'
bne @out
dex
dex
dex
stx base_len
@out: rts

; Print the $00-terminated message at msgs+X.
print: lda msgs,x
beq @done
stx save_x
jsr chrout
ldx save_x
inx
bne print
@done: rts

; Print A (0-99) in decimal; at most 21 errors are ever reported.
print_dec:
ldx #$00
@t: cmp #10
bcc @units
sbc #10
inx
bne @t
@units: pha
txa
beq :+
ora #'0'
jsr chrout
: pla
ora #'0'
jmp chrout

chrout: jsr kcall_inline
.word CHROUT
rts

.segment "RODATA"
load_codes:
.byte E_SRC_FILE_TOO_LARGE, E_SRC_LINE_TOO_LONG, E_SRC_TOO_MANY_LINES
msgs:
msg_title: .byte $0D, "NOVA128 CHECK (DEMO: FRONT END ONLY)", $0D, $00
msg_prompt: .byte "SOURCE FILE?", $0D, $00
msg_checking: .byte "CHECKING...", $0D, $00
msg_ok: .byte "NO ERRORS: DECLARATIONS, MEMBERS,", $0D
.byte "SCOPES AND ACCESS ARE VALID.", $0D
.byte "(NO CODE YET - CODE GENERATION IS E04)", $0D, $00
msg_errors: .byte " ERROR(S); LIST IN ", $00
msg_errfile: .byte ".ERR", $0D, $00

.segment "BSS"
name_buf: .res NAME_MAX
name_len: .res 1
base_len: .res 1
errors: .res 1
save_x: .res 1

.segment "DATA"
dos_text: .byte "00"

+ 135
- 0
newLang/scripts/demo-write-check.ps1 Dosyayı Görüntüle

@@ -0,0 +1,135 @@
# DEMO: write a Nova128 program in the Vim clone (x64sc, C64 mode), then check
# it on the C128 (x128) with the compiler front end as it exists today.
#
# pwsh -File scripts/demo-write-check.ps1 (good.n8 and bad.n8)
# pwsh -File scripts/demo-write-check.ps1 -Programs good.n8
#
# For each demo/<name>.n8 (an ASCII mirror):
# 1. x64sc autostarts VIM from a fresh copy of vim/work.d81 and the program
# is TYPED into it through the keyboard buffer: file name, `y` to create,
# `i`, the text, RUN/STOP, `:w`. Vim writes the PETSCII SEQ file and
# stays on screen for the exit screenshot.
# 2. The SEQ file is read back with c1541 and compared with the mirror.
# 3. x128 autostarts N8CHECK from the same disk (after x64sc has exited),
# the file name is typed at its prompt, and it parses the file.
# 4. The screen and NAME.ERR, if any, are shown.
# Screenshots go to build/demo/. No code is generated yet (epic E04).
[CmdletBinding()]
param([string[]]$Programs = @("good.n8", "bad.n8"), [int]$KeyDelay = 120)

$ErrorActionPreference = "Stop"
$project = Split-Path $PSScriptRoot -Parent
$repository = Split-Path $project -Parent
Import-Module (Join-Path $PSScriptRoot "lib\Nova128Test.psm1") -Force
$out = Join-Path $project "build\demo"
New-Item -ItemType Directory -Force -Path $out | Out-Null
$c1541 = Get-ViceTool "c1541"
$x64 = Get-ViceTool "x64sc"
$x128 = Get-ViceTool "x128"

# ------------------------------------------------------------- build
$link = Invoke-Nova128Link -Name "n8check" -BuildDir $out `
-Config (Join-Path $project "cfg\compiler.cfg") -Sources @(
(Join-Path $project "src\compiler\mmu.s"),
(Join-Path $project "src\compiler\diskio.s"),
(Join-Path $project "src\compiler\source.s"),
(Join-Path $project "src\compiler\lexer.s"),
(Join-Path $project "src\compiler\names.s"),
(Join-Path $project "src\compiler\diagnostics.s"),
(Join-Path $project "src\compiler\parser.s"),
(Join-Path $project "demo\n8check.s"))

# A fresh copy: the Vim work disk itself is never written.
$disk = Join-Path $out "demo.d81"
if (Test-Path $disk) { Remove-Item $disk -Force }
Copy-Item (Join-Path $repository "vim\work.d81") $disk
& $c1541 $disk -write $link.Program "n8check" 2>&1 | Out-Null
foreach ($p in $Programs) { # stale copies, if any
& $c1541 $disk -delete $p ($p -replace '\.n8$', '.err') 2>&1 | Out-Null
}

function Quote-Arg([string]$a) {
if ($a -ne "" -and $a -notmatch '[\s"]') { return $a }
$e = $a -replace '(\\*)"', '$1$1\"'
$e = $e -replace '(\\+)$', '$1$1'
return '"' + $e + '"'
}
# One emulator at a time, run from build/demo so "demo.d81:prog" has no drive
# letter colon, and waited for so nothing else touches the image.
function Invoke-Vice([string]$exe, [string[]]$argv) {
$psi = [Diagnostics.ProcessStartInfo]::new()
$psi.FileName = $exe
$psi.WorkingDirectory = $out
$psi.Arguments = ($argv | ForEach-Object { Quote-Arg $_ }) -join ' '
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true # VICE's log is noise here
$psi.RedirectStandardError = $true
$proc = [Diagnostics.Process]::Start($psi)
$stdout = $proc.StandardOutput.ReadToEndAsync()
$stderr = $proc.StandardError.ReadToEndAsync()
$proc.WaitForExit()
[void]$stdout.Result; [void]$stderr.Result
Start-Sleep -Milliseconds 900 # let the image write settle
}
function Get-Cycles([int]$keys, [int]$extraSeconds) {
$wall = $keys * $KeyDelay / 1000.0 + $extraSeconds
return [long][Math]::Min([Math]::Max($wall * 13000000, 150000000), 2000000000)
}
function ConvertFrom-PetsciiText([byte[]]$bytes) {
return -join ($bytes | ForEach-Object {
if ($_ -eq 13) { "`n" }
elseif ($_ -ge 0x41 -and $_ -le 0x5A) { [char]($_ + 0x20) }
elseif ($_ -ge 0xC1 -and $_ -le 0xDA) { [char]($_ - 0x80) }
else { [char]$_ } })
}

foreach ($name in $Programs) {
$base = $name -replace '\.n8$', ''
$mirror = (Get-Content -Raw (Join-Path $project "demo\$name")) -replace "`r", ""
$text = $mirror.TrimEnd("`n")
if ($text -cmatch '[A-Z"\\]') { throw "$name must be lowercase without quotes or backslashes (typed via -keybuf)" }
Write-Host ""
Write-Host "=== $name"

# 1. type it into Vim on the C64
$keys = "$name\n" + "y" + "i" + ($text -replace "`n", "\n") + "\x03" + ":w\n"
$shot = Join-Path $out "$base-vim.png"
if (Test-Path $shot) { Remove-Item $shot -Force }
Write-Host " x64sc: typing $($text.Length) characters into VIM..."
Invoke-Vice $x64 @("-drive8type", "1581", "-8", "demo.d81", "-autostart", "demo.d81:vim",
"-autostart-warp", "-warp", "-sounddev", "dummy",
"-keybuf-delay", "$KeyDelay", "-keybuf", $keys,
"-limitcycles", "$(Get-Cycles $keys.Length 25)", "-exitscreenshot", $shot)

# 2. read back what Vim wrote
$seq = Join-Path $out "$base.seq"
if (Test-Path $seq) { Remove-Item $seq -Force }
& $c1541 $disk -read "$name,s" $seq 2>&1 | Out-Null
if (-not (Test-Path $seq)) { throw "VIM did not write $name (see $shot)" }
$saved = (ConvertFrom-PetsciiText ([IO.File]::ReadAllBytes($seq))).TrimEnd("`n")
if ($saved -ne $text) { throw "$name on disk differs from demo\$name (see $shot)" }
Write-Host " VIM saved $name as a SEQ file: $(([IO.File]::ReadAllBytes($seq)).Length) PETSCII bytes, identical to the mirror"

# 3. check it on the C128
$shot128 = Join-Path $out "$base-check.png"
if (Test-Path $shot128) { Remove-Item $shot128 -Force }
Write-Host " x128: N8CHECK $name ..."
Invoke-Vice $x128 @("-drive8type", "1581", "-8", "demo.d81", "-autostart", "demo.d81:n8check",
"-autostart-warp", "-warp", "-sounddev", "dummy",
"-keybuf-delay", "$KeyDelay", "-keybuf", "$name\n",
"-limitcycles", "$(Get-Cycles 10 40)", "-exitscreenshotvicii", $shot128)

# 4. results
$err = Join-Path $out "$base.err.txt"
if (Test-Path $err) { Remove-Item $err -Force }
& $c1541 $disk -read "$base.err,s" $err 2>&1 | Out-Null
if (Test-Path $err) {
Write-Host " $base.err:"
foreach ($line in ([Text.Encoding]::ASCII.GetString([IO.File]::ReadAllBytes($err)).TrimEnd("`r") -split "`r")) {
Write-Host " $line"
}
} else {
Write-Host " no $base.err: the program has no errors"
}
Write-Host " screenshots: $shot, $shot128"
}

Yükleniyor…
İptal
Kaydet

Powered by TurnKey Linux.