Lexical analysis
A lexer converts a character stream into tokens using patterns typically described by regular expressions. Longest match and priority rules resolve ambiguity when multiple patterns match. The lexer does not check grammatical structure.
Check yourself: Does the longest-match rule apply before the priority rule?
Top-down parsing and LL(1)
A predictive parser chooses a production using the current non-terminal and lookahead token. An LL(1) grammar requires: no left recursion, and disjoint FIRST sets for alternatives (using FOLLOW when FIRST contains ε). Left recursion must be eliminated; left factoring resolves common prefixes.
Check yourself: Do FIRST sets of alternative productions overlap for any non-terminal?
Bottom-up parsing and LR
LR parsers shift tokens onto a stack and reduce when the top matches a production's right side. SLR uses FOLLOW sets to decide reductions; CLR and LALR use more precise lookahead sets. An LR(1) grammar is unambiguous, but not every unambiguous grammar is LR(1). Shift-reduce and reduce-reduce conflicts indicate the grammar is not in the parser's class.
Check yourself: Is the conflict a genuine grammar ambiguity or a limitation of the parser class?
Syntax-directed translation
Attributes attached to grammar symbols compute values during parsing. Synthesized attributes flow up the parse tree; inherited attributes flow down. An S-attributed definition uses only synthesized attributes and can be evaluated in a single bottom-up pass.
Check yourself: Does the evaluation order respect attribute dependencies?
Intermediate code and basic optimization
Three-address code represents expressions using at most one operator per statement. Basic blocks are maximal sequences with no branches except at entry and exit. Common subexpression elimination avoids recomputing the same value; dead code elimination removes results that are never used.
Check yourself: Is the value from this computation used on any path to the exit?