Classroom Glossary Public page

Lab 12: Compiler III — Multi-File Compilation and OS Library Calls

440 words

Week: 12
Points: 20
Time: ~5 hours
Deliverable: toolchain/compiler/compiler.py (multi-file) + Pong end-to-end + custom program + diary/week-12.md


What you ship

  • toolchain/compiler/compiler.py — multi-file driver
  • build/vm/Pong/ — three VM files from compiling the Pong directory
  • build/bin/pong.bin — linked Pong binary
  • compiler/week-12/MyProgram.vl — your own VirtusLang program (Lab 12.4)
  • build/vm/MyProgram/MyProgram.vm — compiled output
  • diary/week-12.md

Lab 12.1: Write the multi-file compiler driver

Extend toolchain/compiler/compiler.py to handle directories:

#!/usr/bin/env python3
"""compiler.py -- VirtusLang multi-file compiler."""
import sys
from pathlib import Path
from tokenizer import Tokenizer
from parser import Parser
from codegen import CodeGen

def compile_file(src_path: Path, out_dir: Path):
    source = src_path.read_text()
    tok    = Tokenizer(source)
    tree   = Parser(tok).parse_class()
    gen    = CodeGen()
    gen.compile_class(tree)
    out_path = out_dir / src_path.with_suffix('.vm').name
    out_path.write_text('\n'.join(gen.output) + '\n')
    print(f"  {src_path.name} -> {out_path.name} ({len(gen.output)} VM lines)")

def main():
    if len(sys.argv) < 2:
        print("Usage: compiler.py <source.vl | source-dir> [-o output-dir]")
        sys.exit(1)
    src     = Path(sys.argv[1])
    out_dir = Path(sys.argv[sys.argv.index('-o') + 1]) if '-o' in sys.argv else (
        src.parent if src.is_file() else src
    )
    out_dir.mkdir(parents=True, exist_ok=True)
    sources = sorted(src.glob('*.vl')) if src.is_dir() else [src]
    print(f"Compiling {len(sources)} file(s) -> {out_dir}/")
    for s in sources:
        compile_file(s, out_dir)

if __name__ == '__main__':
    main()

Verify by compiling a two-class directory and confirming that two .vm files are produced.


Lab 12.2: Compile and link Pong

A three-class Pong program is provided in compiler/week-12/Pong/:

  • Pong/Main.vl — entry point; creates PongGame and calls run
  • Pong/PongGame.vl — game logic; uses Screen, Output, Keyboard, GamePad
  • Pong/Ball.vl — ball object; uses Math.abs, Screen.drawRectangle

Run the full pipeline:

# Step 1: Compile all three classes
python3 toolchain/compiler/compiler.py compiler/week-12/Pong/ -o build/vm/Pong/

# Step 2: Translate each VM file to assembly
mkdir -p build/asm/Pong
for f in build/vm/Pong/*.vm; do
    python3 toolchain/vm-translator/translator.py "$f" \
        -o "build/asm/Pong/$(basename ${f%.vm}.s)"
done

# Step 3: Assemble each .s file
mkdir -p build/obj/Pong
for f in build/asm/Pong/*.s; do
    python3 toolchain/assembler/asm.py "$f" \
        -o "build/obj/Pong/$(basename ${f%.s}.vof)"
done

# Step 4: Link with Virtus OS stubs
python3 toolchain/linker/linker.py \
    build/obj/Pong/*.vof \
    virtus-os/*.vof \
    -o build/bin/pong.bin

sha256sum build/bin/pong.bin

Record the SHA-256 hash in diary/week-12.md.


Lab 12.3: Spot-check PongGame.vm

Open build/vm/Pong/PongGame.vm and locate the code generated for one method of your choice. Verify:

  1. Each method call to an OS service uses the correct argument count from OS_SIGNATURES
  2. Object construction uses call Memory.alloc 1 + pop pointer 0
  3. Method calls on objects push pointer 0 before the explicit arguments

Write a two-paragraph spot-check in diary/week-12.md. Paragraph 1: which method you chose and why. Paragraph 2: what you found and whether it matched your expectation.


Lab 12.4: Write your own VirtusLang program

Write a VirtusLang program of your own design. Requirements:

  • At least one class with at least one method
  • At least one while loop
  • At least one OS call (any of: Output.printInt, Output.printString, Screen.drawPixel, Keyboard.readChar)
  • The program must produce visible output when simulated

Create compiler/week-12/MyProgram.vl, compile it, run it through the full pipeline, and capture the simulation output.

In diary/week-12.md, answer the three Week 12 reflection prompts:

  1. Does the order of files in the directory affect correctness? When could it matter?
  2. What was the first thing that did not work when you compiled and ran your program? Describe the debugging steps and root cause.
  3. Your program calls one OS service. What would happen if the Virtus OS changed the argument count of that service without recompiling your program? Design a mechanism that would catch this mismatch at link time.

Lab 12.5: HDMI or UART output path

For students on the hardware path (Tang Primer 25K with HDMI extension):

# Flash the Pong bitstream
openFPGALoader -b tangprimer25k build/bin/pong.bin

Verify that HDMI output shows the Pong frame. Record the binary size and instruction count in diary/week-12.md.

For students on the UART-only path: redirect Screen.drawPixel to a UART escape sequence. Verify that the character-art Pong representation renders correctly over UART.


Grading

Component Points
compiler.py: handles directory input, produces one VM per .vl 4
Pong compile + link: three VM files produced, binary built 5
build/bin/pong.bin SHA-256 recorded in diary 2
Spot-check PongGame.vm: two paragraphs, specific evidence 3
Lab 12.4: own program compiles + runs + produces output 4
Diary: debugging narrative for Lab 12.4 program 2