Compare commits
2 Commits
86e9b0802f
...
feature/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
eb93bb7da0
|
|||
|
1e514f679b
|
@@ -685,9 +685,9 @@ seconds asks for fifty frames a second.
|
||||
### Why `GOTO` rather than `DO ... LOOP`
|
||||
|
||||
A `DO ... LOOP` around the frame would read better, and it is not usable here: **a `GOTO`
|
||||
that jumps out of a `FOR` or a `DO` does not release the loop's scope.** There are 32
|
||||
that jumps out of a `FOR` or a `DO` does not release the loop's scope.** There are 12
|
||||
scopes, so a game that leaves its main loop once per lost life stops on the
|
||||
thirty-second one:
|
||||
twelfth one:
|
||||
|
||||
```basic
|
||||
N# = 0
|
||||
@@ -700,7 +700,7 @@ PRINT "SURVIVED " + N#
|
||||
```
|
||||
|
||||
```output
|
||||
? 3 : PARSE ERROR Environment pool exhausted at line 3 (32 in use)
|
||||
? 3 : PARSE ERROR Environment pool exhausted at line 3 (12 in use)
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -1423,7 +1423,8 @@ IF STATE# = 2 THEN GOSUB UNSTICK
|
||||
RETURN
|
||||
|
||||
LABEL PRESSPAUSE
|
||||
IF STATE# = 2 THEN STATE# = 6 : GMTYP# = 0 : BAN$ = "PAUSED" : GOSUB SETBANNER : RETURN
|
||||
IF STATE# = 2 THEN STATE# = 6 : GMTYP# = 0 : BAN$ = "PAUSED"
|
||||
IF STATE# = 6 THEN GOSUB SETBANNER : RETURN
|
||||
IF STATE# = 6 THEN STATE# = 2 : BAN$ = "" : GOSUB SETBANNER
|
||||
RETURN
|
||||
```
|
||||
|
||||
@@ -56,7 +56,10 @@ This is a tour of the interpreter's edges, on purpose:
|
||||
counterpoint: a genuine 24x21 `SPRSAV` type-in sprite, 63 bytes, which is
|
||||
everything `DATA` has room to say. The paint is the reveal, and the exit is a
|
||||
stride-63 column dissolve — 63 is coprime to 160, so the walk hits every
|
||||
column once and looks random while carrying no state.
|
||||
column once and looks random while carrying no state. The strings come in
|
||||
64-character chunks because a source line is 80 columns, like the machines
|
||||
this pretends to be — the decoder carries its cursor from one `IM$` entry to
|
||||
the next, and the generator refuses to cut inside a run.
|
||||
- **And then the picture is video.** Six delta frames loop the floor grid toward
|
||||
you and crawl the sun's slice pattern — full motion video, 1.3 KB total, about
|
||||
220 bytes a frame. A delta re-encodes only the rows that changed: an `R`
|
||||
@@ -82,6 +85,10 @@ This is a tour of the interpreter's edges, on purpose:
|
||||
batch a bar of noise drums. Noise is real: `ENVELOPE`'s sixth argument is a
|
||||
waveform, 0 to 3, which Chapter 7 forgot to mention. Voice 1 carries the tune so
|
||||
the collision blips (voice 2) and scene sweeps (voice 3) never steal its channel.
|
||||
A batch is four `PLAY` statements, one bar each — the 80-column line limit will
|
||||
not hold four bars in one string, and it does not need to: the parser's voice,
|
||||
envelope and duration state persists across statements and every `PLAY` appends
|
||||
to the same queue, so four bars queue exactly as one line would.
|
||||
|
||||
It also probes for its hardware like a proper boot loader, with one `TRAP` per
|
||||
device: no graphics refuses by name and exits, no audio mutes the soundtrack, no
|
||||
|
||||
@@ -461,38 +461,78 @@ BS% = W# / 160
|
||||
IF BS% < 1 THEN BS% = 1
|
||||
REM ---- PICTURE-BEGIN (generated by vaporwave.py; do not
|
||||
REM ---- hand-edit -- rerun the script to change the picture)
|
||||
DIM IM$(16)
|
||||
DIM IM$(56)
|
||||
DIM VA#(6)
|
||||
DIM VB#(6)
|
||||
NS# = 9
|
||||
VA#(0) = 9
|
||||
VB#(0) = 9
|
||||
VA#(1) = 10
|
||||
VB#(1) = 10
|
||||
VA#(2) = 11
|
||||
VB#(2) = 12
|
||||
VA#(3) = 13
|
||||
VB#(3) = 13
|
||||
VA#(4) = 14
|
||||
VB#(4) = 14
|
||||
VA#(5) = 15
|
||||
VB#(5) = 15
|
||||
IM$(0) = "G9G9G9G9GPGHEHG9GTEHG9GTEHGPGPEHG9GTEHG9GTEHGHGXEHGTBAG8EHG9GTEHG5EHGPEHG5EHGPEHG5EHGAPAG3EHGPEHG5EHGPEHGXGHEHG5EHGPEHG5EHGFBAGIEHGPGPEHGPEHGHEHGPEHGPEHGHEHGPEHGHEHGPEHGPEHGHEHGBPAGMEHGPEHGHEHGPEHGHEHGPEHGPEHGHEHGPEHGPEHGHEHGPEHGHEPGHEHGPEH"
|
||||
IM$(1) = "GHEPGHEHGPEHGHEPGHEHGHEGBAEHGHEHGPEHGHEPGHEHGPEHGHEHGPEHGHEPGHEHGPEHGHEPGHEHGPECPAEDGHEPGHEHGHEPGHEPGHEHGHEPGHEPGHEHGHEPGHEHGHEPGHEPGHECBAEDGHEPGHEPGHEHGHEPGHEHGHEPGHEPGHEHGHEPGHEPEPGHEPGHE5GHEPGHE5GHEHEXGHEPGHEEPAEZGHEPGHE5GHE5GHEPGHE5GHEP"
|
||||
IM$(2) = "GHE5GHE9ETGHE9ETGHEXEHGHE9ETGHHAE9ESGHEPEPGBBAGEE9EMHOE9ETGHEHE9E7HUE9E6E9E4H0E9E3E9E3H2E9EHBAETEHKHE9ELH6E9ECKHEPEPKHE9EBH9HAE9EIKHEHEXKHE2H9HCE9EPKHE5KHEPKDH9HEKCEPKHE5KHE5KHEKH9HGEBKHEPKHEXEHKHE5KHEBH9HIEIKHEPKHEPEPKHEPKHEHKAH9HKKHEHKHEP"
|
||||
IM$(3) = "KHEHKHEPKHEPKHH9HMEGKHEHKHEPKHEHKHEPKHEPH9HMEOKHEHKHEPKHEHKPEHKHEGH9HOKFEPKHEHKPEHKHEHKPEHKGH9HOEFKHEPKHEHKHEPKHEHKPEFH9HQKEEHKHEPKHEHKHEPKHEHKMH9HSKLEHKHEPKHEHKPEHKHEHKEH9HSEDKPEHKPEHKHEHKPEHKHEEH9HSKDEHKPEHKPKPEHKPEHKDH9HUECKHEHKPEHKHKXEH"
|
||||
IM$(4) = "KPEDH9HUKCEHK5EHK5EHKLH9HUKKEHK5EHK5EHKCH9HWEBKPEHKXKHEHK8I9IWKZEHKPKPEHK0I9IWK7EHKHKXEHKSI9IWK9KFEHK9KOI9IWK9KNK9KOI9IWK9KNK9KOI9IWK9KNKPIHKZI9IYK6IHKHKXIHKSI9IWK9KFIHK5IHKKI9IWK9KNIHK5IHKCI9IYKPIHKXKHIHK5IHKPIHK5IHKPIHKPKPIHK0I9IWKJIHKPIH"
|
||||
IM$(5) = "KHIHKPIHKPI9IZKBIHKHIHKPIHKHIHKPIHKKI9IWKJIHKHIHKPIHKHIHKPIHKDI9IXKPIHKHIHKHKHIHKHIPKHI9IYKCIHKPIHKHIHKPIHKHIPKHIHKPIHKHIPKHIHKPIHKHIHKPIHKHI9I9IHKHIHKPIHKHIPKHIHKHIEC9CSKDIPKHIPKHIHKHIPKHIHKEC9CSIDKHIPKHIPIPKHIPKHIFC9CQKEIHKHIPKHIHIXKHIPKG"
|
||||
IM$(6) = "C9COIFKHI5KHI5KHIPKHI5KHIPKHI5KHI5KHIPKHI5KHIPKHIXIHKHI9IDC9CMI4KHIPIPKHI6C9CKI9IDKHIHIXKHIZC9CII9IMKHI9IWC9CGI9IVI9I9I9I9IPI9I9I9I9IPQ9Q9Q9Q9QPE9E9E9E9EPE9E9E9E9EPQ9Q9Q9Q9QPE9E9E9E9EPQ9Q9Q9Q9QPE9E9E9E9EPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9"
|
||||
IM$(7) = "Q9QPE9E9E9E9EPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPE9E9E9E9EPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPE9E9E9E9EPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9"
|
||||
IM$(8) = "Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QP"
|
||||
IM$(9) = "RBRQ9QOKMQHK5RBSQ9QTI9IRRBXQ9QTKPQHKHQPKERBYQ9QPI9IHRB3Q9QSKAI5KHIJRB5Q9QTC9CMRB9Q9QWI9IGRCBQ9QYC9CCRCIA9A9A9A9APRCJE9E9E9E9EPRCNA9A9A9A9APRCOE9E9E9E9EPRCUA9A9A9A9APRCVE9E9E9E9EPRC5A9A9A9A9APRC7E9E9E9E9EP"
|
||||
IM$(10) = "RBQQ9QOK9KIQHKFRBRQ9QOI9IQRBWQ9QPKLQHKHQHKPRBXQ9QTI9QLIERB2Q9QRIBKHIPKHIPKCRB4Q9QSC9CORB8Q9QVI3KHIGRCAQ9QXC9CERCJA9A9A9A9APRCKE9E9E9E9EPRCOA9A9A9A9APRCPE9E9E9E9EPRCVA9A9A9A9APRCXE9E9E9E9EPRC7A9A9A9A9APRDAE9E9E9E9EP"
|
||||
IM$(11) = "RBPQ9QOK9KAQHKNRBQQ9QOI9IWRBVQ9QOKEQHKHQHKPQHKFRBWQ9QPI9IPRB1Q9QQKCIPKHIPKHIDRB3Q9QSC9CORB7Q9QUIWKHIPRB9Q9QWC9CGRCEA9A9A9A9APRCFE9E9E9E9EPRCGA9A9A9A9APRCHE9E9E9E9EPRCPA9A9A9A9APRCQE9E9E9E9EPRCXA9A9A9A9APRCZE9E9E9E9EPRDAA9A9A9A9APRDCE9E9E9E9"
|
||||
IM$(12) = "EP"
|
||||
IM$(13) = "RBOQ9QNK3QHKWRBPQ9QOI9IWRBUQ9QTKHQHKPQHKNRBVQ9QOI9IWRB0Q9QQIKKHIPKHIHKDRB1Q9QQC9CSRB2Q9QRC9CQRB6Q9QTIPKHIYRB8Q9QVC9CIRCKA9A9A9A9APRCLE9E9E9E9EPRCQA9A9A9A9APRCRE9E9E9E9EPRCZA9A9A9A9APRC1E9E9E9E9EPRDCA9A9A9A9APRDFE9E9E9E9EP"
|
||||
IM$(14) = "RBOQ9QNI9IYRBTQ9QOKEQHKPQHKVRBUQ9QTI9IRRBZQ9QTKHQHKPQHKHRB0Q9QQC9CSRB5Q9QTIHKHI5KARB7Q9QUC9CKRCBQ9QYI9ICRCHA9A9A9A9APRCIE9E9E9E9EPRCLA9A9A9A9APRCME9E9E9E9EPRCRA9A9A9A9APRCTE9E9E9E9EPRC1A9A9A9A9APRC3E9E9E9E9EPRDFA9A9A9A9APRDIE9E9E9E9EP"
|
||||
IM$(15) = "RBSQ9QTKPQHK3RBTQ9QOI9IWRBYQ9QPKDQHKPQHKHRBZQ9QTI9ILRB4Q9QSIAKHI5KHIBRB6Q9QTC9CMRCAQ9QXI9IERCEE9E9E9E9EPRCFA9A9A9A9APRCGE9E9E9E9EPRCMA9A9A9A9APRCNE9E9E9E9EPRCTA9A9A9A9APRCUE9E9E9E9EPRC3A9A9A9A9APRC5E9E9E9E9EPRDIA9A9A9A9AP"
|
||||
NS# = 32
|
||||
VA#(0) = 32
|
||||
VB#(0) = 35
|
||||
VA#(1) = 36
|
||||
VB#(1) = 39
|
||||
VA#(2) = 40
|
||||
VB#(2) = 43
|
||||
VA#(3) = 44
|
||||
VB#(3) = 47
|
||||
VA#(4) = 48
|
||||
VB#(4) = 51
|
||||
VA#(5) = 52
|
||||
VB#(5) = 55
|
||||
IM$(0) = "G9G9G9G9GPGHEHG9GTEHG9GTEHGPGPEHG9GTEHG9GTEHGHGXEHGTBAG8EHG9GTEH"
|
||||
IM$(1) = "G5EHGPEHG5EHGPEHG5EHGAPAG3EHGPEHG5EHGPEHGXGHEHG5EHGPEHG5EHGFBAGI"
|
||||
IM$(2) = "EHGPGPEHGPEHGHEHGPEHGPEHGHEHGPEHGHEHGPEHGPEHGHEHGBPAGMEHGPEHGHEH"
|
||||
IM$(3) = "GPEHGHEHGPEHGPEHGHEHGPEHGPEHGHEHGPEHGHEPGHEHGPEHGHEPGHEHGPEHGHEP"
|
||||
IM$(4) = "GHEHGHEGBAEHGHEHGPEHGHEPGHEHGPEHGHEHGPEHGHEPGHEHGPEHGHEPGHEHGPEC"
|
||||
IM$(5) = "PAEDGHEPGHEHGHEPGHEPGHEHGHEPGHEPGHEHGHEPGHEHGHEPGHEPGHECBAEDGHEP"
|
||||
IM$(6) = "GHEPGHEHGHEPGHEHGHEPGHEPGHEHGHEPGHEPEPGHEPGHE5GHEPGHE5GHEHEXGHEP"
|
||||
IM$(7) = "GHEEPAEZGHEPGHE5GHE5GHEPGHE5GHEPGHE5GHE9ETGHE9ETGHEXEHGHE9ETGHHA"
|
||||
IM$(8) = "E9ESGHEPEPGBBAGEE9EMHOE9ETGHEHE9E7HUE9E6E9E4H0E9E3E9E3H2E9EHBAET"
|
||||
IM$(9) = "EHKHE9ELH6E9ECKHEPEPKHE9EBH9HAE9EIKHEHEXKHE2H9HCE9EPKHE5KHEPKDH9"
|
||||
IM$(10) = "HEKCEPKHE5KHE5KHEKH9HGEBKHEPKHEXEHKHE5KHEBH9HIEIKHEPKHEPEPKHEPKH"
|
||||
IM$(11) = "EHKAH9HKKHEHKHEPKHEHKHEPKHEPKHH9HMEGKHEHKHEPKHEHKHEPKHEPH9HMEOKH"
|
||||
IM$(12) = "EHKHEPKHEHKPEHKHEGH9HOKFEPKHEHKPEHKHEHKPEHKGH9HOEFKHEPKHEHKHEPKH"
|
||||
IM$(13) = "EHKPEFH9HQKEEHKHEPKHEHKHEPKHEHKMH9HSKLEHKHEPKHEHKPEHKHEHKEH9HSED"
|
||||
IM$(14) = "KPEHKPEHKHEHKPEHKHEEH9HSKDEHKPEHKPKPEHKPEHKDH9HUECKHEHKPEHKHKXEH"
|
||||
IM$(15) = "KPEDH9HUKCEHK5EHK5EHKLH9HUKKEHK5EHK5EHKCH9HWEBKPEHKXKHEHK8I9IWKZ"
|
||||
IM$(16) = "EHKPKPEHK0I9IWK7EHKHKXEHKSI9IWK9KFEHK9KOI9IWK9KNK9KOI9IWK9KNK9KO"
|
||||
IM$(17) = "I9IWK9KNKPIHKZI9IYK6IHKHKXIHKSI9IWK9KFIHK5IHKKI9IWK9KNIHK5IHKCI9"
|
||||
IM$(18) = "IYKPIHKXKHIHK5IHKPIHK5IHKPIHKPKPIHK0I9IWKJIHKPIHKHIHKPIHKPI9IZKB"
|
||||
IM$(19) = "IHKHIHKPIHKHIHKPIHKKI9IWKJIHKHIHKPIHKHIHKPIHKDI9IXKPIHKHIHKHKHIH"
|
||||
IM$(20) = "KHIPKHI9IYKCIHKPIHKHIHKPIHKHIPKHIHKPIHKHIPKHIHKPIHKHIHKPIHKHI9I9"
|
||||
IM$(21) = "IHKHIHKPIHKHIPKHIHKHIEC9CSKDIPKHIPKHIHKHIPKHIHKEC9CSIDKHIPKHIPIP"
|
||||
IM$(22) = "KHIPKHIFC9CQKEIHKHIPKHIHIXKHIPKGC9COIFKHI5KHI5KHIPKHI5KHIPKHI5KH"
|
||||
IM$(23) = "I5KHIPKHI5KHIPKHIXIHKHI9IDC9CMI4KHIPIPKHI6C9CKI9IDKHIHIXKHIZC9CI"
|
||||
IM$(24) = "I9IMKHI9IWC9CGI9IVI9I9I9I9IPI9I9I9I9IPQ9Q9Q9Q9QPE9E9E9E9EPE9E9E9"
|
||||
IM$(25) = "E9EPQ9Q9Q9Q9QPE9E9E9E9EPQ9Q9Q9Q9QPE9E9E9E9EPQ9Q9Q9Q9QPQ9Q9Q9Q9QP"
|
||||
IM$(26) = "Q9Q9Q9Q9QPQ9Q9Q9Q9QPE9E9E9E9EPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9"
|
||||
IM$(27) = "Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPE9E9E9E9EPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9"
|
||||
IM$(28) = "QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9"
|
||||
IM$(29) = "Q9Q9Q9QPE9E9E9E9EPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9"
|
||||
IM$(30) = "Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QP"
|
||||
IM$(31) = "Q9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QPQ9Q9Q9Q9QP"
|
||||
IM$(32) = "RBRQ9QOKMQHK5RBSQ9QTI9IRRBXQ9QTKPQHKHQPKERBYQ9QPI9IHRB3Q9QSKAI5"
|
||||
IM$(33) = "KHIJRB5Q9QTC9CMRB9Q9QWI9IGRCBQ9QYC9CCRCIA9A9A9A9APRCJE9E9E9E9EP"
|
||||
IM$(34) = "RCNA9A9A9A9APRCOE9E9E9E9EPRCUA9A9A9A9APRCVE9E9E9E9EPRC5A9A9A9A9"
|
||||
IM$(35) = "APRC7E9E9E9E9EP"
|
||||
IM$(36) = "RBQQ9QOK9KIQHKFRBRQ9QOI9IQRBWQ9QPKLQHKHQHKPRBXQ9QTI9QLIERB2Q9QR"
|
||||
IM$(37) = "IBKHIPKHIPKCRB4Q9QSC9CORB8Q9QVI3KHIGRCAQ9QXC9CERCJA9A9A9A9APRCK"
|
||||
IM$(38) = "E9E9E9E9EPRCOA9A9A9A9APRCPE9E9E9E9EPRCVA9A9A9A9APRCXE9E9E9E9EP"
|
||||
IM$(39) = "RC7A9A9A9A9APRDAE9E9E9E9EP"
|
||||
IM$(40) = "RBPQ9QOK9KAQHKNRBQQ9QOI9IWRBVQ9QOKEQHKHQHKPQHKFRBWQ9QPI9IPRB1Q9"
|
||||
IM$(41) = "QQKCIPKHIPKHIDRB3Q9QSC9CORB7Q9QUIWKHIPRB9Q9QWC9CGRCEA9A9A9A9AP"
|
||||
IM$(42) = "RCFE9E9E9E9EPRCGA9A9A9A9APRCHE9E9E9E9EPRCPA9A9A9A9APRCQE9E9E9E9"
|
||||
IM$(43) = "EPRCXA9A9A9A9APRCZE9E9E9E9EPRDAA9A9A9A9APRDCE9E9E9E9EP"
|
||||
IM$(44) = "RBOQ9QNK3QHKWRBPQ9QOI9IWRBUQ9QTKHQHKPQHKNRBVQ9QOI9IWRB0Q9QQIKKH"
|
||||
IM$(45) = "IPKHIHKDRB1Q9QQC9CSRB2Q9QRC9CQRB6Q9QTIPKHIYRB8Q9QVC9CIRCKA9A9A9"
|
||||
IM$(46) = "A9APRCLE9E9E9E9EPRCQA9A9A9A9APRCRE9E9E9E9EPRCZA9A9A9A9APRC1E9E9"
|
||||
IM$(47) = "E9E9EPRDCA9A9A9A9APRDFE9E9E9E9EP"
|
||||
IM$(48) = "RBOQ9QNI9IYRBTQ9QOKEQHKPQHKVRBUQ9QTI9IRRBZQ9QTKHQHKPQHKHRB0Q9QQ"
|
||||
IM$(49) = "C9CSRB5Q9QTIHKHI5KARB7Q9QUC9CKRCBQ9QYI9ICRCHA9A9A9A9APRCIE9E9E9"
|
||||
IM$(50) = "E9EPRCLA9A9A9A9APRCME9E9E9E9EPRCRA9A9A9A9APRCTE9E9E9E9EPRC1A9A9"
|
||||
IM$(51) = "A9A9APRC3E9E9E9E9EPRDFA9A9A9A9APRDIE9E9E9E9EP"
|
||||
IM$(52) = "RBSQ9QTKPQHK3RBTQ9QOI9IWRBYQ9QPKDQHKPQHKHRBZQ9QTI9ILRB4Q9QSIAKH"
|
||||
IM$(53) = "I5KHIBRB6Q9QTC9CMRCAQ9QXI9IERCEE9E9E9E9EPRCFA9A9A9A9APRCGE9E9E9"
|
||||
IM$(54) = "E9EPRCMA9A9A9A9APRCNE9E9E9E9EPRCTA9A9A9A9APRCUE9E9E9E9EPRC3A9A9"
|
||||
IM$(55) = "A9A9APRC5E9E9E9E9EPRDIA9A9A9A9AP"
|
||||
REM ---- PICTURE-END
|
||||
SS# = 0
|
||||
SE# = NS# - 1
|
||||
@@ -1317,13 +1357,25 @@ TB# = TB# + 1
|
||||
IF TB# > 2 THEN TB# = 0
|
||||
RETURN
|
||||
|
||||
REM A batch is four PLAY statements, one bar each: the parser's V, T,
|
||||
REM U and duration state persists across statements and every PLAY
|
||||
REM appends to the same queue, so four bars queue exactly as one long
|
||||
REM string would -- which the 80-column line limit no longer allows.
|
||||
REM Each bar restates the prefix anyway, so a bar dropped by QFULL
|
||||
REM never leaves the next one playing with drum-kit state.
|
||||
LABEL TUNEA
|
||||
PLAY "V1T3U9S O1AO2AO3AO2AO3AO4CEAO1AO2AO4CEAO5CO4AE O1FO2FO3FO2FO3FAO4CFO1FO2FO3AO4CFAO5CO4A O1CO2CO3CO2CO3CEGO4CO1CO2CO3EGO4CEGO5C O1GO2GO3GO2GO3GBO4DGO1GO2GO3BO4DGBO5DO4B"
|
||||
PLAY "V1T3U9S O1AO2AO3AO2AO3AO4CEAO1AO2AO4CEAO5CO4AE"
|
||||
PLAY "V1T3U9S O1FO2FO3FO2FO3FAO4CFO1FO2FO3AO4CFAO5CO4A"
|
||||
PLAY "V1T3U9S O1CO2CO3CO2CO3CEGO4CO1CO2CO3EGO4CEGO5C"
|
||||
PLAY "V1T3U9S O1GO2GO3GO2GO3GBO4DGO1GO2GO3BO4DGBO5DO4B"
|
||||
MT# = TI# + 270
|
||||
RETURN
|
||||
|
||||
LABEL TUNEB
|
||||
PLAY "V1T3U9S O1AO2AO3AO2AO3AO4CEAO1AO2AO4CEAO5CEO4A O1FO2FO3FO2FO3FAO4CFO1FO2FO3AO4CFAO5CO4A O1DO2DO3DO2DO3DFAO4DO1DO2DO3FAO4DFAO5D O1EO2EO3EO2EO3E#GBO4EO1EO2EO3#GBO4E#GBO5E"
|
||||
PLAY "V1T3U9S O1AO2AO3AO2AO3AO4CEAO1AO2AO4CEAO5CEO4A"
|
||||
PLAY "V1T3U9S O1FO2FO3FO2FO3FAO4CFO1FO2FO3AO4CFAO5CO4A"
|
||||
PLAY "V1T3U9S O1DO2DO3DO2DO3DFAO4DO1DO2DO3FAO4DFAO5D"
|
||||
PLAY "V1T3U9S O1EO2EO3EO2EO3E#GBO4EO1EO2EO3#GBO4E#GBO5E"
|
||||
MT# = TI# + 270
|
||||
RETURN
|
||||
|
||||
|
||||
@@ -58,7 +58,14 @@ SKIP = "Q"
|
||||
ROWREC = "R"
|
||||
LENCH = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
MAXRUN = len(LENCH)
|
||||
PAYLOAD = 240
|
||||
|
||||
# The interpreter reads source through an 80-byte line buffer and refuses
|
||||
# any line that fills it (AKBASIC_MAX_LINE_LENGTH, sink_stdio.c), so a
|
||||
# stored line is at most 78 characters plus its newline. 'IM$(NN) = "' and
|
||||
# the closing quote spend 12 of those; 64 keeps the emitted lines under
|
||||
# the ceiling with margin to spare while the index stays two digits.
|
||||
PAYLOAD = 64
|
||||
MAXLINE = 78
|
||||
|
||||
SUN_CX, SUN_CY, SUN_R = 80, 50, 30
|
||||
HORIZON = 74
|
||||
@@ -206,13 +213,32 @@ def encode_delta(prev, cur):
|
||||
|
||||
|
||||
def chop(blob):
|
||||
return [blob[i:i + PAYLOAD] for i in range(0, len(blob), PAYLOAD)]
|
||||
"""Split a stream into strings of at most PAYLOAD characters, cutting
|
||||
only between records. The decoder reads a record's tail characters
|
||||
with MID on the string it is walking, so a run (two characters) or a
|
||||
row record (three) that straddled two IM$ entries would decode as
|
||||
garbage; DRAWSTREAM only carries the cursor, never a partial record."""
|
||||
out, cur = [], ""
|
||||
p = 0
|
||||
while p < len(blob):
|
||||
n = 3 if blob[p] == ROWREC else 2
|
||||
if len(cur) + n > PAYLOAD:
|
||||
out.append(cur)
|
||||
cur = ""
|
||||
cur += blob[p:p + n]
|
||||
p += n
|
||||
if cur:
|
||||
out.append(cur)
|
||||
return out
|
||||
|
||||
|
||||
def simulate(raster, blob):
|
||||
def simulate(raster, blob, x=0, y=0):
|
||||
"""Apply one encoded stream to a raster exactly the way the BASIC
|
||||
decoder does, skips-draw-nothing and all."""
|
||||
x = y = p = 0
|
||||
decoder does, skips-draw-nothing and all. The cursor comes in and
|
||||
goes back out because DRAWSTREAM carries it from one IM$ entry to
|
||||
the next -- decoding the chopped strings one at a time with the
|
||||
cursor threaded through is exactly what the demo will execute."""
|
||||
p = 0
|
||||
while p < len(blob):
|
||||
c = blob[p]
|
||||
if c == ROWREC:
|
||||
@@ -230,20 +256,31 @@ def simulate(raster, blob):
|
||||
x = 0
|
||||
y += 1
|
||||
p += 2
|
||||
return raster, x, y
|
||||
|
||||
|
||||
def simulate_lines(raster, lines):
|
||||
"""One stream as its chopped strings, cursor carried across the
|
||||
boundaries the way DRAWSTREAM carries X# and Y#."""
|
||||
x = y = 0
|
||||
for line in lines:
|
||||
raster, x, y = simulate(raster, line, x, y)
|
||||
return raster
|
||||
|
||||
|
||||
def verify(frames, base_blob, delta_blobs):
|
||||
def verify(frames, base_lines, delta_line_groups):
|
||||
"""The base must reproduce frame 0 exactly, and each delta must
|
||||
carry the raster exactly to the next frame. A skip leaves the cell
|
||||
the encoder promised was already right, so equality is total and
|
||||
any difference at all is an encoder bug."""
|
||||
any difference at all is an encoder bug. This decodes the CHOPPED
|
||||
strings, not the blobs, so a chop that split a record would fail
|
||||
here instead of corrupting the screen."""
|
||||
raster = [[1] * W for _ in range(H)]
|
||||
raster = simulate(raster, base_blob)
|
||||
raster = simulate_lines(raster, base_lines)
|
||||
assert raster == frames[0], "base stream does not reproduce frame 0"
|
||||
for i, blob in enumerate(delta_blobs):
|
||||
for i, lines in enumerate(delta_line_groups):
|
||||
want = frames[(i + 1) % PHASES]
|
||||
raster = simulate(raster, blob)
|
||||
raster = simulate_lines(raster, lines)
|
||||
assert raster == want, "delta %d does not reproduce its frame" % i
|
||||
|
||||
|
||||
@@ -261,6 +298,9 @@ def emit_block(base_lines, delta_ranges, all_lines):
|
||||
for i, s in enumerate(all_lines):
|
||||
out.append('IM$(%d) = "%s"' % (i, s))
|
||||
out.append("REM ---- PICTURE-END")
|
||||
for line in out:
|
||||
assert len(line) <= MAXLINE, "emitted line over %d chars: %r" % (
|
||||
MAXLINE, line)
|
||||
return out
|
||||
|
||||
|
||||
@@ -303,15 +343,15 @@ def main():
|
||||
base_lines = chop(base_blob)
|
||||
all_lines = list(base_lines)
|
||||
delta_ranges = []
|
||||
delta_blobs = []
|
||||
delta_line_groups = []
|
||||
for i in range(PHASES):
|
||||
blob = encode_delta(frames[i], frames[(i + 1) % PHASES])
|
||||
delta_blobs.append(blob)
|
||||
lines = chop(blob)
|
||||
delta_line_groups.append(lines)
|
||||
delta_ranges.append((len(all_lines), len(all_lines) + len(lines) - 1))
|
||||
all_lines.extend(lines)
|
||||
verify(frames, base_blob, delta_blobs)
|
||||
dbytes = sum(len(b) for b in delta_blobs)
|
||||
verify(frames, base_lines, delta_line_groups)
|
||||
dbytes = sum(len(l) for g in delta_line_groups for l in g)
|
||||
print("base %d bytes in %d strings; video %d bytes in %d strings; "
|
||||
"%d strings total" %
|
||||
(sum(len(s) for s in base_lines), len(base_lines), dbytes,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
10 REM An array reference used as a function argument, and as one of several.
|
||||
20 REM An identifier's subscript list used to hang off .right, which is also
|
||||
30 REM where an argument list chains its arguments -- so the arity counter walked
|
||||
30 REM where an argument list chains its arguments; the arity counter walked
|
||||
40 REM straight into the subscripts and refused the call. TODO.md section 4.
|
||||
50 DIM C#(4)
|
||||
60 C#(1) = -9
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
10 REM FILTER has no device capability behind it -- akgl_audio_* synthesises and
|
||||
20 REM mixes but has no filter stage, and SDL3 supplies no primitive to build one
|
||||
30 REM from. It is refused rather than silently ignored, so a program that asked
|
||||
10 REM FILTER has no device capability; akgl_audio_* synthesises and mixes but
|
||||
20 REM has no filter stage, and SDL3 supplies no primitive to build one from.
|
||||
30 REM It is refused rather than silently ignored, so a program that asked
|
||||
40 REM for a low-pass finds out it did not get one.
|
||||
50 PRINT "BEFORE"
|
||||
60 FILTER 1000, 1, 0, 0, 5
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
10 REM The standalone driver lends the script no audio device. ENVELOPE, VOL and
|
||||
10 REM The standalone driver lends the script no audio device. ENVELOPE, VOL,
|
||||
20 REM TEMPO only change interpreter state, so they work regardless; SOUND and
|
||||
30 REM PLAY need the device and must name themselves when there is none.
|
||||
40 ENVELOPE 1, 5, 9, 12, 2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
10 REM A DEF call takes its environment from the pool, one per call, exactly as
|
||||
10 REM A DEF call takes one environment from the pool, exactly as
|
||||
20 REM GOSUB does. It used to be owned by the funcdef and reset on every call,
|
||||
30 REM which cost two silent defects: two calls in one expression shared a slot,
|
||||
30 REM which cost two silent defects: calls in one expression shared a slot,
|
||||
40 REM and recursion never came back at all.
|
||||
50 DEF FACT(N#)
|
||||
60 IF N# <= 1 THEN RETURN 1
|
||||
@@ -15,9 +15,9 @@
|
||||
150 DEF DBL(N#) = N# * 2
|
||||
160 PRINT DBL(10) + DBL(1)
|
||||
170 PRINT DBL(1) + DBL(10) + DBL(100)
|
||||
180 REM Depth answers to the environment pool now, so runaway recursion reports
|
||||
190 REM "Environment pool exhausted" rather than hanging. It is not exercised here
|
||||
200 REM because the statement containing a failed call still prints a junk value
|
||||
210 REM afterwards -- a separate, pre-existing defect recorded in TODO.md, and one
|
||||
220 REM this golden file would pin if it went in. tests/user_functions.c asserts
|
||||
180 REM Depth answers to the environment pool, so runaway recursion reports
|
||||
190 REM "Environment pool exhausted" rather than hanging. It is not exercised
|
||||
200 REM here because the failed statement still prints junk afterwards;
|
||||
210 REM this is a separate defect in TODO.md, and one this golden file
|
||||
220 REM would pin if it went in. tests/user_functions.c asserts
|
||||
230 REM the message instead.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
10 REM A range check reported through the driver, end to end. The program stops
|
||||
10 REM A range check reported through the driver, end to end. The program
|
||||
20 REM at the first error, so this file covers one; the rest of the checks are
|
||||
30 REM asserted in tests/graphics_verbs.c against the recording backend.
|
||||
40 PRINT "BEFORE"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
10 REM The standalone driver lends the script no graphics device.
|
||||
20 REM COLOR, LOCATE and SCALE only touch interpreter state and must still work.
|
||||
20 REM COLOR, LOCATE and SCALE touch interpreter state and must still work.
|
||||
30 COLOR 1, 3
|
||||
40 LOCATE 40, 50
|
||||
50 SCALE 1, 640, 400
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
10 REM Group B: the housekeeping verbs. None of these is in the Go reference --
|
||||
20 REM they are on its own unimplemented list -- so what each one means here is
|
||||
10 REM Group B: housekeeping verbs. None is in the Go reference --
|
||||
20 REM they are on its unimplemented list -- so each meaning here is
|
||||
30 REM a decision, recorded in src/runtime_housekeeping.c beside the verb.
|
||||
40 A# = 1 : B# = 2
|
||||
50 PRINT A# : PRINT B#
|
||||
@@ -11,7 +11,7 @@
|
||||
110 P#(2) = 7 : Q#(2) = 9
|
||||
120 SWAP P#, Q#
|
||||
130 PRINT P#(2) : PRINT Q#(2)
|
||||
140 REM TRON prints each line number inline before the line runs, as a C128 does.
|
||||
140 REM TRON prints each line number inline, as a C128 does.
|
||||
150 TRON
|
||||
160 PRINT "TRACED"
|
||||
170 TROFF
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
10 REM A leading zero is padding, not a radix. The reference selects base 8 for
|
||||
20 REM any lexeme starting with 0, so 010 printed 8 and 08 was a parse error --
|
||||
30 REM TODO.md section 6 item 10, fixed. Commodore BASIC has no octal literals.
|
||||
40 REM 0x is the one prefix that changes the base, and it now reaches the scanner
|
||||
10 REM A leading zero is padding, not a radix. The reference selected base 8
|
||||
20 REM for lexemes starting with 0; 010 printed 8 and 08 was a parse error --
|
||||
30 REM TODO.md section 6 item 10 is fixed; Commodore BASIC has no octal.
|
||||
40 REM 0x is the one prefix that changes the base, and now reaches the scanner
|
||||
50 REM whole: that was section 6 item 15.
|
||||
60 PRINT 010
|
||||
70 PRINT 08
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
10 REM A truth value carries its payload in boolvalue, not floatval. The three
|
||||
20 REM numeric operators were `if ( INTEGER ) ... else <treat as float>`, and
|
||||
30 REM that else was a catch-all rather than a float branch -- so a truth value
|
||||
30 REM that else was a catch-all, not a float branch -- so a truth value
|
||||
40 REM on the LEFT computed 0 - 1 into a field nothing reads, kept its BOOLEAN
|
||||
50 REM type, and printed `true` instead of -2. Silent, and wrong twice over.
|
||||
60 A# = 1
|
||||
70 PRINT (A# == 1)
|
||||
80 REM On the RIGHT it stays legal and stays -1, which is the same property that
|
||||
90 REM lets AND and OR double as logical operators. Refusing it here would have
|
||||
80 REM On the RIGHT it stays legal and stays -1, the same property that
|
||||
90 REM lets AND and OR act as logical operators. Refusing it would have
|
||||
100 REM broken every condition in the language.
|
||||
110 PRINT 5 - (A# == 1)
|
||||
120 PRINT 5 * (A# == 1)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
10 REM Statements separated by colons. The COLON token existed from the start of
|
||||
20 REM the port and nothing consumed it, so a line could hold only one statement.
|
||||
10 REM Statements separated by colons. The COLON token existed from the start;
|
||||
20 REM nothing consumed it, so a line could hold only one statement.
|
||||
30 PRINT "A" : PRINT "B"
|
||||
40 A# = 1 : B# = 2 : PRINT A# + B#
|
||||
50 REM An empty statement is not an error: a trailing separator, or a run of them.
|
||||
50 REM Empty statements are valid: a trailing separator or runs of them.
|
||||
60 PRINT "C" :
|
||||
70 PRINT "D" :: PRINT "E"
|
||||
80 REM Everything after THEN belongs to the condition, which is BASIC 7.0 and is
|
||||
80 REM Everything after THEN belongs to the condition, as in BASIC 7.0, and is
|
||||
90 REM not something the reference had an opinion about -- it never got here.
|
||||
100 IF 1 == 1 THEN PRINT "TRUE-1" : PRINT "TRUE-2"
|
||||
110 IF 1 == 0 THEN PRINT "NEVER-1" : PRINT "NEVER-2"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
10 REM A field name is checked against a closed set the program declared, which
|
||||
20 REM is the one thing in this language whose valid spellings are written down.
|
||||
10 REM A field name is checked against the closed set the program declared;
|
||||
20 REM this is the one thing whose valid spellings are written down.
|
||||
30 REM A misspelled *variable* is still silent -- see the last two lines.
|
||||
40 TYPE RECT
|
||||
50 W#
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
170 RETURN B@.W#
|
||||
180 PRINT WIDEN(A@)
|
||||
190 PRINT A@.W#
|
||||
200 REM To change one on purpose, pass a pointer. Assignment copies a pointer's
|
||||
200 REM To change one on purpose, pass a pointer. Assignment copies its
|
||||
210 REM reference, so the callee is looking at the caller's own record.
|
||||
220 DIM Q@ AS PTR TO CRATE
|
||||
230 POINT Q@ AT A@
|
||||
@@ -37,7 +37,7 @@
|
||||
370 N2@.COUNT# = 20
|
||||
380 POINT N1@.TAIL@ AT N2@
|
||||
390 DEF TOTAL(P@ AS PTR TO NODE)
|
||||
395 REM A pointer is true when it points at something, which is how a walk knows
|
||||
395 REM A pointer is true when it points at something, so a walk knows
|
||||
396 REM where the list ends. NOT is the bitwise operator here, so the test is
|
||||
397 REM written the positive way round.
|
||||
400 IF P@->TAIL@ THEN RETURN P@->COUNT# + TOTAL(P@->TAIL@)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
10 REM A TYPE declares its fields; each takes its own type from its own suffix,
|
||||
10 REM A TYPE declares its fields; each takes its type from its own suffix,
|
||||
20 REM which is the same rule every other name in this language follows.
|
||||
30 TYPE COORD
|
||||
40 X#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
10 REM A type name and a field name are bare words, and so is every verb, so
|
||||
20 REM they share a namespace whether we like it or not. Both are refused with
|
||||
30 REM the same rule the scanner already applies to variable names -- and a type
|
||||
30 REM the scanner applies the same rule to variable names -- and a type
|
||||
40 REM name is refused by the prescan, which can say so plainly rather than
|
||||
50 REM leaving the parser to report "Expected expression or literal".
|
||||
60 TYPE POINT
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
10 REM This shows the waitingForCommand utility in the BasicEnvironment
|
||||
11 REM when we have a nested for loop. The inner loop SHOULD execute, but
|
||||
12 REM the outer loop should NOT execute. Therefore, neither loop should execute.
|
||||
12 REM the outer loop should NOT execute; neither loop should execute.
|
||||
20 FOR I# = 1 TO 0
|
||||
25 FOR J# = 2 TO 4
|
||||
30 PRINT "waitingForCommand FAILS if this is seen"
|
||||
@@ -8,4 +8,4 @@
|
||||
35 NEXT J#
|
||||
40 NEXT I#
|
||||
50 PRINT "SUCCESS"
|
||||
80 QUIT
|
||||
80 QUIT
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
10 PRINT MOD(10, 3)
|
||||
20 PRINT MOD(12, 5)
|
||||
30 PRINT MOD(4, 2)
|
||||
40 REM MOD() ONLY WORKS WITH INTEGERS - RESULTS WITH FLOATING POINT ARE UNRELIABLE
|
||||
40 REM MOD() ONLY WORKS WITH INTEGERS; FLOATING POINT RESULTS ARE UNRELIABLE
|
||||
50 REM PRINT MOD(1.2, 0.4)
|
||||
60 REM THERE IS NO ERROR THROWN HERE. JUST DONT DO IT.
|
||||
|
||||
Reference in New Issue
Block a user