What lexing does — and why it's a separate phase
Raw source is just a byte stream. The lexer (scanner) converts it into a flat sequence of tokens, each carrying a kind and a lexeme (the raw text). Separating lexing from parsing is a classic compiler decision: the grammar for tokens is regular (finite automata suffice), while the grammar for programs is context-free (needs a stack). Keeping the phases separate makes both simpler.
A typical token stream for x = 1 + 2;:
IDENT("x") ASSIGN INT(1) PLUS INT(2) SEMI
Each token carries its kind, its literal text, and usually source coordinates (file, line, column) for error messages. The parser never looks at raw characters — only at this stream.
