A CPU only ever executes binary machine code. Every program you've ever written in a higher-level language had to pass through one of three kinds of translator first. This page builds every stage of that pipeline for real, live, on data you type in yourself.
| Translator | What it does | Output |
|---|---|---|
| Compiler | Translates the entire program before any of it runs | Standalone machine code executable |
| Interpreter | Translates and executes one line at a time | No executable, source needed every run |
| Assembler | Translates assembly mnemonics into machine code | One mnemonic → one machine instruction |
The very first thing any translator does is stop treating your code as plain text. Type a line below and watch it split into tokens live, exactly as a real lexer would.
The lexer above only produces a flat list of tokens, it knows nothing about structure. The parser's job is to build a genuine tree from that list, one that correctly captures precedence, this is the actual Abstract Syntax Tree a compiler would build, not just a description of one.
Syntactically valid code can still be meaningless. "Check the variable was declared before use" isn't just a rule to memorise, here's the actual lookup that enforces it, live.
| empty |
Same 4 lines, same bug on line 3 (q was never defined). Run both and watch the single most commonly examined difference between them play out for real.
"The compiler optimises the code" is easy to state and easy to leave vague. Here's a genuine optimisation, verified, with a real instruction count before and after.
A naive interpreter doesn't just execute a line, it re-translates that exact same line every single time it's reached. A compiler translates it once, no matter how many times it later runs.
This program jumps to a label, END, that hasn't been defined yet when the jump instruction is written. A single top-to-bottom pass genuinely cannot resolve that, here's why two passes fixes it, using the exact LDA/ADD/STA encoding from the Fetch-Execute Cycle lesson.
| empty |