Contents
- 1. Overview
- 2. Command line
- 3. Source language
- 3.1 Line numbers, labels, and renumbering
- 3.2 Comments
- 3.3 String codes (PETSCII)
- 3.4 Replacement macros
- 3.5 Parser variables & conditional compilation
- 3.6 Supervariables
- 3.7 Custom tokens
- 3.8 File inclusion
- 3.9 Build revisioning & system variables
- 3.10 Diagnostics directives & escaping
- 3.11 Inline assembly
- 3.12 Preface files
- 3.13 Compiler directives
- 4. Turbo mode
- 5. Diagnostics
- 6. Brace-namespace cheat sheet
- 7. Known limitations / not yet implemented
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}
{:Name}defines a label (on its own line, attached to the next numbered line) and references it. Labels resolve to real line numbers at compile time.- A numeric "keeper" label (
{:140}) doubles as a renumbering hint and is what-lblemits, so an existing program's numbers survive a.prg → .lbl → .prgcycle. - Unnumbered lines are auto-numbered.
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.
- Colors:
{black}{white}{red}{cyan}{purple}{green}{blue}{yellow}{orange}{brown}{light red}/{lt red}, and the grey/gray set ({gray1}..{gray3},{grey 1}..{grey 3},{dark gray},{light gray},{light green},{light blue}). - Cursor:
{up}{down}/{dn}{left}/{lt}{right}/{rt}{home}{clear}/{clr}. - Editing:
{insert}/{inst}{del}/{delete}/{bksp}. - Reverse / case:
{reverse on}/{rvs on}{reverse off}/{rvs off}{uppercase}/{upper}{lowercase}/{lower}{enable_shift}{disable_shift}. - Control / special:
{stop}/{runstop}{shift return}/{shft ret}{shift space}/{shft space}{space}{return}{pi}. - Function keys:
{f1}–{f8}. - Glyphs:
{pound}/{british pound}{up arrow}/{^}{back arrow}/{left arrow}.
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–$7Aare 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}
-def:NAME[=value]is the command-line form of{def}(repeatable).- Conditional blocks do not nest; a missing
{endif}, stray{else}/{endif}, or duplicate{else}are diagnosed.
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
{asm:inline}placement (edge case; needs two-pass layout + emulator verification).{removerem}/-rem(accepted but a no-op; warns).{cmdr}virtual modifier (the C= graphics are a non-linear table).{crsrcodes}/{crsrcount}and scoped{crunch:on|off}/{autospace}switches.- casm-only mode (
.asminput),-sym/-lstassembler outputs. .d64read/write, and 6pack packing hand-off.- A
'afterDATA/REMis kept in the.prg, but the comment stripper still has one raw-text edge (tracked as D6) pending the line lexer.