Files
akbasic/docs/13-differences.md

164 lines
5.7 KiB
Markdown
Raw Normal View History

# 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.