Add a '$EXTERN NAME(ARGTYPES) AS RET pragma so compiled BASIC can call C
functions directly, the natural follow-up to Level 1 (--emit-obj /
--main-name). The pragma is an apostrophe comment, so the interpreter
ignores it while the compiler registers it.
Map INTEGER/SINGLE/DOUBLE/STRING to int16_t/float/double/const char* at the
boundary: a string argument crosses as a temporary C copy that is freed
after the call, and a string return is copied into the pool. The call name
is matched case-insensitively but emitted as the C symbol with the case
written in the pragma. Names are recognized before parse_var() truncates
identifiers to two significant characters, so multi-character C function
names work.
A string return that aliases a char* argument is copied before the argument
temporaries are freed, which avoids a use-after-free. Over-supplied
arguments are consumed without desyncing the token stream and warn on arity
mismatch.
Docs: getting-started.md "Foreign Functions from BASIC". Test:
tests/run_ffi_test.sh, wired into CI. 63/63 compiler, 72/72 interpreter,
68/68 compat still pass.
Also refile the roadmap "Next Up" backlog as git-bug issues and prune
docs/roadmap.md to point at git-bug as the source of truth for planned work.
Co-authored-by: Eremey Valetov <evvaletov@users.noreply.github.com>
- .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.
- build_dos.sh: Linux-friendly cross-compile to DOS via OpenWatcom V2.
OpenWatcom's wmake on Linux can't apply the .c.obj implicit rule for
subdirectory paths, and Makefile.dos / Makefile.dos16 rely on DOS-
only commands like 'del'. Script invokes wcc / wcc386 directly,
tracks 16-bit vs 32-bit mode via a stamp file (auto-cleans on
switch), generates a wlink directive file (the brace-delimited file
list wouldn't survive shell quoting), and supports clean. The DOS
Makefiles still work on Windows / DOS hosts.
- tests/run_compiler_tests.sh: AOT compiler harness. For each .bas
in tests/programs/, compiles via gwbasic-compile -c, runs the
resulting executable, normalizes output and diffs against the
golden file from tests/expected/. Skip list covers chain/common
multi-file flows, hardware/timing-dependent programs, unnumbered
direct-mode programs (compiler requires line numbers), and
misc_stmts/run_file (interpreter-vs-compiler ON ERROR divergence).
Result: 56/56 pass.
- tests/run_dos_smoke.sh + dos_smoke.bas + expected: runs gwbasic16.exe
under DOSBox-X (flatpak) with a program that exercises arithmetic,
strings, control flow, GOSUB, FOR/NEXT, DATA/READ, DEF FN, OPEN/
PRINT#/CLOSE, and diffs against the interpreter's golden output.
Uses $HOME for the staging dir (DOSBox-X flatpak doesn't see /tmp).
- pkg/GWBASIC.LSM + pkg/build_pkg.sh: FreeDOS submission package.
Produces dist/gwbasic-<VERSION>.zip with the standard FreeDOS
layout (APPINFO/GWBASIC.LSM, BIN/GWBASIC.EXE, DOC/GWBASIC/{README,
CHANGES,LICENSE} with CRLF, SOURCE/GWBASIC/<full source>). Source
tree is filtered through git ls-files to exclude build artifacts.
- docs/Makefile: standard Sphinx Makefile so 'cd docs && make html'
works as documented in README.md.
- .github/workflows/ci.yml: split into two jobs. build-and-test now
also runs the compiler harness. New dos-cross-compile job caches
~/openwatcom-v2, downloads the OpenWatcom V2 snapshot if not
cached, builds both 16-bit and 32-bit DOS binaries, asserts size
bounds, and uploads them as artifacts.
- .gitignore: ignore .dos_build_mode (script's stamp), .link_dir/
(transient wlink directive dir), dist/ (package output).
The Ubuntu package index on GitHub runners was stale, causing 404s for
libglib2.0 (a transitive dependency of libpulse-dev). Also make the
install non-fatal since PulseAudio is optional.
Add GitHub Actions CI with automated build and test. Implement real
terminal I/O with raw mode (enable_raw/disable_raw, proper INKEY$
polling via VMIN=0/VTIME=0, INPUT$ function). Add Sixel graphics
engine with virtual framebuffer (SCREEN 1: 320x200, SCREEN 2:
640x200), Bresenham line drawing, midpoint circle, flood fill PAINT,
DRAW mini-language parser, and Sixel encoder with RLE. Replace all
graphics stubs with real implementations (PSET, LINE, CIRCLE, DRAW,
PAINT, COLOR, SCREEN, POINT). Fix AND/OR/XOR operator precedence
to be lower than relational operators. Add 13 classic test programs
(39 total). Bump version to 0.5.0.