Source code is the human-readable program written by a developer. Before a computer can run it, it must be translated into object code (executable machine code). The program that does this translation is called a translator.
Assembler
Translates assembly language source code into machine code.
- One-to-one translation: each mnemonic becomes exactly one machine instruction
- Output: object code ready to execute
Compiler
Translates an entire high-level source program into machine code (or bytecode) before execution.
Steps:
- Lexical analysis — tokenises the source
- Syntax analysis — builds a parse tree; checks grammar
- Semantic analysis — checks type compatibility, scope
- Code generation — produces machine code or bytecode
- Optimisation — improves speed or reduces size
Key properties:
- Translation happens once; the compiled program runs without the source code or compiler present
- Faster execution than interpretation (no translation overhead at runtime)
- Errors are reported as a complete list after the whole program is analysed
- Object file is hardware-specific (unless producing bytecode)
Interpreter
Translates and executes the source code line by line at runtime.
Key properties:
- No separate compilation step — run the source directly
- Slower execution — each line is re-translated every time it is reached (e.g. inside a loop)
- Easier to debug interactively — errors are reported immediately at the failing line
- Source code must be present on the target machine
- Useful for scripting, rapid development, and cross-platform environments
Bytecode
Some compilers (notably Java's javac) do not produce machine code directly. Instead they produce bytecode: an intermediate representation that is:
- More compact than source code
- Not tied to any specific hardware
- Executed by a virtual machine (VM) at runtime (e.g. the Java Virtual Machine, JVM)
This gives a middle ground: compile once to bytecode; the VM interprets or JIT-compiles it on any platform.