Skip to main content

Free 10-chapter course · C++20 · x86-64 · NASM · Docker

Build a Compiler From Scratch in C++

Build a compiler in C++ for Si, a small programming language targeting Linux x86-64. The series takes you from language design and tokenisation through parsing, type checking, intermediate representation, assembly generation, and optimisation.

Chapters
10/10
Project time
—
Explorers
1

What You Will Build

The project connects a C++ compiler, a small assembly runtime, and a command-line toolchain. Together, they translate Si programs such as this one into executable code.

The example calls a function, multiplies two integers, and prints 42. Supporting it requires the compiler to recognise the source text, check its meaning, generate instructions, and link the program with the runtime.

answer.si
fn multiply(a: int, b: int): int {
    return a * b;
}

fn main(): int {
    let answer: int = multiply(6, 7);
    out(answer);
    return 0;
}
A Si program the finished compiler turns into a native x86-64 executable.

Milestones

Design a language, then lex, parse, check and compile it to native Linux x86-64 programs.

  1. 01 Language design
  2. 02 Lexer
  3. 03 Parser + AST
  4. 04 Semantic analysis
  5. 05 IR
  6. 06 x86-64 backend
  7. 07 ABI & runtime
  8. 08 Control flow
  9. 09 Optimisation

The Full Curriculum

Each chapter extends the same project, with explanations, implementation code, and tests. Follow the chapters in order to build the complete compiler, or jump to the stage you want to understand.

  1. 01

    How a Compiler Works: From Source Code to Machine Code

    Learn how a compiler transforms source code into machine code through lexing, parsing, semantic analysis, IR, optimisation and x86-64 code generation.

  2. 02

    How to Design a Programming Language from Scratch

    Design a small statically typed C-style programming language from scratch, including its syntax, types and grammar, then build its compiler in C++ with CMake and Docker.

  3. 03

    How to Build a Lexer in C++: Lexical Analysis and Tokens

    Build a lexer in C++ that converts source code into tokens, recognises keywords and operators, applies maximum munch, and reports useful errors.

  4. 04

    How to Build a Recursive Descent Parser in C++ with an AST

    Build a recursive descent parser in C++ that converts lexer tokens into an AST, handles operator precedence, reports syntax errors, and runs CTest tests.

  5. 05

    Compiler Semantic Analysis: Symbols, Scopes and Types in C++

    Learn semantic analysis in a compiler by building symbol tables, nested scopes and static type checking in C++, with diagnostics and CTest tests.

  6. 06

    How to Build a Compiler IR in C++: Three-Address Code

    Build an intermediate representation in C++. Lower a checked AST into three-address-style instructions with temporaries, variables, basic blocks, branches, loops and function calls.

  7. 07

    How to Build a Compiler Backend in C++: x86-64 Generation

    Build a compiler backend in C++ that translates checked IR into x86-64 NASM assembly with stack frames, arithmetic operations and native Linux executables.

  8. 08

    x86-64 Function Calls in a C++ Compiler: System V ABI and Runtime

    Add System V AMD64 function calls to a C++ compiler with x86-64 argument registers, stack alignment, return values, a NASM runtime and ELF64 linking.

  9. 09

    Compiler Control Flow in C++: x86-64 Branches, Loops and Jumps

    Implement compiler control flow in x86-64 assembly by lowering IR comparisons, conditional branches, if/else statements and while loops.

  10. 10

    Compiler Optimisation in C++: Constant Folding and Dead Code Elimination

    Build an IR optimiser in C++ with constant folding, branch simplification, unreachable-code removal and dead code elimination while preserving behaviour.

The series page, From Source to Machine Code , has the same chapters with a topic index.

Prerequisites

  • Comfortable reading C++, using classes and common data structures.
  • Comfortable running commands in a terminal. Docker provides the Linux toolchain.
  • No previous compiler-development experience. Assembly is introduced when code generation starts.

Want the background first? The Compilers learning path puts this project in order with the chapters and explorers that lead up to it.

Verified toolchain

The versions the series' code was last tested with.

  • Docker image ubuntu:24.04
  • g++ (build-essential), C++20
  • CMake (≥ 3.10)
  • NASM, x86-64 ELF64

Repository

Each chapter's code is on its own branch, so what you check out matches what you read.

github.com/gianni1998/gsisi

Branch per chapter (9)

Explorers for this project

Drive the hardest part of the project yourself before, or after, you implement it.

Compilers

Expression Parser Explorer

Type an expression and watch the tokens, the recursive-descent call stack and the AST.

Frequently asked questions

What language does the compiler compile?

Si, a small statically typed, C-style language designed in chapter 2 for this series. It has typed variables, arithmetic, functions, conditions, loops and output: enough to write real programs while keeping every stage of the compiler small enough to understand and test.

Do I need to know assembly before I start?

No. Assembly concepts are introduced when the project reaches code generation. If you want a head start, the x86-64 Assembly Hello World guide walks through assembling and linking a first NASM program.

What does the finished compiler produce?

NASM assembly for Linux x86-64. NASM and the system linker turn that output, together with a small assembly runtime, into a native executable you can run.

Can I follow along on macOS or Windows?

Yes. The series uses a Docker image based on Ubuntu 24.04 as its development environment, so the compiler, NASM and the linker run inside Linux regardless of the host system.

Where is the code for each chapter?

In the Si compiler repository on GitHub. Every implementation chapter links to its own branch, so the code you check out matches the listings in the chapter you are reading.

Start at chapter one

Written by the engineers behind BIOS Confessions. 10 of 10 chapters are published, and all of them are free.

Begin with Chapter 1