Files
gw-basic-2026/docs/getting-started.md
T
Eremey Valetov da1e6cebf1 CI: fix dos-cross-compile env; codegen: accept concat in CVI/CVS/CVD/cmp
- .github/workflows/ci.yml: the dos-cross-compile job failed on the
  first push because build_dos.sh sources $HOME/openwatcom-v2/setvars.sh
  if WATCOM is unset, but that file isn't part of the OpenWatcom V2
  snapshot — I'd been creating it locally by hand.  Add a "Configure
  OpenWatcom env" step that generates setvars.sh after extraction (so
  build_dos.sh works) AND exports WATCOM/PATH/INCLUDE via $GITHUB_ENV
  (so subsequent steps work even if setvars.sh sourcing changes).
  Also stash both DOS binaries before the next-mode clean wipes them,
  so the artifact upload actually has both .exe files.

- src/codegen.c: switch the four remaining emit_str_atom callers
  (CVI/CVS/CVD function args + string-comparison left/right) to
  emit_str_expr.  Now `CVS(A$+B$)` and `A$+B$ < C$` accept
  concatenation in their string operands; previously the atom-level
  caller stopped at the first identifier and the trailing `+` confused
  downstream parsing.  Verified: CVS(MKS$(3.14)+MKS$(0)) round-trips
  to 3.14 in both interpreter and compiled binary.  All 72 interpreter
  + 63 compiler tests still pass.

- docs/getting-started.md: document that gwbasic-compile auto-numbers
  unnumbered direct-mode lines (last_num + 10) so scratchpad-style
  programs compile without manual renumbering.

- tests/run_freedos_qemu.sh: helper for going through the manual TUI
  checklist on bare FreeDOS.  Modern qemu-kvm doesn't expose -fda on
  the default machine type and fat:rw: protocol is gone, so a fully
  automated FreeDOS smoke isn't tractable from userspace; this script
  builds a FAT data image (mtools), attaches it as -hdb to the FreeDOS
  qcow2, and points the user at the manual sequence in the script
  header.  The DOSBox-X harness (run_dos_smoke.sh) remains the
  automated DOS smoke.
2026-05-04 18:16:21 -04:00

6.8 KiB

Getting Started

Dependencies

  • C11 compiler (GCC or Clang)
  • CMake 3.10+
  • PulseAudio development library (libpulse-simple) -- optional, for SOUND/BEEP/PLAY

On Debian/Ubuntu:

sudo apt-get install build-essential cmake libpulse-dev

On Fedora/RHEL:

sudo dnf install gcc cmake pulseaudio-libs-devel

Building

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

./gwbasic tests/programs/prime_sieve.bas

Piped Input

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

# Emit C source to stdout
build/gwbasic-compile program.bas

# Compile to native executable
build/gwbasic-compile -c --runtime . program.bas

Both numbered (10 PRINT "HI") and unnumbered (PRINT "HI") sources compile. Unnumbered lines get auto-assigned numbers (10, 20, 30, ...) so the analysis pass and codegen can produce labeled statements; explicit line numbers are preserved. Direct-mode scratchpad scripts and classic "just a list of statements" programs compile without manual renumbering.

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.

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

Produces a standalone 128KB MZ executable -- no DOS extender required.

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

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:

./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)