v3 Bytecode Format (BC2)
Lesson, slides, and applied problem sets.
View SlidesLesson
v3 Bytecode Format (BC2)
Why this module exists
From v3 onward, modules and closures need an executable artifact that preserves function identity and init flow. BC2 is the textual contract used by this pack’s compiler/linker/runtime pipeline.
1) BC2 surface syntax
A minimal valid BC2 file has:
- required magic header line:
BC2 - zero or more function sections:
FUNC <id> <name> [param1 param2 ...]- instruction lines
END
- one
MAINsection- instruction lines
END
Example:
BC2
FUNC 0 add x y
LOAD x
LOAD y
ADD
RETURN
END
MAIN
PUSH_NUM 1
PUSH_NUM 2
CALL 2
END
Comments and blank lines are ignored for parsing.
2) Function section contract
For each function section:
idmust be a non-negative integer- function name may be present as identifier
- parameters are ordered and preserved for arity checks
- all function body opcodes emit into that function’s instruction list
The parser should reject:
- duplicate function ids
- duplicate
(id, name)assumptions that conflict with symbol expectations - invalid section nesting (e.g.
ENDwithout open section)
id values are stable handles across linker rewrite and execution.
3) MAIN section contract
MAIN is top-level startup code for a module.
- only one
MAINsection is legal - instructions in MAIN execute when the program starts
MAINcan still legitimately be empty
If encoded module has no MAIN, compiler/linker should raise deterministic decode error.
4) Instruction encoding rules
BC2 uses whitespace tokenized lines:
- mnemonic first
- optional integer immediates as later tokens
Examples:
PUSH_NUM 1LOAD xCALL 2MAKE_CLOSURE 3MAKE_MAP 2
CALL arity remains part of BC2 syntax, not metadata.
5) Deterministic decoding and validation
A robust decoder should validate:
- all ids are parseable integers
- opcode arguments satisfy expected count and type (numeric/string where required)
- there are no unknown opcodes
- sections are well-formed and fully terminated by
END
A practical decode invariant: encode(decode(text)) should preserve logical bytecode shape and section order for stable snapshots.
6) BC2 errors as stable diagnostics
Helpful classes:
- malformed header
- duplicate function IDs
- unknown opcode
- bad argument type
- section mismatch (
END/missingEND) - missing
MAIN - instruction outside any section
Stable error strings make golden tests precise.
7) Why BC2 at all
This is not “just serialization.” BC2 is the contract that enables:
- compile-vs-runtime decoupling
- linker function rebasing
- repeatable roundtrip tests
- readable failing artifacts
8) Practice checkpoints (almost solved)
1) Valid minimal program + Construct a BC2 with MAIN that pushes 1, pushes 2, ADD, and returns through implicit top-level behavior. Expected: parser accepts and runtime can execute deterministically.
2) Missing main + BC2 with only functions and no MAIN Expected: decode error for missing MAIN.
3) Duplicate function ID + FUNC 0 a ... and later FUNC 0 b ... Expected: decode-time duplicate-id diagnostic.
4) Unclosed section + FUNC 0 ... without END Expected: decode-time structure error.
5) Wrong opcode arity + CALL with non-numeric argument Expected: argument-type/parse error for opcode immediate.
6) Section order + MAIN ... END FUNC 1 ... after main Expected: parse error if format disallows extra sections after MAIN.
7) Deterministic diff + Re-emit from parse tree should keep function and main order unchanged.
Module Items
Bytecode IO v3