Bytecode Format: A Real Compile Artifact

Lesson, slides, and applied problem sets.

View Slides

Lesson

Bytecode Format: A real compile artifact

A bytecode text format is not just serialization—it is an ABI of your compiler pipeline.


Why BC1 matters

  • decouple compiler and VM implementation details,
  • support persistence/debugging,
  • validate compiler output shape before execution,
  • make linker/runner deterministic.

If format checks are weak, runtime bugs become integration bugs.


Shape contract

  • file starts with BC1 header,
  • zero or more FUNC name [params...] ... END blocks,
  • one MAIN ... END block,
  • blank lines and comments (#) are non-semantic.

Section order and names are part of identity for this pack.


Instruction line grammar

Opcodes may have:

  • no args: ADD, RETURN
  • integer arg: JUMP 12, PUSH_NUM 7
  • name arg: LOAD x, DEFINE_VAR y
  • mixed: CALL print 1
  • string arg: PUSH_STR "..."

A parser must validate both token count and arg types.


String and escaping discipline

PUSH_STR values must parse with quote-aware logic:

  • collect characters until matching quote,
  • decode \n, \t, \", \\,
  • reject bare newline/unterminated quote.

On encode, escaped characters must be re-emitted safely.


Determinism and canonicalization

Round-trip expectation:

  • Decode -> object should reject malformed structure,
  • Encode should emit stable deterministic order,
  • structural equivalence should preserve function names/order/sections and instructions.

If instruction ordering changes with equivalent content, diff tests become noisy and caches become unreliable.


Error model

Fail fast on first structural invalidity:

  • missing header,
  • unexpected end-of-section,
  • missing END,
  • unknown opcode,
  • malformed integer,
  • invalid string literal,
  • wrong arg count.

Bytecode as contract between stages

Compile -> Encode -> Decode -> VM is where pipeline correctness is hardened:

  • compile can be wrong,
  • runtime might still crash in later phases,
  • but decode catches representation mismatch early if format contract is strict.

Deep practice checkpoints (almost solved)

1) Basic sectioning

Input:

BC1
FUNC add a
LOAD a
RETURN
END
MAIN
PUSH_NUM 1
END

Expected:

  • one function add, one main section.

2) Missing section close

Input: BC1\nMAIN\nPUSH_NUM 1

Expected:

  • decode error for missing final END.

3) Unknown opcode

Input: BC1\nMAIN\nFOO\nEND

Expected:

  • decode error: unknown opcode.

4) String parse correctness

Input: BC1\nMAIN\nPUSH_STR "a\\nb\"c"\nEND

Expected:

  • decoded instruction string has newline and quote inside value.

5) Header requirement

Input without BC1

Expected:

  • decode reject malformed header.

6) Deterministic encode behavior

Given same decoded object twice

Expected:

  • encodings should be structurally equivalent (function/section order stable).

7) Mixed arg checks

Input: CALL\nCALL 1\nCALL f x

Expected:

  • arity checks for each bad call shape.

8) Comment skipping

Input includes: # header comment

Expected:

  • comments ignored and don't alter instruction stream.

9) Function param capture

FUNC add x y

Expected:

  • params x y captured as part of function identity in decode model.

10) Malformed line shape

Input: PUSH_STR unquoted

Expected:

  • decode error for unterminated or malformed string literal.

Module Items

  • Bytecode IO

    Encode and decode a readable BC1 bytecode format.

    medium Sign in to access medium and hard problems
Join Discord