Files
akbasic/docs/01-introduction.md
Andrew Kesterson 342e4c07da
Some checks failed
akbasic CI Build / cmake_build (push) Successful in 3m2s
akbasic CI Build / sanitizers (push) Successful in 3m52s
akbasic CI Build / coverage (push) Failing after 3m24s
akbasic CI Build / akgl_build (push) Failing after 20s
akbasic CI Build / mutation_test (push) Has been cancelled
Execute every documented example as a test
docs/ and README.md carry 85 fenced blocks. Every one was checked by hand
exactly once, when it was written, which is not a standard that survives a
changing interpreter -- and four were already wrong: two transcripts showing a
leading space PRINT does not emit, akbasic_TextSink in README.md missing the
two members it had grown hours earlier, and FILTER's refusal quoted with
wording the code does not use.

tests/docs_examples.sh reads a fence-tag vocabulary and runs what it finds.
BASIC programs and transcripts run and are byte-compared against an `output`
block; C snippets compile with -fsyntax-only against the real include path,
which CMake writes out because it is transitive through akerror, akstdlib and
akgl; shell blocks run in a sandbox. Anything that would reconfigure the build
tree, hit the network or re-enter the suite is tagged norun with the reason in
MAINTENANCE.md, and the two cmake blocks stay hand-maintained by decision.

An untagged block is a failure rather than a default, and the pass line
reports what it executed by kind. Both exist because the way a harness like
this dies is by quietly matching nothing and passing -- which it duly did on
the first CTest run, where a generator expression evaluating to nothing still
contributed an empty argument that the script read as a filename. The count is
what caught it.

The excerpt check earns its own mention: a block tagged
`c excerpt=include/akbasic/sink.h` must still appear in that header, comments
and whitespace ignored. Compiling it would only redefine the type, so a
compile check could not have found the stale struct, and did not.

Registered as the CTest case docs_examples in both configurations. Fixing the
four wrong examples turned up two interpreter defects, fixed in the previous
commit and recorded in TODO.md section 8.

MAINTENANCE.md is new: the fence-tag reference, what to do when the case
fails, and the conventions that until now only existed inside source comments
-- the three test lists and how two of them invert "passed", the sorted verb
table, that a golden file is never edited to suit this interpreter, and that a
fix gets mutation-checked with a file copy rather than git checkout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 22:41:36 -04:00

2.7 KiB

1. Introduction

What akbasic is

A BASIC interpreter written in C, styled after Commodore BASIC 7.0 and Dartmouth BASIC. It does three things:

  • Runs a program from a file. basic program.bas loads it, runs it, and exits.
  • Gives you a prompt. basic with no arguments is a REPL: type lines with numbers to build a program, type verbs without numbers to run them immediately.
  • Links into a program as a library. A game can embed the interpreter, hand it a script, and step it a frame at a time. That is the reason for most of the design decisions you will notice.

It is a rewrite of an earlier Go implementation, which is kept only as a reference for questions about semantics. Its acceptance corpus is checked in here and runs on every build.

What akbasic is not

It is not an emulator. There is no 6502, no VIC-II, no SID, no 1541 and no bank-switched memory. Verbs that only make sense against that hardware are either reinterpreted for a modern machine — and Chapter 13 says exactly how — or refused by name with the reason. Nothing is silently ignored.

It is not byte-compatible with a C128. Error numbers are not Commodore's, floating point is IEEE double rather than Commodore's five-byte format, and a handful of statements parse differently. Again: Chapter 13.

Two builds

The default build has no dependency on SDL and no graphics, sound, sprites or windowed text. Everything else works, and the whole test suite runs on a machine with no SDL installed at all.

cmake -S . -B build
cmake --build build

The SDL build adds a window, the Commodore font, and the graphics, sound and sprite devices. It needs libakgl, which is vendored as a submodule.

git submodule update --init --recursive
cmake -S . -B build-akgl -DAKBASIC_WITH_AKGL=ON
cmake --build build-akgl

A verb that needs a device the build does not have does not crash and does not lie. It reports itself by name:

10 DRAW 1, 0, 0 TO 100, 100
? 10 : RUNTIME ERROR DRAW needs a graphics device and this runtime has none

That is the same message an embedded host sees when it deliberately withholds a device — a game may want a script that can print but not draw.

Running the tests

ctest --test-dir build --output-on-failure

The suite includes the original Go implementation's acceptance corpus, byte-compared, plus this project's own tests for everything the corpus does not reach.

Where to go next

Chapter 2 gets a program running. If you already write BASIC 7.0, read Chapter 13 first — it is short, and it will save you the three or four surprises that would otherwise find you one at a time.