Files
gw-basic-2026/docs/language-reference.md

354 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Language Reference
## Data Types
| Type | Suffix | Description |
|------|--------|-------------|
| INTEGER | `%` | 16-bit signed |
| SINGLE | `!` | 32-bit float |
| DOUBLE | `#` | 64-bit float |
| STRING | `$` | Up to 255 bytes |
## Operators
`+`, `-`, `*`, `/`, `^`, `\` (integer div), `MOD`, `AND`, `OR`, `XOR`, `EQV`,
`IMP`, `NOT`, `<`, `=`, `>`, `<=`, `>=`, `<>`
## Numeric Functions
`SGN`, `INT`, `ABS`, `SQR`, `SIN`, `COS`, `TAN`, `ATN`, `LOG`, `EXP`, `RND`,
`FIX`, `CINT`, `CSNG`, `CDBL`
`RND` can be called with or without parentheses: `RND` is equivalent to `RND(1)`.
## String Functions
`LEN`, `ASC`, `CHR$`, `VAL`, `STR$`, `LEFT$`, `RIGHT$`, `MID$`, `SPACE$`,
`STRING$`, `HEX$`, `OCT$`, `INSTR`, `INPUT$`
## File Functions
`EOF`, `LOC`, `LOF`
## Pseudo-variables
`ERL`, `ERR`, `CSRLIN`, `INKEY$`, `DATE$`, `TIME$`, `TIMER`, `POS(0)`
## Literals
Decimal, `&H` hex, `&O` octal, `D` exponent (double), `E` exponent (single),
type suffixes (`%`, `!`, `#`)
## Statements
| Category | Statements |
|----------|------------|
| Output | `PRINT`, `LPRINT`, `LLIST`, `PRINT USING`, `WRITE`, `CLS` |
| Variables | `LET`, `DIM`, `ERASE`, `SWAP`, `DEFINT`, `DEFSNG`, `DEFDBL`, `DEFSTR` |
| Control flow | `GOTO`, `GOSUB`/`RETURN`, `FOR`/`NEXT`, `IF`/`THEN`/`ELSE`, `WHILE`/`WEND`, `ON...GOTO`, `ON...GOSUB` |
| Input | `INPUT`, `LINE INPUT`, `DATA`/`READ`/`RESTORE`, `INKEY$` |
| Program control | `RUN`, `RUN "file"`, `CONT`, `STOP`, `END`, `NEW`, `LIST`, `CLEAR`, `AUTO`, `RENUM`, `DELETE`, `EDIT` |
| Sequential I/O | `OPEN`, `CLOSE`, `PRINT#`, `WRITE#`, `INPUT#`, `LINE INPUT#` |
| Random-access I/O | `FIELD`, `LSET`, `RSET`, `PUT`, `GET`, `CVI`/`CVS`/`CVD`, `MKI$`/`MKS$`/`MKD$` |
| Program I/O | `SAVE` (binary/ASCII), `LOAD` (auto-detects), `MERGE`, `CHAIN`, `COMMON` |
| Event trapping | `ON TIMER(n) GOSUB`, `TIMER ON`/`OFF`/`STOP`, `ON KEY(n) GOSUB`, `KEY(n) ON`/`OFF`/`STOP` |
| Error handling | `ON ERROR GOTO`, `RESUME`, `RESUME NEXT`, `RESUME n`, `ERROR`, `ERR`, `ERL` |
| User functions | `DEF FN`, `RANDOMIZE` |
| File management | `KILL`, `NAME`, `FILES`, `MKDIR`, `RMDIR`, `CHDIR`, `SHELL` |
| Date/time | `DATE$`, `TIME$`, `TIMER` |
| Screen | `LOCATE`, `COLOR`, `WIDTH`, `SCREEN`, `KEY ON`/`OFF`/`LIST`, `KEY n,"string"` |
| Graphics | `PSET`, `PRESET`, `LINE`, `CIRCLE`, `DRAW`, `PAINT`, `GET`, `PUT`, `VIEW`, `WINDOW`, `PALETTE`, `PMAP` |
| Sound | `SOUND`, `BEEP`, `PLAY` (MML parser, PulseAudio backend) |
| Memory | `DEF SEG`, `PEEK`, `POKE`, `BSAVE`, `BLOAD` |
| Hardware I/O | `OUT`, `INP`, `WAIT`, `MOTOR`, `STICK`, `STRIG` |
| Misc | `KEY`, `TRON`/`TROFF`, `OPTION BASE`, `MID$` assignment |
| System | `SYSTEM` |
## Program I/O (SAVE / LOAD)
`SAVE` writes the current program to a file. The default format is tokenized
binary (compact, fast to load), matching the original GW-BASIC behavior:
```
SAVE "myprog.bas" ' tokenized binary (default)
SAVE "myprog.bas",A ' ASCII text (human-readable, editable)
```
`LOAD` reads a program file, auto-detecting the format from the first byte:
```
LOAD "myprog.bas" ' auto-detects binary or ASCII
LOAD "myprog.bas",R ' load and run immediately
```
Binary files use the standard GW-BASIC 0xFF header format. Command-line
loading (`./gwbasic file.bas`) also auto-detects format.
`MERGE` loads an ASCII file without clearing the current program, overlaying
lines by number. `CHAIN` loads and runs a new program, optionally preserving
variables listed by `COMMON`.
## INKEY$ Extended Keys
`INKEY$` returns a zero-length string when no key is available, a one-byte
string for regular ASCII keys, or a two-byte string for extended keys:
```
K$ = INKEY$
IF LEN(K$) = 2 THEN scan = ASC(MID$(K$, 2, 1))
```
Extended keys return `CHR$(0)` as the first byte and the IBM PC scan code
as the second. Common scan codes:
| Key | Scan | Key | Scan |
|-----|------|-----|------|
| F1-F10 | 59-68 | Home | 71 |
| Up | 72 | PgUp | 73 |
| Left | 75 | Right | 77 |
| End | 79 | Down | 80 |
| PgDn | 81 | Ins | 82 |
| Del | 83 | | |
## Printer Output (LPRINT / LLIST)
`LPRINT` works identically to `PRINT` but sends output to the printer:
- **Default:** output is appended to `LPT1.TXT` in the current directory
- **`--lpt /dev/lp0`** (Linux) or **`--lpt LPT1`** (FreeDOS): send to real hardware
- **`--lpt report.txt`**: redirect to a custom file
`LLIST` lists the program to the printer, with optional line number ranges
(`LLIST`, `LLIST 10-50`, `LLIST -100`).
Both support `PRINT USING`, semicolons, commas, `TAB()`, and `SPC()`.
## Graphics
Graphics mode is activated with `SCREEN 1` (320x200, 4 colors) or
`SCREEN 2` (640x200, monochrome). Drawing commands render to an internal
framebuffer and output via [Sixel graphics](https://en.wikipedia.org/wiki/Sixel),
which works in terminals like xterm, mlterm, foot, and WezTerm.
### Drawing Commands
- `PSET (x,y), color` / `PRESET (x,y)` — set/reset individual pixels
- `LINE (x1,y1)-(x2,y2), color [,B|BF]` — lines, boxes, filled boxes
- `CIRCLE (cx,cy), r [,color [,start, end [,aspect]]]` — circles and arcs
- `PAINT (x,y), fill, border` — flood fill
- `DRAW string` — turtle graphics mini-language (U/D/L/R/E/F/G/H, M, C, S, B, N)
- `POINT (x,y)` — read pixel color
- `COLOR fg, bg` — set foreground/background colors
### Sprite Capture and Blit (GET / PUT)
- `GET (x1,y1)-(x2,y2), array` — capture a screen rectangle into an integer array
- `PUT (x,y), array [, action]` — blit a captured sprite back to the screen
The `action` parameter controls how the sprite combines with the existing screen:
| Action | Effect |
|--------|--------|
| `XOR` (default) | Exclusive OR — drawing twice erases the sprite |
| `PSET` | Overwrite screen with sprite pixels |
| `PRESET` | Overwrite screen with inverted sprite pixels |
| `AND` | Bitwise AND of screen and sprite |
| `OR` | Bitwise OR of screen and sprite |
Sprite data is stored in CGA-compatible packed format: word 0 is the width
in bits, word 1 is the height, and remaining words contain packed pixel data
matching the original GW-BASIC representation.
### VIEW / WINDOW / PALETTE
- `VIEW [[SCREEN] (x1,y1)-(x2,y2) [,[fill][,border]]]` — define a graphics
viewport. Without `SCREEN`, drawing coordinates are relative to the
viewport origin. With `SCREEN`, coordinates remain absolute. Without
arguments, resets to full screen.
- `WINDOW [[SCREEN] (x1,y1)-(x2,y2)]` — map logical coordinates onto the
viewport. Without `SCREEN`, Y increases upward (Cartesian); with `SCREEN`,
Y increases downward. Without arguments, resets to physical coordinates.
- `PALETTE [attribute, color]` — remap a color attribute to a different
physical color (015). Without arguments, resets to the default CGA palette.
- `PMAP(coordinate, function)` — convert between logical and physical
coordinates. Function 0/1 = logical→physical X/Y; 2/3 = physical→logical X/Y.
### Example
```
SCREEN 1
LINE (0,0)-(319,199), 1
CIRCLE (160,100), 80, 2
PAINT (160,100), 3, 2
```
## DEF SEG / PEEK / POKE
`DEF SEG`, `PEEK`, and `POKE` provide access to a virtual 8086 address space
that emulates the memory layout programs expected on a real IBM PC:
```
DEF SEG = &HB800 ' select CGA video buffer segment
POKE 0, 65 ' write 'A' to top-left screen cell
PRINT PEEK(1) ' read the color attribute
DEF SEG ' reset to default segment
```
### Emulated Memory Regions
| Segment | Address Range | Description |
|---------|---------------|-------------|
| `0040` | BIOS data area | Video mode (`0049`), column count (`004A`), cursor position (`0050-0051`), timer ticks (`006C-006F`), screen rows (`0084`), keyboard shift flags (`0017`: bit 7 = insert mode) |
| `B800` | CGA text buffer | Character/attribute pairs in text mode (even byte = char, odd byte = attr, 80 columns × 25 rows = 4000 bytes) |
| `B800` | CGA graphics buffer | In SCREEN 1/2: CGA interlaced layout (even rows at offset 0, odd rows at 0x2000, 80 bytes/row) |
All other segments read as 0 and writes are silently discarded. The timer
tick counter at `0040:006C` tracks real time at the original 18.2 Hz rate.
## BSAVE / BLOAD
`BSAVE` saves a block of virtual memory to a binary file with a 7-byte header.
`BLOAD` loads it back. These operate on whichever segment was last set by
`DEF SEG`.
```
DEF SEG = &HB800
BSAVE "screen.bin", 0, 4000 ' save the CGA text buffer
CLS
BLOAD "screen.bin" ' restore it
BLOAD "screen.bin", 100 ' load to a different offset
```
The file format is compatible with the original GW-BASIC: byte 0 = `0xFD`,
bytes 1-2 = segment (LE), bytes 3-4 = offset (LE), bytes 5-6 = length (LE),
followed by the raw data bytes.
## Hardware I/O (OUT / INP / WAIT)
`OUT`, `INP`, and `WAIT` provide access to emulated IBM PC I/O ports, enabling
classic programs that drive hardware directly — speaker tones via the 8253 PIT,
CGA palette tricks, and serial port polling.
```
OUT &H43, &HB6 ' PIT channel 2: lobyte/hibyte, mode 3
OUT &H42, &HD3 : OUT &H42, &H04 ' set frequency divisor (1235 → 966 Hz)
OUT &H61, INP(&H61) OR 3 ' speaker on
OUT &H61, INP(&H61) AND &HFC ' speaker off
```
### Emulated Ports
| Port | Device | Behavior |
|------|--------|----------|
| `&H42``&H43` | 8253 PIT channel 2 | Speaker frequency divisor (1193180 / divisor Hz) |
| `&H61` | PPI Port B | Bits 01 control speaker; both set = tone on, either clear = off |
| `&H3D8` | CGA mode control | Mode register; writes with changed mode bits trigger `SCREEN` changes |
| `&H3D9` | CGA color select | Background color (bits 03) and palette select (bit 5) |
| `&H201` | Game port | Returns `&HF0` (no joystick connected) |
| `&H3F8``&H3FE` | COM1 serial | Minimal stub; LSR (`&H3FD`) returns `&H60` (transmitter ready) |
| Default | — | Reads return `&HFF` (floating bus), writes silently discarded |
### Related Functions
- `INP(port)` — read a byte from an I/O port
- `STICK(n)` — joystick axis position (returns 128 = center, n = 03)
- `STRIG(n)` — joystick button state (returns 0 = not pressed)
- `WAIT port, mask [, xor_mask]` — busy-wait until `(INP(port) XOR xor_mask) AND mask` is nonzero; Ctrl+C breaks out
- `MOTOR [n]` — accepted and silently ignored (cassette motor control)
When the PPI speaker bits are set, the PIT frequency divisor is used to
generate a continuous tone via PulseAudio (same backend as `SOUND` / `PLAY`).
## Sound
- `SOUND frequency, duration` — play a tone (frequency in Hz, duration in clock ticks)
- `BEEP` — play the default beep
- `PLAY string` — Music Macro Language (MML) string for melodies
Sound output uses PulseAudio when available; commands are silently ignored otherwise.
## Full-Screen Editor (TUI)
When running interactively, GW-BASIC 2026 presents the authentic full-screen
editor:
- 25×80 screen buffer by default, or full terminal size with `--full`
- Press Enter on any screen line to re-enter it as BASIC input
- Insert/Overwrite toggle (Insert key)
- Home/End/Delete/Backspace/Escape for line editing
- Ctrl+C interrupts running programs
- Uses the ANSI alternate screen buffer for clean terminal restore on exit
### Function Keys
Default F1-F10 bindings match the original GW-BASIC:
| Key | Default | Key | Default |
|-----|---------|-----|---------|
| F1 | `LIST ` | F6 | `,"LPT1:"` + Enter |
| F2 | `RUN` + Enter | F7 | `TRON` + Enter |
| F3 | `LOAD"` | F8 | `TROFF` + Enter |
| F4 | `SAVE"` | F9 | `KEY ` |
| F5 | `CONT` + Enter | F10 | `SCREEN 0,0,0` + Enter |
- `KEY ON` — show the function key bar on line 25
- `KEY OFF` — hide the bar
- `KEY LIST` — display all definitions
- `KEY n, "string"` — redefine a function key
### Piped Mode
When stdin is not a terminal (piped input), the TUI is not activated.
The interpreter reads lines from stdin and writes output directly to stdout,
suitable for scripting and test harnesses.
### Program Editing
- `EDIT [linenum]` — display a program line for editing in the TUI; press Enter to re-store it
- `AUTO [start][,increment]` — automatic line numbering mode
- `RENUM [new][,[old][,increment]]` — renumber program lines (patches all GOTO/GOSUB references)
- `DELETE range` — delete program lines (`DELETE 10-50`, `DELETE -100`, `DELETE 200-`)
## Event Trapping
GW-BASIC supports event-driven programming through trap handlers that fire
between statements during program execution.
### Timer Events
```
ON TIMER(n) GOSUB line ' register handler (fires every n seconds)
TIMER ON ' enable timer trapping
TIMER STOP ' suspend trapping (events are queued)
TIMER OFF ' disable trapping (events are discarded)
```
### Function Key Events
```
ON KEY(n) GOSUB line ' register handler for F-key n (1-10)
KEY(n) ON ' enable trapping for key n
KEY(n) STOP ' suspend trapping (events are queued)
KEY(n) OFF ' disable trapping
```
Event handlers execute as implicit GOSUBs. The `RETURN` statement returns
to the interrupted code and clears the handler's in-progress flag. Events do
not fire inside their own handler (re-entrant protection).
`TIMER STOP` / `KEY(n) STOP` queue events while stopped; switching to
`TIMER ON` / `KEY(n) ON` fires the pending event immediately.
## References
- Microsoft Corporation. *Microsoft GW-BASIC: User's Guide and Reference*.
Microsoft Press, 1989. ISBN 978-1-55615-260-3.
- Inman, Don and Bob Albrecht. *The GW-BASIC Reference*. Osborne McGraw-Hill,
1990. ISBN 978-0-07-881644-4.
- Ahl, David H. *BASIC Computer Games: Microcomputer Edition*. Workman, 1978.
ISBN 978-0-89480-052-8.
- Microsoft Corporation. *GW-BASIC User's Manual*. Microsoft, 1987.
(OEM bundled; no ISBN.)
- Microsoft Corporation.
[GW-BASIC Source Code](https://github.com/microsoft/GW-BASIC). Released 2020.