Files
gw-basic-2026/docs/getting-started.md
T
Eremey Valetov 70ffd39562 v0.17.0: BIOS-routed TUI on DOS, version banner, compiler PulseAudio link
QA findings from a multi-round review of the FreeDOS submission prep work:

- TUI rendering refactor: src/tui.c emitted ANSI escape sequences via
  printf, which displays as raw text on bare FreeDOS (no ANSI.SYS).
  Add four HAL ops (tui_enter, tui_leave, render_run, set_cursor_shape)
  and route per-cell rendering through them.  POSIX backend keeps the
  ANSI path; DOS backend drives BIOS INT 10h via the existing
  bios_set_cursor / bios_write_char helpers.  The TUI's logical cursor
  goes through the saved orig_locate to avoid recursing through the
  swapped-in gw_hal->locate.

- DOS extended-key mapping: dos_getch returns 0x100 | scancode for
  arrows / F-keys; tui_read_key wasn't translating those to its TK_*
  constants, so the editor never saw arrow keys or F1-F10 on DOS.
  Add a __MSDOS__-conditional translation table in tui_read_key.

- Version banner: GW_VERSION was still 0.16.0 even though the v0.17.0
  release prep was already in CHANGES.TXT.  Bump.

- Compiler PulseAudio link: gwbasic-compile -c hardcoded
  '-lgwrt -lm -lpthread' on the gcc command line.  When libgwrt was
  built against libpulse-simple (the default on any host with the
  PulseAudio dev headers installed), the compile workflow failed with
  'undefined reference to pa_simple_drain'.  CMake now passes
  GWRT_HAS_PULSEAUDIO to gwbasic-compile when libpulse is present, and
  the compiler appends -lpulse-simple to the link line.

- FRE("") garbage collection: the interpreter skipped strpool_gc with a
  comment 'unsafe during expression eval', but that's exactly what real
  GW-BASIC's FRE("") does (and the AOT compiler path already did).  Add
  the GC call; strpool_pin/unpin is the existing escape hatch if a
  caller has live pool pointers on the C stack.  Fixes the string_gc
  compat test.

- Test harness normalization: run_tests.sh stripped trailing whitespace
  on the actual output but not the expected file, causing spurious
  mismatches against golden files captured from real GWBASIC.EXE.
  Normalize both sides identically.  Fixes the peek_gfx mismatch.

- Print_using: snprintf into mantissa[32] with %.*f and an unbounded
  dec triggered a -Wformat-truncation warning.  Clamp dec to 20 (IEEE
  double has at most ~17 significant decimal digits).

- Doc/version consistency: 16-bit binary size reported as 127KB in one
  place and 128KB in three; standardize on 128KB.  HAL backend count
  said '1 file' but is now 2.  CI test count said 'all 66 test
  programs' but is 72.  Add a v0.17.0 row to the development.md table.
  Update getting-started.md DOS section to match the BIOS-rendering
  reality and add a manual TUI verification checklist.

- dos_init now writes back BIOS-reported cols/rows to dos_hal struct
  fields (forward-declared so dos_init can reference it).

After these changes: 72/72 interpreter tests pass, compat 68/68
matched, no warnings on the Linux build.
2026-05-03 12:25:41 -04:00

224 lines
6.5 KiB
Markdown

# Getting Started
## Dependencies
- C11 compiler (GCC or Clang)
- CMake 3.10+
- PulseAudio development library (`libpulse-simple`) -- optional, for `SOUND`/`BEEP`/`PLAY`
On Debian/Ubuntu:
```bash
sudo apt-get install build-essential cmake libpulse-dev
```
On Fedora/RHEL:
```bash
sudo dnf install gcc cmake pulseaudio-libs-devel
```
## Building
```bash
git clone https://github.com/evvaletov/gw-basic-2026.git
cd gw-basic-2026
mkdir -p build && cd build
cmake .. && make
```
The binary is `build/gwbasic`.
## Usage
### Interactive Mode
Running `./gwbasic` with no arguments launches the full-screen editor:
```
$ ./gwbasic
GW-BASIC 2026 0.17.0
(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
```
Use arrow keys to move the cursor freely. Press Enter on any screen line to
re-enter it. F1-F10 insert common commands (F2 runs the program).
### Running a Program File
```bash
./gwbasic tests/programs/prime_sieve.bas
```
### Piped Input
```bash
echo '10 FOR I=1 TO 10:PRINT I*I;:NEXT' | ./gwbasic
```
### Direct Mode Expressions
Type expressions and statements at the `Ok` prompt:
```
PRINT SIN(3.14159/2)
1
A$="HELLO WORLD":MID$(A$,7,5)="BASIC":PRINT A$
HELLO BASIC
```
### Command-Line Options
```
Usage: gwbasic [options] [file.bas]
Options:
-f, --full Use full terminal size (default: 25x80)
-h, --help Show this help
--lpt DEVICE|FILE Printer output destination (default: LPT1.TXT)
Use LPT1 or /dev/lp0 for real hardware
-v, --version Show version
```
## Ahead-of-Time Compiler
`gwbasic-compile` translates `.bas` programs to C source, then optionally
invokes GCC to produce native executables linked against `libgwrt.a`.
### Basic Usage
```bash
# Emit C source to stdout
build/gwbasic-compile program.bas
# Compile to native executable
build/gwbasic-compile -c --runtime . program.bas
```
### Compiler Options
```
Usage: gwbasic-compile [options] input.bas
Options:
-o FILE Output C source file (default: stdout)
-c Compile to executable (invoke gcc)
-O LEVEL GCC optimization level (default: 2)
--keep-c Keep generated C file (with -c)
--runtime DIR Path to runtime headers/library
--warn Static analysis warnings
--safe Runtime safety checks (implies --warn)
--safe=sanitize Above + address/UB sanitizers (with -c)
```
### Memory Safety (`--warn` / `--safe`)
The `--warn` flag enables compile-time static analysis warnings:
- **Uninitialized variables** -- variables used before their first assignment
(via LET, FOR, READ, INPUT)
- **GOTO/GOSUB to nonexistent line** -- jump targets that don't exist in the
program
- **Unreachable code** -- lines after unconditional GOTO/END/STOP that are not
jump targets
The `--safe` flag (implies `--warn`) adds runtime safety checks to the
generated C:
- **Integer overflow detection** -- arithmetic on integer (%) variables uses
checked functions (`gw_int_add`, `gw_int_sub`, `gw_int_mul`) that raise
"Overflow" instead of silently wrapping, matching real GW-BASIC behavior
- **Enhanced array diagnostics** -- subscript errors report the array name,
subscript value, line number, and which dimension exceeded its bound
- **GOSUB stack diagnostics** -- stack overflow reports the source line and
current depth
The `--safe=sanitize` flag (with `-c`) additionally passes
`-fsanitize=address,undefined` to GCC for full memory error detection.
```bash
# Warnings only (zero runtime cost)
build/gwbasic-compile --warn program.bas
# Runtime safety checks
build/gwbasic-compile --safe -c --runtime . program.bas
# Full sanitizer build (debugging)
build/gwbasic-compile --safe=sanitize -c --runtime . program.bas
```
## Building for DOS / FreeDOS
GW-BASIC 2026 cross-compiles to DOS using OpenWatcom V2 (`wcc` / `wcc386`).
Two targets are available:
### 16-bit real-mode (recommended for FreeDOS)
Produces a standalone 128KB MZ executable -- no DOS extender required.
```bash
wmake -f Makefile.dos16
```
Requires OpenWatcom V2 with 16-bit DOS target. Uses MEDIUM memory model
(`-mm`): code can exceed 64KB, data must fit in 64KB.
### 32-bit DOS/4GW
Produces a 175KB LE executable requiring `DOS4GW.EXE` (265KB) at runtime.
Also builds the compiler (`GWBASCOM.EXE`) and runtime library (`GWRT.LIB`).
```bash
wmake -f Makefile.dos
```
### Running on FreeDOS
Copy `GWBASIC.EXE` (and `DOS4GW.EXE` for the 32-bit build) to your FreeDOS
system. Run programs from the command line:
```
C:\> GWBASIC PROGRAM.BAS
```
Running without arguments launches the interactive editor. The TUI renders
through BIOS INT 10h with the screen buffer in far memory, so the full-screen
editor, F-key bar, cursor positioning, and scrolling all work on bare FreeDOS
without `ANSI.SYS`.
### Verifying the DOS Build
Two automated checks run from a Linux host:
```bash
./build_dos.sh 16 # produces gwbasic16.exe (~128KB)
./build_dos.sh 32 # produces gwbasic.exe (~175KB)
bash tests/run_dos_smoke.sh # runs gwbasic16.exe under DOSBox-X, diffs golden
```
The smoke harness validates non-interactive features (arithmetic, strings,
control flow, GOSUB, FOR/NEXT, DATA/READ, DEF FN, file I/O via OPEN/PRINT#).
The interactive TUI features below need a manual session under DOSBox-X or
real FreeDOS:
| Check | What to do | Expected |
|-------|-----------|----------|
| TUI startup | Launch `GWBASIC.EXE` with no arguments | `Ok` prompt, F-key bar at row 25 (`1LIST 2RUN ...` in inverse video) |
| Cursor keys | Press up/down/left/right | Cursor moves freely without printing characters |
| Re-enter line | Type `10 PRINT "HI"`, Enter; arrow up to that line, Enter | Line re-tokenized; subsequent `LIST` shows it stored |
| F1 (LIST) | Press F1 then Enter | Inserts `LIST `, runs `LIST` |
| F2 (RUN) | Type a program, press F2 | Runs it (`RUN\r` is appended) |
| Insert toggle | Press Ins; type characters mid-line | Cursor switches between block (insert) and underline (overwrite) shapes; characters insert vs overstrike accordingly |
| Home / End | Press Home, End | Cursor jumps to column 0 / past last printable char on the row |
| Scroll | Fill the screen with output | Bottom row pinned to the F-key bar; new lines push old ones up |
| Ctrl-C | Run `10 GOTO 10` and press Ctrl-C | Program stops with `Break in 10` |
| KEY OFF / KEY ON | `KEY OFF` then `KEY ON` | F-key bar disappears / reappears |
| CLS | `CLS` | Screen clears, cursor at top-left |
| Exit | `SYSTEM` | Returns to DOS prompt cleanly (no leftover escape codes) |