The Baron reference

The tables. For the friendly walk-through, start with the guide; for zero-page allocation in depth, see Zero page allocation.

Contents

Command line reference

baron [-v | -vv] [--check] [-D <sym>=<expr>] [-p <path>] [--inf] [-o <image.ssd>] [--title <t>]
      [--opt <0-3>] [--cycle <0-99>] [--pad] [-log<n> <file>] [--symbols <file>] [--warn <n>]
      <source files>
Switch What it does
-v Print an assembly listing to stdout: emitted bytes against their source line (up to eight, then ...), each label's address alongside it, assignments as their evaluated values (source expression bracketed when it differs; list values cut after eight elements), macro expansions and includes followed through, PRINT output interleaved.
-vv The uncut -v: every emitted byte, wrapped eight per line with the address in the margin, and list values rendered whole.
-D <sym>=<expr> Predefine a symbol before assembly, e.g. -D DEBUG=TRUE -D version="1.0" (no spaces inside the assignment; repeat the switch for more). The expression gets the full evaluator and may forward-reference symbols the source defines. Applies to every source file on the line. See Predefined symbols.
--check Assemble and validate everything, write nothing - no binaries, no image, no logs.
-p <path> Write every saved section as a raw binary into the directory path (which must already exist; . for the current one). Nothing is written without this or -o.
--inf Write a .inf sidecar beside each raw binary, carrying its DFS name and load/exec addresses. Needs -p.
-o <image.ssd> Gather every saved section onto a DFS single-sided disc image. Only .ssd for now (.dsd, .adf and .uef are spoken for, later). May be combined with -p.
--title <t> The disc title, up to 12 characters. Needs -o.
--opt <0-3> The *OPT4 boot option: 0 none, 1 *LOAD, 2 *RUN, 3 *EXEC !BOOT. Needs -o.
--cycle <0-99> The catalogue cycle number. Needs -o.
--pad Pad the image out to a full 80-track disc (200K); every unused sector is filled with &E5, the single-density format filler. Without it the image is truncated after the last used sector. Needs -o.
-log<n> <file> Redirect PRINT channel n (0-9) to a file. Channel 0 otherwise goes to stdout; channels 1-9 are otherwise discarded.
--symbols <file> Write every source file's sections and resolved symbols to one JSON file: an entry per source file listing the files it read and its sections (name, parent, size, attributes as written), each section holding the symbols defined in it, grouped by kind (labels, assignments, defines, za_autos, loop_vars, params) with each one's value, source and line. Sorted, one symbol per line. See The symbol dump.
--warn <n> Show warnings up to level n. The default 1 shows the ordinary warnings; --warn 2 adds the opt-in audits (a store into the ZA_POOL at a fixed address); --warn 3 adds branches that cross a page boundary and so cost a cycle more when taken (plentiful in ordinary code, so they get a level of their own); --warn 0 shows errors only. Warnings never affect the exit code.
--help Print the switch summary.
--version Print the version and author information.

-p and -o are the two output gates, and neither is implied: a run given neither still assembles, reports and prints (-v, PRINT, -log<n> are unaffected), but the assembled bytes go nowhere and a warning says so. --check asks for exactly that on purpose, and stays quiet.

Anything that is not a switch is a source file, and each assembles independently - a fresh symbol table per file, diagnostics reported per file as it finishes. Diagnostics go to stderr in the file:line:col: error: message shape; success is silent.

The exit code is 0 exactly when every file assembled (warnings alone stay 0). Every file is assembled even after a failure - one run reports everything - but nothing is written (no binaries, no image, no logs) unless the whole batch succeeded.

Development builds also accept baron --test [group], which runs the unit test suite.

Keyword reference

Everything is case-insensitive. Statements are separated by newlines or :; comments run from ; or \ to the end of the line.

Labels, symbols and scopes

Syntax Meaning
.name Bind a label at the current address.
name = expr Bind a symbol to a value. Symbols are immutable: one name, one value, per scope. Prefix the name with @ (@next = 5) if the name clashes with a keyword.
{ ... } A scope. A label immediately before the brace names it; its symbols are reachable from outside as name.symbol. Anonymous scopes are truly private. Both braces double as statement separators, so LDX #8 {.loop DEX : BNE loop } RTS needs no extra colons.
.@ Bind an anonymous local label here. Referenced by @- / @+ (nearest behind / ahead, within the current scope).

Data

Syntax Meaning
EQUB v [, v...] Emit bytes. Numbers emit one byte (-255..255 accepted); strings emit their characters; lists and ranges flatten. EQUS is an alias - the two are interchangeable.
EQUW v [, v...] As EQUB, but each value is a 16-bit little-endian word.
EQUD v [, v...] As EQUB, but 32-bit.
SKIP n Reserve n bytes of zeroes. n can be at most &10000.
SKIPTO addr Pad with zeroes up to addr (the address only ever moves forwards). addr can be at most &10000, the top of memory.
ALIGN n Pad with zeroes to the next multiple of n, which must be between 1 and &10000.
INCBIN "file" Splice a binary file's bytes into the output. Path is relative to the including source file.
BITABS Emit a lone &2C (a BIT abs opcode): at run time its operand fetch swallows the next 2 bytes, so fall-through resumes past them while a branch straight to the next instruction executes it - the classic skip trick. The zero-page allocator models it (the swallowed instruction counts only on the branch-taken path); without the allocator it is trusted raw emission, exactly like EQUB &2C.
BITZP The 1-byte flavour: emit &24 (BIT zp), swallowing the next single byte.
BASIC ... ENDBASIC Emit an inline BBC BASIC program, tokenised exactly as BASIC 4 stores it (uppercase keywords only, &8D line-number encoding, &0D &FF terminator). Each line starts with a decimal line number 0-32767 and runs to the end of the physical line; between lines only blanks and comments are allowed. A { ending a line splices Baron statements into it up to a }, which resumes the same line: the spliced bytes go in untokenised, the tokeniser carries on as if they weren't there, and the splice opens no scope. Lines emit in written order and a record past 255 bytes (splices included) is refused.

Structure and control

Syntax Meaning
IF e / ELIF e / ELSE / ENDIF Conditional assembly. A dead branch emits nothing, binds nothing and computes nothing (no call, builtin or RND runs in it). Nests freely.
FOR v = seq ... NEXT Run the body once per element of a range or list, v bound to each element, each iteration in its own scope. An empty sequence runs zero times.
INCLUDE "file" Splice another source file in textually: its code emits here, its symbols bind here. Paths resolve relative to the including file.
MACRO name sig ... ENDMACRO Define a macro. The signature is parameter names, commas, and quoted literal tokens matched verbatim; one name may carry several overloads, matched by shape. An empty body forward-declares. Define before use.
FUNCTION name(params) = expr A pure function usable in any expression - one-liner form, or a multi-line body of local assignments, IFs, FOR ... NEXT loops and ASSERTs ending in a top-level = expr return. A local (parameters included) takes a new value at each assignment and can be read only once assigned; assigning a global's name makes a local that hides it, so a body changes nothing outside itself. A body FOR walks a list or bounded range as the statement does, its variable an ordinary local; there is no WHILE or BREAK, and the return is never inside a loop or an IF. Overloads by parameter count. Define before use. Recursion may nest 128 calls deep; loops have no limit.
PRINT [#n,] v [, v...] Write text during assembly (final pass only): values concatenated, one newline per statement, to channel n (default 0).
ERROR [v [, v...]] Report the message as an assembly error and fail the build; assembly carries on to find more.
ASSERT e [, v [, v...]] IF NOT(e) : ERROR v... : ENDIF in one statement. The message is evaluated only on failure; without one the error is "Assertion failed". Also a FUNCTION body statement, where a failure becomes the call's result.

Sections and output

Syntax Meaning
SECTION name [, attr = e ...] ... ENDSECTION A uniquely-named block of output owning its own bytes. Nesting is containment: at ENDSECTION a child's bytes are copied into its parent and the parent's address moves past them; a child with an explicit org is rephased (its labels resolve at the runtime address while its bytes land in the parent - the relocation workflow). A top-level section stands alone: the default section's address follows only its own bytes. Attributes are never inherited.
SECTION name ... ENDSECTION (again) Reopens a closed section, carrying on from its address so far; the piece's bytes join the section's own, wherever the piece is written. Top-level sections can always be reopened; a nested one only if it took no room in its parent (a virtual child of a real section, or a child with its own org inside a virtual one). A reopening takes no attributes and keeps the first line's, so that line must come first. A section cannot be reopened from inside itself.

Attributes Baron acts on: org (assembly address; default: continue the enclosing section - the default section starts at 0), filename (the request to save; an empty filename is a config error), load (default org), exec (default load), cmos (truthy enables the 65C02 instruction set for this section - see the note under Reserved names), guard (an address the section's emission must not reach; overrunning it is a non-halting error reporting the overshoot - checked at each ENDSECTION, so per piece of a reopened section), transform (the name of a FUNCTION, as a string: at ENDSECTION the section's bytes, as a list of numbers, are replaced by what it returns - a list of bytes, or a string - and that is what the parent receives; the section's labels keep their untransformed addresses. It runs once every byte is final, and a change of size sends the assembly round again until the sizes settle. Not on a virtual section, and a transformed section cannot be reopened), and virtual (truthy makes the section assign addresses but keep no bytes: it cannot be saved, and its code is ignored by the zero-page allocator. Inside a real section it takes no room, so it needs an org of its own. As a parent it is a memory map: it steps past each child that continues its address, while the children keep their own bytes and can be saved; a child with its own org takes no room in it). Other keys are carried through untouched.

The address attributes take the BBC's full 32-bit host addresses (&FFFFxxxx = the I/O processor, &0000xxxx = the second processor): load and exec keep the whole value for the catalogue, while org and guard apply their low 16 bits - the 6502's actual address - to the assembly.

The last byte of memory is &FFFF. A section may fill right up to it, but a byte placed past it is a non-halting error ("Program counter runs past &FFFF by N bytes"), reported once per section at the statement that went over.

A filename destined for a disc image follows DFS rules: an optional single-character directory prefix ("D.NAME"; default $), then a name of up to 7 characters.

Zero-page allocation

Syntax Meaning
ZA_POOL addrs Hand the allocator a pool of zero-page bytes: a comma-separated list of addresses and .. ranges. Its presence switches the feature on.
ZA_AUTO1 names Declare one-byte auto-allocated variables.
ZA_AUTO2 names Declare two-byte variables (pointer pairs).
ZA_AUTO n, names Declare n-byte variables (1-256).
ZA_UNREACHABLE Assert control cannot fall through to this point - a branch's dead arm, or the continuation of a never-returning JSR; that path is pruned.
ZA_CANCALL targets After a computed/self-modified JSR: the routines it may reach. Targets flatten like EQUB data, so a list-valued symbol works. Name your own code by label (an alias or label+n works too); a plain number landing on assembled code is refused.
ZA_CANJUMP targets After a computed/indirect JMP, a self-modified branch, or an RTS-dispatch: the labels it may land on, replacing any literal operand. Targets flatten like EQUB data, and follow ZA_CANCALL's label rule.
ZA_RETURN Declare the preceding jump/branch a return to this routine's caller (the inline-data trick's computed exit).
ZA_RETURNTO targets Declare where the preceding JSR resumes, replacing its fall-through (a data-consuming callee that resumes somewhere other than just past the data).
ZA_DISCARD vars Promise the named ZA_AUTO variables' current values are dead - later reads see only later writes. For arrays rebuilt via STA arr,X, whose writes prove nothing. Binds to the path it is written on; below a label it applies to every path through that point.
ZA_WIPE Promise that the sweep just before it has written the whole pool (the boot-time zero-page wipe): place it directly after the wipe loop. Every variable counts as freshly written from the marker, and the sweep's own fixed-base stores are not warned about. Binds like ZA_DISCARD: written inside a branch arm it stays on that arm.
ZA_INDEXEDBY values Declare the index values the register can hold at the indexed ZA_AUTO access just before it (var,X / var,Y / (var,X)). Ranges and lists flatten like EQUB data; each value 0-255. The access is then bounds-checked against the variable's width (refused if any declared index reaches outside it - the base itself may sit below the variable, as in var-4,X : ZA_INDEXEDBY 4..7) and the default-level unchecked-index warning goes quiet.
ZA_ENTRY Mark the routine it opens as an externally-called entry point (a reachability root). Any ZA_ENTRY replaces the default "each section starts a routine" presumption.
ZA_INTERRUPT Mark the routine it opens as an interrupt handler: a root whose variables are kept apart from the rest of the program.

The full story - liveness, footprints, sections, every error - is in Zero page allocation.

Reserved names

TRUE, FALSE and PI are reserved outright - they cannot name a label or symbol anywhere. Any other spelling is fair game wherever a name is defined: labels (.next, .clr), FOR variables, macro and FUNCTION parameters, ZA_AUTO names and -D defines may all share a spelling with a mnemonic, directive or macro, because references are read where an operand is expected, and no mnemonic, directive or macro name means anything there. The one exception is a plain assignment, whose name starts the statement - there the keywords win, so next = 5 will not parse. Prefix the name with @ to force it to read as a name: @next = 5 binds next, referenced bare (the C# idiom). Inside a FUNCTION body, a local's assignment starts its statement too, so the body keywords (IF, ELIF, ELSE, ENDIF, ASSERT, FOR, NEXT) cannot name locals. Macro and FUNCTION names stay restricted - they become keywords themselves, and a FUNCTION cannot take a builtin function's name (LO, REPLACE, WHERE, ...). All the NMOS 6502 mnemonics are recognised, plus the 65C02 extras (BRA, STZ, PHX, ...) - usable inside a section carrying cmos = TRUE; elsewhere the target is plain NMOS and a CMOS-only encoding is refused with its own message.

Expression reference

Values

Kind Examples
Number 42, 1.5, &FF or $FF (hex), %1010 (binary), 'A' (a character literal: 65). All numbers are one type.
Boolean TRUE, FALSE - what comparisons and the predicates return. Coerces to 1 / 0 in any numeric context ((x>5)*10, EQUB flag), so a boolean goes anywhere a number does; only AND/OR/EOR/NOT care about the difference (logical on booleans, bitwise on numbers, a mixed pair refused). Note: This is a breaking change from BeebAsm, which represents TRUE as -1, not 1. The switch --beebasm-true can be used to restore TRUE as -1.
String "hello" - write "" for a literal quote. A string is one value, like a number: broadcasting, list building (CONCAT, FLATTEN) and shape (RANK("abc") is 0) all treat it whole, and FOR won't walk one. Only the functions that work along a sequence - subscripts, LEN, REVERSE, FIND and LZ_PARSE's data - read its characters, giving back a string (or a position in one). There is no character type: one character is a one-character string.
List {1, 2, 3} - nestable, mixed types welcome, newlines allowed inside the braces. Nested equal-length lists act as higher-rank arrays; SHAPE/RANK report the axes all elements agree on (ragged lists keep only their uniform leading axes).
Range A compact list of consecutive integers - see Range forms.

Character literals

A character literal is exactly one character between single quotes, and it is simply a number: the character's code. It goes anywhere a number does - LDA #'A' loads 65, 'z'-'a' is 25, and EQUB 'h', 'i' emits two bytes.

Any character except a newline or the single quote itself may sit between the quotes, ';' and ':' included. There are no escape sequences, so write 39 for a quote. For the codes of a whole string, see CODES under Element-wise functions.

Range forms

Endpoints must be whole numbers, at most 2^53 either way (where numbers stop holding every integer); either or both may be any constant expression. .. binds looser than arithmetic and comparisons, so 0..n-1 needs no parentheses.

Form Meaning
a..b Inclusive at both ends. Direction is inferred: 5..1 is {5, 4, 3, 2, 1}.
a..<b Excludes the end. Ascending only; a..<b with a >= b (e.g. 5..<5) is the legal empty list {}.
a..b..c Stepped: b is the second element, fixing the step at b-a; c is a limit, not a promise (1..3..10 is {1, 3, 5, 7, 9}), though it must reach b (0..2..2 is {0, 2}; 0..2..1 is an error). Steps down too: 10..8..1 is {10, 8, 6, 4, 2}.
a..b..<c As above, excluding c. The < goes on the final separator only.
a.. / ..b / a..b.. / .. Unbounded: one or both ends left off. Not enumerable as data - used as subscript selectors, where the axis supplies the missing end (..b runs from the start, a.. to the end).

Operators, tightest first

Operators Meaning
x[...] Subscript - see Subscripts.
^ Power (right-associative).
-x +x Unary minus / plus.
* / DIV MOD << >> Multiply, divide, integer divide, modulo, shifts.
+ - Add, subtract. + also concatenates strings.
= == != <> < > <= >= Comparisons, yielding TRUE or FALSE. =/== and !=/<> are synonyms; strings compare too. A boolean compares against a number as 1 / 0, so 1 = TRUE holds.
AND Logical AND on two booleans (yielding a boolean); bitwise AND (32-bit) on two numbers. A mixed boolean/number pair is an error.
OR EOR Logical / bitwise OR and exclusive-OR, overloaded exactly as AND.
.. ..< Range construction.
<x >x ~x 6502-style low / high byte of the whole following expression: <start+1 is LO(start+1). ~x is the same shape, giving x as an uppercase hex string - 2, 4 or 8 digits, the narrowest that holds it (~10 is "0A", ~&123 is "0123", ~&123456 is "00123456"). No & prefix; the 32-bit pattern is what is formatted, so ~-1 is "FFFFFFFF". For decimal text, see AS_STRING.

Subscripts

x[sel, sel, ...] - one selector per axis, outermost first; fewer selectors than axes leaves the trailing axes whole (M[1] is a row; M[1][2] and M[1, 2] are the same element). Three selector kinds:

Selector Behaviour
Integer Picks one element and drops the axis. Out of range is an error.
Range Slices, keeping the axis. Forgiving: clipped to the axis, may come back empty. Unbounded ends take the axis bounds (L[..] is the whole list, L[3..] from index 3 on, L[0..2..] every other element); a descending range reverses (L[4..0]).
List Gathers exactly the named indices, in order, keeping the axis (L[{0, 4}]; L[{1, 1, 1}] repeats). Out of range is an error.

Ranges subscript via their elements ((100..200)[10] is 110). Strings are rank 1 and always yield a string: "hello"[1..3] is "ell", "hello"[4..0] is "olleh".

Broadcasting

Operators and element-wise functions map across lists and ranges, NumPy-fashion. The rules, in order:

  1. A range becomes its list of elements.
  2. A single value (a number, or a string) pairs with everything in the other side, however deep: {{1, 2}, {3, 4}} * 10 is {{10, 20}, {30, 40}}.
  3. Two lists of the same depth pair off element-wise - lengths must match ({1, 2} + {1, 2, 3} is a shape error), except that a length-1 list repeats: {1, 2, 3} + {10} is {11, 12, 13}.
  4. The shallower side is held whole and applied to each element of the deeper: a rank-1 list against a rank-2 one applies per row ({{1, 2, 3}, {4, 5, 6}} * {1, 0, 0} is {{1, 0, 0}, {4, 0, 0}}), and a column against a row is the outer product ({{1}, {2}} + {10, 20} is {{11, 21}, {12, 22}}).

The rules recurse, so nesting and ragged tails work: {1, {2, 3}} * 2 is {2, {4, 6}}. A string is a single value here, like a number: {"a", "b"} + "!" is {"a!", "b!"}.

Only operators and the element-wise functions broadcast. Every other function takes its arguments whole: LEN({{1, 2}, {3}}) is 2, not {2, 1}. The one exception is FIND's second argument, which maps. A user FUNCTION takes its arguments whole too, and maps over a list only when everything in its body does: sqr(0..15) is a 16-element list because x*x maps, but an IF needs one number or boolean, so a list condition is an error. WHERE is the element-wise choice that maps instead.

Element-wise functions

All broadcast; trigonometry is in radians.

Function Meaning
LO(n), HI(n) The low byte (bits 0-7) / the high byte (bits 8-15).
ABS(n) Absolute value.
INT(n), FLOOR(n) Round down (the two are synonyms).
ROUND(n) Round to nearest; halves go away from zero (ROUND(2.5) is 3, ROUND(-2.5) is -3).
TRUNC(n) Round toward zero.
CEIL(n) Round up.
SQRT(n) Square root.
SIN(n), COS(n), TAN(n), ASIN(n), ACOS(n), ATAN(n) Trigonometry.
LOG(n), LN(n), EXP(n) Log base 10, natural log, e^n.
NOT(x) Logical NOT on a boolean (NOT(TRUE) is FALSE); bitwise complement (32-bit) on a number.
RND(n) A random integer in 0..n-1. RND(REPEATED(k, n)) makes k draws. Deterministically reseeded each pass, so it converges.
CODES(s) A string's character codes as a rank-1 list: CODES("AB") is {65, 66}, CODES("") is {}. The bridge from text to arithmetic (a lone character is simpler as a character literal, 'A'). The result broadcasts like any list: CODES(s) - ' ' offsets every code.
AS_STRING(n) A number as decimal text, exactly as PRINT shows it: AS_STRING(42) is "42", AS_STRING(1.5) is "1.5", AS_STRING(TRUE) is "1". For hex, use ~n. A ZA_AUTO address is refused, since its length as text isn't known until it's allocated (PRINT v shows it).
WHERE(mask, a, b) The element-wise IF: for each value in mask (a boolean, or a number with non-zero for true), the matching value of a where it is true and of b where it is false. The three arguments broadcast together, as an operator's two do: WHERE({1, 300} > 255, 255, {1, 300}) is {1, 255}. Only picked values matter - an error in one it passes over (a division by zero, a name not yet defined) is dropped, as in an IF arm not taken - so WHERE(x = 0, 0, 1/x) is safe.
AS_NUMBER(s) The number a string spells, written as a number literal is written in source: an optional - or +, then decimal, &/$ hex, % binary or a character literal - AS_NUMBER("42") is 42, AS_NUMBER("-&FF") is -255. The whole string must be that one number, with no blanks around it; anything else is an error naming the string (Not a number: '12x'). So hex from ~ needs its & back: AS_NUMBER("&" + ~n) is n.

String, search and type functions

Function Meaning
CHR(x) The inverse of CODES: every numeric leaf of x (flattened; ranges enumerate) becomes one character of a single string - CHR(72) is "H", CHR({72, 73}) is "HI", CHR(CODES(s)) is s. Codes must land in 0..255; fractions truncate. Doubles as the way to join a list of codes into one string.
FIND(x, v [, otherwise]) The index of v's first occurrence in x (a list, range, or string - a string is searched for a substring: FIND("hello world", "world") is 6). The needle broadcasts - the one argument of a whole-value function that does - so FIND(from, CODES(s)) is a same-shape list of indices; a needle can therefore never itself be a list-valued element, nor a run of elements. A miss is a hard error naming the needle, unless otherwise is given: then a miss gives otherwise (per needle, when the needle maps). otherwise only matters on a miss, so ERROR("...") there makes a custom message.
REPLACE(x, old, new) x with every occurrence of old replaced by new, left to right, never overlapping, and never looking inside what it has put in: REPLACE("aaa", "aa", "b") is "ba". In a string, old and new are strings. In a list (or range) they are runs of elements, read as CONCAT reads its arguments - a list gives its elements, any other value is one element - so REPLACE(bytes, &0D, {&0D, &0A}) adds a line feed after every carriage return; wrap a list to mean one list-valued element ({{1, 2}}). Nothing found leaves x unchanged; an empty old is an error.
IS_STRING(x), IS_NUMBER(x) TRUE or FALSE for the value as a whole - a list is neither (test list-ness with SHAPE(x) != {} or RANK(x) > 0). A boolean counts as a number (it coerces to one). A still-undefined symbol defers rather than answering.
ERROR(v, ...) The ERROR statement as a value: an error carrying the concatenated message (strings raw, everything else as PRINT shows it), reported wherever the value ends up used. Made for guarding FUNCTION bodies: r = ERROR("bad width: ", w) behind an IF.

List functions

Function Meaning
LEN(x) Length of the outermost axis (elements, characters, or range count).
SHAPE(x) The axis lengths as a list, outermost first; the axes all elements agree on (SHAPE({{1,2},{3,4,5}}) is {2}). {} for a scalar; a range counts as the rank-1 list it stands for (SHAPE(0..9) is {10}; unbounded errors); empty axes are real lengths (SHAPE({}) is {0}, SHAPE({{}}) is {1, 0}).
RANK(x) The number of axes (0 for a scalar; 1 for any range, unbounded included).
REPEATED(n, v), FULL(n, v) A list of n copies of v (two names, one function).
FLATTEN(x) Every leaf, in order, as one flat list.
CONCAT(a, b, ...) Join along the outermost axis: each list (or range) argument contributes its top-level elements, each scalar (strings included) itself - so a scalar and a one-element list are interchangeable. Not a flatten: nesting inside elements survives (CONCAT({1,{2,3}}, 4) is {1,{2,3},4}). To append a list as a single element, wrap it: CONCAT(xs, {{3,4}}).
ZIP(a, b, ...) Equal-length lists into a list of tuples: ZIP({1,2},{3,4}) is {{1,3},{2,4}}.
REVERSE(x) The outermost axis reversed (works on strings too).
SORT(L [, key...]) Sort ascending by key, the keys all numbers or all strings (strings in character-code order, as < orders them); extra arguments subscript each element to find its key (SORT(L, 0) sorts on first items).
SUM(x [, axis]), PRODUCT(x [, axis]) With no axis, fold every leaf to one scalar (SUM({{1,2,3},{4,5,6}}) is 21; SUM({}) is 0). With an axis (0 = outermost), collapse just that one: axis 0 folds rows together ({5, 7, 9}), axis 1 folds within each row ({6, 15}). SUM is + folded, so it joins strings: SUM({"ab", "cd"}) is "abcd", and SUM(rows, 1) joins each row. Strings and numbers don't mix.
MIN(x [, axis]), MAX(x [, axis]) Smallest / largest, same axis rules; strings compare as < compares them (MIN({"pear", "apple"}) is "apple"). MIN({}) errors - no identity.
DEFINED(name) TRUE if the symbol resolves (yet), FALSE if not - the one function happy to receive an undefined name.

Bit and compression functions

The building blocks of a section transform that compresses. A field of n bits holding v is written as the single number 2^n + v (the top set bit marks the width).

Function Meaning
BITLEN(x) How many bits x's integer part needs: floor(log2 x) + 1, exactly, and 0 below 1. Broadcasts. A field's width is BITLEN(field) - 1.
BITPACK(fields) The fields (flattened, as for EQUB) concatenated into a list of bytes, each field most significant bit first and each byte filled from its top bit; the last byte is padded with zero bits. A field is a whole number from 1 (no bits) to 2^53 - 1 (52 bits).
LZ_PARSE(data, literal_run, literal, match_run, length, offset [, repeat]) The cheapest way to write data (a list of bytes, or a string) as runs alternating literals and matches - literals first, each run's count before its contents, a match copying length bytes from offset back. The other arguments are cost tables: lists of bits by value written (a run's count, a literal byte, a match run's count, a length, an offset), a negative entry meaning impossible. offset may be a list of tables, one per match length from 1, the last serving every longer match. The optional repeat table prices a repeat match by its length: the first match of a match run may copy from the previous match's offset again. repeat may instead be a pair {lengths, after}, after giving by the count of the literal run before what any match there pays, negative where no repeat may follow (Exomizer: {-1, 1}). Returns {bits, runs}, each run {0, bytes} or {1, {offsets, lengths}}, a repeat having offset 0. Exact, given: when match runs' counts all cost the same, nothing more (every offset is tried); otherwise, counts and offsets never cheaper as they grow; and, with repeats, literal-run counts (with what a match after them pays) and repeat lengths likewise.

Constants

Constant Meaning
TRUE, FALSE The boolean values. Coerce to 1 and 0 in numeric contexts.
PI 3.14159...
*, P% The current assembly address - of this statement, so JMP * is jump-to-self and EQUB *,*,* advances per byte. Read-only.
@-, @+ The nearest .@ local label behind / ahead, within the current scope.

Your own FUNCTION names join the table as they are defined, callable as name(args).

Version history

See the GitHub releases page for what changed in each version.