the compiler front end
A compiler is like a translation pipeline that turns source code into something a machine can run. Think of it as a factory line in two halves. The front end is the half that reads and understands the source language: it figures out what the program says and whether it is well formed. The back end is the half that generates and optimizes the target code. The clean division means you can swap target machines without rewriting the understanding part, and vice versa.
The front end runs in stages, each handing its output to the next. First the scanner (lexer) groups raw characters into tokens, the words of the language: keywords, identifiers, numbers, punctuation. Then the parser takes that token stream and checks it against the grammar, building a parse tree or abstract syntax tree (AST) that captures the program's structure. After that comes semantic analysis: name resolution, type checking, and other rules a context-free grammar cannot express. Notice the labour split: the scanner handles the regular-language part (token shapes), the parser handles the context-free part (nesting and structure). This is formal-language theory turned directly into software architecture.
The front end matters because it is where source text becomes meaning. If the front end accepts a program, the rest of the compiler can trust it is syntactically valid and work on a clean tree instead of raw text. Errors caught here, a missing semicolon, an unbalanced bracket, an undeclared variable, are reported to the programmer in human terms. A robust front end is also reusable: language servers, linters, formatters, and refactoring tools all reuse the very same scanning and parsing machinery.
Compiling x = a + 2: the scanner yields tokens [id:x, =, id:a, +, num:2], the parser builds an assignment tree (x on the left, the expression a + 2 on the right), and semantic analysis checks that a is declared and the types line up. Only then does the back end emit machine code.
Front-end stages: characters -> tokens (scanner) -> tree (parser) -> meaning (semantic analysis).
Not every language rule is context-free. 'Use a variable only after declaring it' cannot be enforced by the grammar, so it is left to semantic analysis, not the parser. The parser only guarantees syntactic structure.