notesonly.in

One notebook for every subject — open it anywhere.

Log in

Lexical Analysis and Tokenization: Complete Beginner's Guide

Lexical analysis is the first phase of a compiler. It reads the raw source code as a stream of characters and groups them into meaningful chunks called tokens — the words of the programming language. Just as an English reader groups letters into words before understanding sentences, a compiler groups characters into tokens before understanding program structure.

This phase matters because everything downstream depends on it: the parser, type checker, and optimizer all work with tokens, never raw characters. A fast, correct lexer makes compilation quick and produces clear error messages like "unexpected character" instead of mysterious failures deep inside the compiler.

Key Concepts

  • Token: a pair of a token type and an optional value, for example an identifier token carrying the text "total", or a number token carrying 42.
  • Lexeme: the actual character sequence in the source that produced the token — "total" is the lexeme for the identifier token above.
  • Pattern: a regular expression describing all lexemes of a token type, for example a letter followed by letters or digits for identifiers.
  • Maximal munch: the rule that the lexer always matches the longest possible lexeme, so "counter" becomes one identifier, not "count" plus "er".
  • Keywords vs identifiers: reserved words like if and while are usually recognized as identifiers first, then looked up in a keyword table.

How It Works

  1. The lexer reads characters one at a time, skipping whitespace and comments, and starts building a lexeme.
  2. It feeds characters into a finite automaton built from the token patterns, tracking the longest prefix that matches any pattern.
  3. When no pattern can extend further, it emits the token for the longest match (maximal munch) and continues from the character after it.
  4. If no pattern matches at all, it reports a lexical error naming the offending character and its line number.

Worked Example

Tokenize the line total = price + 5; (24 characters including spaces and the semicolon):

  1. "total" matches the identifier pattern: token IDENTIFIER("total"), 5 characters.
  2. "=" matches the assignment pattern: token ASSIGN, 1 character.
  3. "price" matches the identifier pattern: token IDENTIFIER("price"), 5 characters.
  4. "+" matches the plus pattern: token PLUS, 1 character.
  5. "5" matches the number pattern: token NUMBER(5), 1 character.
  6. ";" matches the semicolon pattern: token SEMICOLON, 1 character.

Result: 6 tokens built from 14 non-space characters, with 5 spaces skipped silently. The parser will later see only this clean token stream — it never deals with individual letters or spaces.

Common Misconceptions

  • The lexer checks grammar. It does not — "if if if" lexes perfectly into three keyword tokens; only the parser can reject it as meaningless.
  • Tokenizing is just splitting on spaces. Operators like >= and strings like "hello world" must be recognized via patterns, not whitespace.
  • The lexer understands meaning. It cannot tell a variable from a function name — it only classifies shapes of text; meaning is the semantic analyzer's job.

Real-World Applications

  • Compilers and interpreters: every language from C to Python starts with lexical analysis.
  • Syntax highlighting: code editors color keywords, strings, and comments using lexer-like tokenization.
  • Linters and formatters: tools that check style or reformat code tokenize the source first.
  • Configuration parsers: JSON, YAML, and INI readers all begin by lexing the input text.

Lexical analysis turns a flat stream of characters into a structured stream of tokens — the vocabulary the rest of the compiler speaks. By handling the messy details of spelling, spacing, and comments up front, it lets the parser focus entirely on the grammar of the language.