2026-02-22 12:18:17 -05:00
|
|
|
|
# GW-BASIC 2026
|
2026-02-10 15:53:57 -05:00
|
|
|
|
|
|
|
|
|
|
A portable C reimplementation of Microsoft GW-BASIC, using the
|
|
|
|
|
|
[original 8088 assembly source](https://github.com/microsoft/GW-BASIC)
|
|
|
|
|
|
(released by Microsoft in 2020) as the authoritative reference.
|
|
|
|
|
|
|
|
|
|
|
|
This is not a transpilation — it reimplements the algorithms in clean C11
|
|
|
|
|
|
with modern data structures while targeting bug-compatible behavior.
|
|
|
|
|
|
|
|
|
|
|
|
## Building
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
mkdir -p build && cd build
|
|
|
|
|
|
cmake .. && make
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-02-15 16:28:44 -05:00
|
|
|
|
Requires a C11 compiler and CMake 3.10+. PulseAudio (`libpulse-simple`)
|
|
|
|
|
|
is optional — detected at build time for `SOUND`/`BEEP`/`PLAY` support.
|
2026-02-10 15:53:57 -05:00
|
|
|
|
|
|
|
|
|
|
## Usage
|
|
|
|
|
|
|
2026-02-22 12:18:17 -05:00
|
|
|
|
Interactive mode launches the authentic GW-BASIC full-screen editor:
|
2026-02-10 15:53:57 -05:00
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
$ ./gwbasic
|
2026-02-22 13:22:52 -05:00
|
|
|
|
GW-BASIC 2026 0.8.0
|
2026-02-10 15:53:57 -05:00
|
|
|
|
(C) Eremey Valetov 2026. MIT License.
|
|
|
|
|
|
Based on Microsoft GW-BASIC assembly source.
|
|
|
|
|
|
Ok
|
|
|
|
|
|
PRINT 2+2
|
|
|
|
|
|
4
|
|
|
|
|
|
Ok
|
|
|
|
|
|
FOR I=1 TO 5:PRINT I;:NEXT
|
|
|
|
|
|
1 2 3 4 5
|
|
|
|
|
|
Ok
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Run a program file:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
2026-02-10 17:01:50 -05:00
|
|
|
|
./gwbasic tests/programs/prime_sieve.bas
|
2026-02-10 15:53:57 -05:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Pipe input:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
echo '10 FOR I=1 TO 10:PRINT I*I;:NEXT' | ./gwbasic
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## What Works
|
|
|
|
|
|
|
|
|
|
|
|
**Data types:** INTEGER (%), SINGLE (!), DOUBLE (#), STRING ($)
|
|
|
|
|
|
|
|
|
|
|
|
**Operators:** `+ - * / ^ \ MOD AND OR XOR EQV IMP NOT < = > <= >= <>`
|
|
|
|
|
|
|
|
|
|
|
|
**Numeric functions:** SGN, INT, ABS, SQR, SIN, COS, TAN, ATN, LOG, EXP,
|
|
|
|
|
|
RND, FIX, CINT, CSNG, CDBL
|
|
|
|
|
|
|
|
|
|
|
|
**String functions:** LEN, ASC, CHR$, VAL, STR$, LEFT$, RIGHT$, MID$,
|
2026-02-10 17:01:50 -05:00
|
|
|
|
SPACE$, STRING$, HEX$, OCT$, INSTR, INPUT$
|
2026-02-10 15:53:57 -05:00
|
|
|
|
|
|
|
|
|
|
**Statements:**
|
|
|
|
|
|
|
|
|
|
|
|
| Category | Statements |
|
|
|
|
|
|
|----------|------------|
|
|
|
|
|
|
| Output | PRINT, LPRINT, PRINT USING, WRITE, CLS |
|
|
|
|
|
|
| Variables | LET, DIM, ERASE, SWAP, DEFINT/SNG/DBL/STR |
|
|
|
|
|
|
| Control flow | GOTO, GOSUB/RETURN, FOR/NEXT, IF/THEN/ELSE, WHILE/WEND, ON...GOTO/GOSUB |
|
2026-02-10 17:01:50 -05:00
|
|
|
|
| Input | INPUT, LINE INPUT, DATA/READ/RESTORE, INKEY$ |
|
2026-02-22 12:58:47 -05:00
|
|
|
|
| Program | RUN, RUN "file", CONT, STOP, END, NEW, LIST, CLEAR, AUTO, RENUM, DELETE |
|
2026-02-10 15:53:57 -05:00
|
|
|
|
| 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$ |
|
2026-02-22 12:58:47 -05:00
|
|
|
|
| Program I/O | SAVE, LOAD, MERGE, CHAIN, COMMON |
|
2026-02-10 17:01:50 -05:00
|
|
|
|
| Error handling | ON ERROR GOTO, RESUME, ERROR, ERR, ERL |
|
2026-02-10 15:53:57 -05:00
|
|
|
|
| User functions | DEF FN, RANDOMIZE |
|
2026-02-22 12:40:18 -05:00
|
|
|
|
| File management | KILL, NAME, FILES, MKDIR, RMDIR, CHDIR, SHELL |
|
|
|
|
|
|
| Date/time | DATE$, TIME$, TIMER |
|
2026-02-22 12:18:17 -05:00
|
|
|
|
| Screen | LOCATE, COLOR, WIDTH, SCREEN, KEY ON/OFF/LIST |
|
2026-02-10 17:01:50 -05:00
|
|
|
|
| Graphics | PSET, PRESET, LINE, CIRCLE, DRAW, PAINT |
|
2026-02-15 16:28:44 -05:00
|
|
|
|
| Sound | SOUND, BEEP, PLAY (MML) |
|
2026-02-10 15:53:57 -05:00
|
|
|
|
|
2026-02-22 12:18:17 -05:00
|
|
|
|
### Full-Screen Editor (TUI)
|
|
|
|
|
|
|
|
|
|
|
|
When running interactively, GW-BASIC 2026 presents the authentic full-screen
|
|
|
|
|
|
editor that people remember from the 1980s:
|
|
|
|
|
|
|
|
|
|
|
|
- 25×80 screen buffer with free cursor movement (arrow keys)
|
|
|
|
|
|
- **Enter on any screen line** re-enters it as BASIC input
|
|
|
|
|
|
- Insert/Overwrite toggle (Insert key, cursor shape changes)
|
|
|
|
|
|
- Function key bar on line 25 (`KEY ON`/`KEY OFF`/`KEY LIST`)
|
|
|
|
|
|
- Default F1-F10 bindings (F1=LIST, F2=RUN, F3=LOAD", etc.)
|
|
|
|
|
|
- Ctrl+C interrupts running programs
|
|
|
|
|
|
- Piped input bypasses the TUI entirely — scripts and test harnesses work unchanged
|
2026-02-22 13:22:52 -05:00
|
|
|
|
- `--full` flag adapts to the full terminal size instead of the classic 25×80
|
2026-02-22 12:18:17 -05:00
|
|
|
|
|
2026-02-10 17:01:50 -05:00
|
|
|
|
### Graphics
|
|
|
|
|
|
|
|
|
|
|
|
Graphics mode is activated with `SCREEN 1` (320×200, 4 colors) or
|
|
|
|
|
|
`SCREEN 2` (640×200, monochrome). Drawing commands render to a virtual
|
|
|
|
|
|
framebuffer and output via [Sixel graphics](https://en.wikipedia.org/wiki/Sixel),
|
|
|
|
|
|
which works in terminals like xterm, mlterm, foot, and WezTerm.
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
SCREEN 1
|
|
|
|
|
|
LINE (0,0)-(319,199), 1
|
|
|
|
|
|
CIRCLE (160,100), 80, 2
|
|
|
|
|
|
PAINT (160,100), 3, 2
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-02-10 15:53:57 -05:00
|
|
|
|
## Architecture
|
|
|
|
|
|
|
|
|
|
|
|
The interpreter follows the original GW-BASIC's internal structure:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
Source text → Tokenizer (CRUNCH) → Token stream
|
|
|
|
|
|
↓
|
|
|
|
|
|
Expression evaluator (FRMEVL)
|
|
|
|
|
|
↓
|
|
|
|
|
|
Statement dispatcher (NEWSTT)
|
|
|
|
|
|
↓
|
2026-02-22 12:18:17 -05:00
|
|
|
|
TUI screen buffer (interactive)
|
|
|
|
|
|
↓
|
2026-02-10 15:53:57 -05:00
|
|
|
|
HAL (platform I/O)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
| Module | File | Original |
|
|
|
|
|
|
|--------|------|----------|
|
|
|
|
|
|
| Tokenizer | tokenizer.c | GWMAIN.ASM |
|
|
|
|
|
|
| Evaluator | eval.c | GWEVAL.ASM |
|
|
|
|
|
|
| Interpreter | interp.c | BINTRP.ASM |
|
2026-02-22 12:18:17 -05:00
|
|
|
|
| TUI editor | tui.c | — |
|
2026-02-10 17:01:50 -05:00
|
|
|
|
| Graphics | graphics.c | — |
|
2026-02-10 15:53:57 -05:00
|
|
|
|
| Tokens | tokens.c | IBMRES.ASM |
|
|
|
|
|
|
| Errors | error.c | GWDATA.ASM |
|
|
|
|
|
|
| Math | math_int.c, math_float.c, math_transcend.c | MATH1/2.ASM |
|
|
|
|
|
|
| Strings | strings.c | BISTRS.ASM |
|
|
|
|
|
|
| File I/O | fileio.c | BIPTRG.ASM |
|
|
|
|
|
|
| PRINT USING | print_using.c | BIPRTU.ASM |
|
2026-02-15 16:28:44 -05:00
|
|
|
|
| Sound | sound.c | — |
|
2026-02-10 15:53:57 -05:00
|
|
|
|
| Platform | hal_posix.c | OEM*.ASM |
|
|
|
|
|
|
|
|
|
|
|
|
Key design differences from the original:
|
|
|
|
|
|
- IEEE 754 floating point (MBF conversion only for CVI/CVS/CVD compatibility)
|
|
|
|
|
|
- Dynamic memory allocation instead of 64KB segment layout
|
|
|
|
|
|
- malloc'd strings instead of compacting garbage collector
|
|
|
|
|
|
- setjmp/longjmp for error recovery
|
|
|
|
|
|
|
|
|
|
|
|
## Tests
|
|
|
|
|
|
|
2026-02-22 12:58:47 -05:00
|
|
|
|
53 test programs in `tests/programs/`, with CI via GitHub Actions:
|
2026-02-10 15:53:57 -05:00
|
|
|
|
|
|
|
|
|
|
```bash
|
2026-02-10 17:01:50 -05:00
|
|
|
|
bash tests/run_tests.sh
|
2026-02-10 15:53:57 -05:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-02-22 12:18:17 -05:00
|
|
|
|
Compatibility testing against real GWBASIC.EXE under DOSBox-X:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
bash tests/run_compat.sh --generate # generate .expected from GWBASIC.EXE
|
|
|
|
|
|
bash tests/run_compat.sh # compare gwbasic output against .expected
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-02-10 15:53:57 -05:00
|
|
|
|
## License
|
|
|
|
|
|
|
|
|
|
|
|
MIT License. See [LICENSE](LICENSE).
|