164 lines
5.7 KiB
Markdown
164 lines
5.7 KiB
Markdown
|
|
# 13. Differences from BASIC 7.0
|
||
|
|
|
||
|
|
If you already write Commodore BASIC, this is the chapter to read first. Everything
|
||
|
|
here is deliberate, and everything is recorded in the repository's `TODO.md` with the
|
||
|
|
reasoning — this is the short version.
|
||
|
|
|
||
|
|
## The language
|
||
|
|
|
||
|
|
### Variables carry a type suffix, and the suffixes differ
|
||
|
|
|
||
|
|
| | Integer | Float | String |
|
||
|
|
|---|---|---|---|
|
||
|
|
| C128 | `A%` | `A` | `A$` |
|
||
|
|
| akbasic | `A#` | `A%` | `A$` |
|
||
|
|
|
||
|
|
There is **no such thing as an unsuffixed variable**. A bare name is a label.
|
||
|
|
|
||
|
|
### `=` works in a condition, and `==` works everywhere
|
||
|
|
|
||
|
|
`IF A = 5 THEN` does what you expect. `==` also means equality and is what the older
|
||
|
|
programs in this repository use. Outside a condition `=` is assignment, as always.
|
||
|
|
|
||
|
|
### `AND`, `OR` and `NOT` in conditions
|
||
|
|
|
||
|
|
These work, and a condition is a whole expression rather than a single comparison, so
|
||
|
|
`IF A = 1 AND B = 2 THEN` parses. Truth is nonzero, so `IF A THEN` works too.
|
||
|
|
|
||
|
|
### `MID` and `INSTR` count from zero
|
||
|
|
|
||
|
|
A C128 counts from one. A failed `INSTR` gives -1 rather than 0.
|
||
|
|
|
||
|
|
### `THEN` needs a verb
|
||
|
|
|
||
|
|
`IF X THEN 100` is not a jump. Write `IF X THEN GOTO 100`.
|
||
|
|
|
||
|
|
### Strings are 255 characters and cannot contain a quote
|
||
|
|
|
||
|
|
There is no escape character.
|
||
|
|
|
||
|
|
### Numbers
|
||
|
|
|
||
|
|
Integers are 64-bit and floats are IEEE doubles, so `PRINT 1.5` gives `1.500000`. A
|
||
|
|
leading zero is not octal; `0x` is hexadecimal.
|
||
|
|
|
||
|
|
## Block structure
|
||
|
|
|
||
|
|
**A whole loop on one line does not loop.**
|
||
|
|
|
||
|
|
```
|
||
|
|
10 FOR I# = 1 TO 3 : PRINT I# : NEXT I#
|
||
|
|
```
|
||
|
|
|
||
|
|
prints nothing. Block skipping walks source *lines*, so a `NEXT` on the same line as
|
||
|
|
its `FOR` is never reached. The same applies to `DO`/`LOOP`. Write loops across lines.
|
||
|
|
|
||
|
|
## Two known defects in `FOR`
|
||
|
|
|
||
|
|
Both are recorded, both have tests asserting the correct behaviour, and both are
|
||
|
|
waiting on a decision rather than on work:
|
||
|
|
|
||
|
|
- **A step that overshoots runs the body one extra time.** `FOR I = 1 TO 9 STEP 3` runs
|
||
|
|
with 1, 4, 7 *and 10*.
|
||
|
|
- **`FOR I = 1 TO 1` does not run its body at all**, where every other BASIC runs it
|
||
|
|
once.
|
||
|
|
|
||
|
|
The two errors cancel out for a step of 1, which is why they went unnoticed. Fixing
|
||
|
|
them would change the output of a checked-in acceptance file, which is not something
|
||
|
|
this project does silently.
|
||
|
|
|
||
|
|
**A loop counter does not survive its loop.** It lives in the loop's own scope, so
|
||
|
|
reading it afterwards gives zero.
|
||
|
|
|
||
|
|
## Direct mode
|
||
|
|
|
||
|
|
A statement typed with no line number runs immediately, as it should. This was not
|
||
|
|
true until recently — the interpreter used to file everything but a handful of verbs as
|
||
|
|
program text.
|
||
|
|
|
||
|
|
## Errors
|
||
|
|
|
||
|
|
`ER` and `EL` are **`ER#` and `EL#`**, ordinary global variables. `ER#` holds this
|
||
|
|
interpreter's error code, which bears no relation to a Commodore error number. Print
|
||
|
|
`ERR(ER#)` for the text.
|
||
|
|
|
||
|
|
## Graphics
|
||
|
|
|
||
|
|
- **Coordinates are always 320 by 200**, whatever the window size.
|
||
|
|
- **`SSHAPE` puts a handle in the string, not the pixels.** You can pass it to `GSHAPE`
|
||
|
|
and `SPRSAV`; you cannot save it or take its `LEN`.
|
||
|
|
- **`WIDTH` is emulated** by drawing parallel passes.
|
||
|
|
- **Drawing does not persist across frames.** The verbs draw straight to the renderer,
|
||
|
|
so anything drawn is overwritten on the next frame unless the program redraws it.
|
||
|
|
This is a defect, not a design.
|
||
|
|
- **`CHAR` ignores its colour argument** and needs a text device with a cursor.
|
||
|
|
|
||
|
|
## Sound
|
||
|
|
|
||
|
|
- **`PLAY` and `SOUND` do not block.** The statement after them runs immediately.
|
||
|
|
- **`FILTER` is refused.** There is no filter stage to configure.
|
||
|
|
- **`PLAY`'s `M` is accepted and does nothing.**
|
||
|
|
- **`TEMPO`'s calibration is a choice**, not a transcription.
|
||
|
|
|
||
|
|
## Sprites
|
||
|
|
|
||
|
|
- **Coordinates are the 320 by 200 drawing space**, not the VIC-II's raster space.
|
||
|
|
- **`SPRSAV` takes an integer array**, not a string, for the data form — a string here
|
||
|
|
cannot hold a zero byte. It also takes an **image file path**, which a C128 cannot.
|
||
|
|
- **A sprite loaded from a file keeps the image's own size**, not 24 by 21.
|
||
|
|
- **`MOVSPR`'s speed unit is a choice.** The manual does not say what a unit is worth.
|
||
|
|
- **Collision is by bounding box**, not by pixel, and only type 1 exists.
|
||
|
|
- **Priority and multicolour are recorded but not drawn.**
|
||
|
|
- **`SPRDEF` is out of scope.**
|
||
|
|
|
||
|
|
## Files
|
||
|
|
|
||
|
|
- **`PRINT #` and `INPUT #` need a space before the `#`.** `PRINT#1` scans as a
|
||
|
|
variable name.
|
||
|
|
- **`RECORD` counts lines**, not fixed-length records.
|
||
|
|
- **`BLOAD` requires a length.**
|
||
|
|
- **`HEADER`, `COLLECT`, `BACKUP` and `BOOT` are refused.** They operate on a physical
|
||
|
|
disk.
|
||
|
|
- **`DIRECTORY` is refused** pending a wrapper in the standard library.
|
||
|
|
|
||
|
|
## Machine
|
||
|
|
|
||
|
|
- **`SYS` is refused.** There is no 6502 and no ROM.
|
||
|
|
- **`FETCH` and `STASH` are the same byte copy.** There is no expansion RAM to tell
|
||
|
|
them apart.
|
||
|
|
- **`POKE`, `PEEK` and `POINTER` use real process addresses.** A wrong one is a
|
||
|
|
segmentation fault, not an error message.
|
||
|
|
- **`BANK`, `FAST` and `MONITOR` do not exist.**
|
||
|
|
|
||
|
|
## Formatting
|
||
|
|
|
||
|
|
- **`PRINT USING` renders one field per statement.** `PRINT USING "### ###"; A, B` is
|
||
|
|
not supported.
|
||
|
|
- **Exponential fields (`^^^^`) are not implemented.**
|
||
|
|
|
||
|
|
## Console
|
||
|
|
|
||
|
|
- **`SLEEP` and `WAIT` hold the program without blocking the host.** `SLEEP` with no
|
||
|
|
host clock does nothing at all rather than waiting forever.
|
||
|
|
- **`TI` and `TI$` are `TI#` and `TI$`**, refreshed once per step.
|
||
|
|
- **`WAIT` polls ordinary process memory.** Nothing changes it but the host.
|
||
|
|
- **`KEY` stores macros and nothing expands them.**
|
||
|
|
|
||
|
|
## Limits
|
||
|
|
|
||
|
|
| | |
|
||
|
|
|---|---|
|
||
|
|
| Source lines | 9999 |
|
||
|
|
| Line length | 255 |
|
||
|
|
| String length | 255 |
|
||
|
|
| Variables | 128 |
|
||
|
|
| Array elements | 1024 per array, 4096 in total |
|
||
|
|
| Scopes | 32 |
|
||
|
|
| Labels | 64 |
|
||
|
|
| `DATA` items | 512 |
|
||
|
|
| File channels | 10 |
|
||
|
|
| Operations per line | roughly 16 |
|
||
|
|
|
||
|
|
Every one is a fixed pool. Nothing in the interpreter calls `malloc`, which is what
|
||
|
|
makes it safe to embed in a game that cannot afford a surprise allocation.
|