Compilers and interpreters are the programs that turn source code written by humans into something a machine can actually execute, sitting underneath every programming language toolchain from CPython to LLVM-backed Rust. Understanding this pipeline matters because it explains why languages behave the way they do: why a syntax error surfaces before a program runs, why some languages catch type mistakes early and others only at runtime, why JavaScript engines get faster the longer a loop runs, and why a "new" language rarely starts from zero but instead reuses proven front-end and back-end building blocks. The key mental model is that nearly every language implementation is really a pipeline of independent, swappable stages β lexer, parser, semantic analyzer, intermediate representation, optimizer, code generator β and the "compiler vs. interpreter" question is less a strict binary than a choice of which stages run ahead of time versus at run time. Once that pipeline clicks, picking up a new language's toolchain stops feeling like starting over and starts feeling like recognizing the same stages wearing different names.
What This Cheat Sheet Covers
This topic spans 14 focused tables and 96 indexed concepts, 91 flashcards. Below is a complete table-by-table outline of this topic, spanning foundational concepts through advanced details.
A jump-to index of every table row in this cheat sheet.
An interactive map of every table and concept in this topic.
Table 1: Execution Models: How Source Code Becomes Running Code
Every language runtime answers the same question β when does source code turn into something the CPU executes β differently, and that single choice shapes startup time, peak speed, and portability.
| Model | Example | Description | |
|---|---|---|---|
gcc program.c -o program then ./program runs the compiled result | Translates source code into a lower-level target, usually machine code, entirely before the program runs, as a separate step from execution. | ||
python script.py runs the script directly with no separate build step | Reads and executes a program, or its parsed form, on the fly, in the same process that produces its effects. | ||
The JVM interprets bytecode first, then compiles hot methods to native code with its C1/C2 compilers once they run often enough | Compiles parts of a program to native code while it runs, using runtime profiling data an ahead-of-time compiler never has access to. | ||
native-image in GraalVM turns a JVM application into a standalone native binary before deployment | β’ Produces machine code entirely before execution β’ trades a JIT's warm-up-driven peak performance for instant startup and predictable memory use | ||
CPython compiles a .py file to .pyc bytecode, then its virtual machine interprets that bytecode | β’Source is compiled to a compact intermediate instruction set first. β’A lightweight virtual machine interprets that instead of raw source text or native code. | ||
An AdditionExpression node's evaluate() method recursively calls evaluate() on both of its child nodes | β’ Executes a program by directly walking its abstract syntax tree node by node β’ simple to build, but slow due to pointer-chasing and virtual dispatch | ||
Babel converts modern ES2022 JavaScript into ES5-compatible JavaScript | Translates source code in one language, or one version of a language, into source code in another comparable-level language, rather than into machine code. |