Oliver VieBrooks

6basic / 6basic reference

Contents

SixBASIC Reference

A complete, user-facing reference for the SixBASIC Commodore 64 BASIC cross-toolchain — every command-line option and every {...} source enhancement as currently implemented.


1. Overview

SixBASIC compiles plain-text BASIC source (.bas / .txt / .lbl) into a C64 .prg, and decompiles a .prg back to text. The source may be ordinary CBM BASIC 2.0 plus the enhancements in §3 — all resolved at compile time, leaving a clean, runnable .prg. The model is edit in rich text, emit .prg many times.

Pipeline (high level): source loader (includes, parser variables, conditional compilation, {asm}, numeric/string expansion) → tokenizer (BASIC → bytes, or the turbo pointer tokenizer) → .prg. Errors are reported with file name and line number.


2. Command line

6basic [subcommand] [options] <infile> [outfile]

A subcommand fixes one output format; the positional outfile names it:

Subcommand Action
bas2prg Tokenize .bas/.txt/.lbl → .prg
prg2bas Detokenize .prg → .bas text (output defaults to .bas)
listbasic Detokenize .prg → listing on the console (stdout)
dumpbasic Hex dump of the loaded image to the console

With no subcommand the action is auto-detected from the input extension: .bas / .txt / .lbl tokenize to .prg; a .prg lists to the console (or, given an outfile, detokenizes to that .bas). The installer also adds wrapper commands bas2prg/prg2bas/listbasic/dumpbasic that each prepend their verb.

Output formats (repeatable)

A subcommand fixes a single output format. To emit several outputs in one run, omit the subcommand and use these repeatable format flags instead; you may not combine a positional outfile with format flags.

Flag Produces
-prg[:name] Tokenized PRG (with 2-byte load address)
-bin[:name] Tokenized image without the load address
-hex[:name] ASCII hex dump (address-prefixed)
-txt[:name] Detokenized BASIC text
-lbl[:name] Detokenized text with line numbers replaced by labels

Output naming (the :name part):

Form Result
-prg <input>.prg
-prg:foo foo.prg
-prg:foo.x foo.x
-prg:foo. foo (no extension)
-prg:. <input> base name, no extension
-prg:con write to the console (text formats only)

Outputs are placed in the input file's directory unless the name includes a path.

Options

Option Effect
-def:<n[=v]> Define a parser variable (for {ifdef}/{usedef}); repeatable
-combine Fold {asm:sys} regions into one .prg (default: a sidecar .prg per region)
-crunch Remove unneeded spaces when tokenizing
-rem Remove REM statements (accepted, not yet implemented — warns)
-turbo Tokenize as Turbo/pointer BASIC, no patch injected (§4)
-turbo-data Turbo + self-installing DATA preamble
-turbo-split Turbo + separate .patch.prg file
-pref:<file> Apply a directives-only preface before the input (§3.10)
-labels:<file> Write the resolved label=line map after a successful compile
-uselabels:<file> Read external label=line defs to resolve cross-file {:label} refs
-loadext:<ext> Force the input type when the extension is missing/unknown
-notbasic Treat a loaded .prg as non-BASIC (disables -txt/-lbl)
-range:<a>[-<b>] Limit -hex output to an address window (decimal or $hex)
-keycase Detokenize keywords in lowercase (default uppercase)
-varcase Detokenize variable letters in lowercase
-verbose[:list] Show info-level diagnostics; :list echoes each source line
-ovr, -f Overwrite existing outputs (never the input file)
-h, -help, -? Show help (also shown with no arguments)

Examples:

6basic game.bas                             # game.bas -> game.prg (auto)
6basic bas2prg game.bas                     # same, explicit subcommand
6basic listbasic game.prg                   # list a PRG to the terminal
6basic prg2bas game.prg game.bas            # detokenize a PRG to text
6basic game.bas -prg:build/game -hex        # PRG + hex dump (multi-output)
6basic bas2prg game.bas -def:DEBUG          # conditional build
6basic bas2prg demo.bas -combine            # fold {asm:sys} ML into one .prg

Cross-file labels:

6basic bas2prg library.bas library.prg -labels:library.lbl    # export labels
6basic bas2prg main.bas main.prg -uselabels:library.lbl       # import labels

3. Source language

3.1 Line numbers, labels, and renumbering

Lines may be numbered (10 PRINT) or label-driven. A label marks a branch target and is referenced where a line number would go:

{:loop}
10 PRINT "HELLO"
20 GOTO {:loop}

Renumbering directives (positional):

Directive Effect
{renumber} Renumber the whole program (default from 0, step 1)
{number:n} Force the next line's number (must exceed the previous; 0–63999)
{step:n} Set the increment
{nice:n} Round the next line number up to a multiple of n
{assign:Label=n} Resolve {:Label} to n even if no such line exists

Label references follow the new numbers; literal numeric branches (GOTO 100) are not rewritten — use labels as branch targets (same caveat as {crunch}).

3.2 Comments

A single quote ' begins a comment to end-of-line, stripped from the .prg:

GOSUB {:init}   'this comment is removed
'standalone comment line, removed too

A ' is kept (not a comment) inside quoted strings, and after REM/DATA (where it is literal data). REM works as on a C64.

3.3 String codes (PETSCII)

Inside quoted strings, write control/color/graphic characters as readable names; they convert to the correct PETSCII byte.

Repetition: append :N to repeat — {down:4}, {right:10}. On detokenize, runs of the same code collate back into {name:N}.

Raw bytes: insert any byte by value — {$ff} (hex, any case), {%01100001} (binary), {97} (decimal).

Virtual modifier keys: inside a string, {shft}/{shift} and {ctrl}/{control} transform following A–Z into the shifted/control glyph until {lift} (or another modifier / end of line) — e.g. {shft}A → spade. ({cmdr} is recognized but not yet mapped.)

Custom glyphs: {quoter:$61="spade"} defines a name ({spade}) for a byte.

Alpha modes & letter-range bytes. Letters inside quotes follow the active {alpha:<mode>} (positional): default (the SixBASIC case-swap — type lowercase, get C64 uppercase), ascii (no conversion), upper, lower. Raw-byte / glyph / {shft} results in the letter range $41–$7A are subject to the alpha mode like any quoted character; use {alpha:ascii} to insert an exact byte.

3.4 Replacement macros

Simple text substitution, defined once:

{#SCREEN|1024}
{#COLRAM|55296}
POKE {#SCREEN},1 : POKE {#COLRAM},0

3.5 Parser variables & conditional compilation

Resolved by the source loader before tokenization:

{def:DEBUG}              ' define (empty value)
{def:LEVELS=8}           ' with a value
{undef:DEBUG}            ' remove
X={usedef:LEVELS}        ' insert a value inline

{ifdef:DEBUG}            ' include block only if defined
30 PRINT "DEBUG"
{else}
30 PRINT "RELEASE"
{endif}

Numeric conversion: {$:hex} and {%:binary} insert the decimal value — e.g. POKE 53280,{$:0F} → POKE 53280,15. (Distinct from the raw-byte {$ff} / {%..} string codes, which the loader leaves alone.)

3.6 Supervariables

Readable long names mapped to real 2-character C64 variables:

{var:LIVES=lv}
{var:PLAYERNAME$=pn$}
10 {var:LIVES}=3 : PRINT {var:LIVES}

Each use is written {var:Name}. Undefined supervariables are diagnosed.

3.7 Custom tokens

Add, replace, or remove single-byte BASIC tokens ($80–$FF) for this compile:

{tokenizer:$cc="GRAB",$cd="DROP"}   ' add two custom keywords
{tokenizer:206="SPLAT"}             ' decimal value also accepted
{tokenizer:$99=""}                  ' remove a token (here, PRINT)

Values separated by , or ;. On detokenize, a byte with no known keyword renders as {$xx} (custom tokens round-trip as hex unless the detokenizer is given the same mapping, e.g. via a preface — §3.10).

3.8 File inclusion

{addsearchpath:lib,../shared}   ' add include search dirs (relative to this file)
{include:macros.bas}            ' splice a file's contents here
{uses:macros.bas}               ' like include, but only once (include-once)

Resolution order: the including file's directory → the input directory → each search path. {include} may repeat; circular includes are detected, nesting is capped at 50 levels, and {uses} skips an already-included file. Includes interleave with conditionals (an {include} in an inactive branch is skipped), and diagnostics from an included file name that file.

3.9 Build revisioning & system variables

{buildrev:build.rev}            ' read a counter into {__BuildRev}
10 PRINT "BUILD ";{usedef:__BuildRev}

{buildrev:<file>} reads an integer from the file into __BuildRev; after an error-free build the counter is incremented (error if it exceeds 65535). Predefined system variables (quoted string values): {__BuildDate} ("YYYY-MMM-DD"), {__BuildTime} ("HH:MM:SS"), {__BuildRid64}/{__BuildRid32} (per-run random hex IDs), {__SixBASIC} (defined in BASIC mode).

3.10 Diagnostics directives & escaping

{info:msg} (shown only with -verbose), {warning:msg}, {error:msg}, and {fatal:msg} (stops processing) emit through the diagnostics channel. A leading tick escapes a directive: {'def:X} is emitted literally as {def:X}.

3.11 Inline assembly

{asm[:mode]} … {endasm} blocks are written in 6asm/DASM syntax (processor 6502, org, byte, label:) and assembled by the external 6asm tool. {sym:Name} resolves to a symbol's 5-digit address for SYS/PEEK/POKE.

10 FOR I=0 TO {sym:Size}-1:READ B:POKE {sym:Start}+I,B:NEXT
20 SYS {sym:Start}
{asm:data}
        processor 6502
        org $c000
Start:  lda #$00
        sta $d020
        rts
{endasm}
Mode Behavior
{asm:data} The assembled bytes become DATA statements (install via READ/POKE)
{asm:sys[:$addr]} A separate region at a fixed org; written as a sidecar .prg, or folded in with -combine
{asm:inline} Deferred (edge case) — splice ML into the BASIC stream; use data/sys instead

3.12 Preface files

-pref:<file> applies a directives-only file to the compile context before the main input — useful for shared config: {def}, {tokenizer}, {var}, {keycase}/{varcase}, {addsearchpath}. A preface that emits code is an error. A preface's {tokenizer}/{keycase} carry into detokenization (so you can list a .prg that uses custom tokens).

3.13 Compiler directives

Directive Effect
{loadaddr:<addr>} Set the load address (decimal or $hex; default $0801)
{crunch} Merge consecutive short lines with : (≤250 chars)
{turbo} Tokenize as Turbo/pointer BASIC (§4)
{debug} Emit intermediate debug dumps
{renumber} Renumber the program (§3.1)
{removerem} Accepted, not yet implemented — warns

4. Turbo mode

Turbo (pointer) BASIC replaces GOTO/GOSUB/THEN line-number lookups with direct 3-byte memory pointers, skipping the interpreter's line search at run time. Enable with {turbo} or the -turbo* flags. This format is non-standard and not editable on a stock C64; the -turbo-data/-turbo-split deployments install the required ML patch. Detokenizing a turbo .prg resolves the pointers back to line numbers (prefixed ;; TURBO PRG).


5. Diagnostics

Messages are reported as <severity>: [file (line)] message, followed by a ==== N Errors; N Warnings ==== summary. Compilation that produces an error writes no output. Example:

error: [game.bas (12)] Undefined label {:loop} in: GOTO {:loop}
==== 1 Errors; 0 Warnings ====

6. Brace-namespace cheat sheet

Different {...} forms mean different things — keep them straight:

Form Meaning
{:Name} Label (define / reference)
{#Name\|text} / {#Name} Replacement macro
{def:}/{usedef:}/{var:} Parser variable / supervariable
{$ff} {%bin} {nnn} Raw PETSCII byte (string code)
{$:hex} {%:bin} Preprocessor numeric → decimal text
{sym:Name} Assembly symbol address
{down} {red} {shft} … String/cursor codes & modifiers

7. Known limitations / not yet implemented