v3 Bytecode Format (BC2)

Lesson, slides, and applied problem sets.

View Slides

Lesson

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 MAIN section
    • 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:

  • id must 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. END without 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 MAIN section is legal
  • instructions in MAIN execute when the program starts
  • MAIN can 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 1
  • LOAD x
  • CALL 2
  • MAKE_CLOSURE 3
  • MAKE_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/missing END)
  • 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

    Encode and decode a readable BC2 bytecode format.

    medium Sign in to access medium and hard problems
Join Discord