Short Notes on Compiler Tools & Techniques (LEX/YACC, Symbol Table, Predictive Parsing, Peephole Optimization)

Short Notes on Compiler Tools & Techniques (LEX/YACC, Symbol Table, Predictive Parsing, Peephole Optimization)

Verified Sources
Nov 4, 2026

I can generate a Coursify course section for any two items from: (a) LEX and YACC, (b) Peephole Optimization, (c) Symbol Table, (d) Predictive parser.
However, my web-research tool (tavily_search) is currently failing due to a usage-limit error, so I cannot retrieve external sources to satisfy the requirement that every major claim/statistic/technical detail be backed by web citations.

Web research blocked (citations required)

The required web search tool is returning an error, so I cannot collect sources to provide the mandatory footnote citations.

In the meantime, below is a study-ready course section written as a “short-notes” style package covering (a) LEX and YACC and (c) Symbol Table—but note: it does not include the required external citations because web search is unavailable.

Selected topics

I will cover:

  • LEX
  • YACC
  • Symbol Table
  • Token
  • Parse Tree

LEX and YACC (Short Notes)

A typical compiler frontend splits into:

  1. Lexical analysis (turns characters into tokens)
  2. Syntax analysis (validates grammar structure of tokens)

LEX (often implemented as lex/flex) reads rule specifications (typically regular expressions → actions) and generates a scanner program that recognizes tokens.
YACC (often implemented as yacc/bison) reads grammar specifications (productions → semantic actions) and generates a parser.

How LEX and YACC fit together

  1. 1
    Step 1

    Define regular expressions for tokens (e.g., keywords, identifiers, numbers) and attach actions such as returning token types and setting semantic values.

  2. 2
    Step 2

    Run LEX to produce C (or target language) code for scanning input and producing a stream of tokens.

  3. 3
    Step 3

    Provide context-free grammar rules and semantic actions to build AST/parse tree or compute attributes.

  4. 4
    Step 4

    Run YACC to produce a parser that reads tokens from the lexer and checks if the token stream matches the grammar.

  5. 5
    Step 5

    Connect tokenization with parsing; lexer supplies tokens via a function (e.g., yylex), and parser calls it during parsing.

  6. 6
    Step 6

    Semantic actions can perform tasks like expression evaluation, AST construction, and type checking (often involving the symbol table).

Typical LEX specification ideas (what to write)

  • Rules: patterns for tokens using regular expressions (e.g., identifiers, integers, whitespace).
  • Actions: code executed when a pattern matches—commonly:
    • return a token code (like ID, NUM, IF)
    • set yylval (semantic value) for tokens like identifiers and numbers
    • ignore whitespace/comments

Tokens are the interface between LEX and YACC.

Typical YACC specification ideas (what to write)

  • Grammar productions: rules like
    • expr : expr PLUS term | term
  • Terminal symbols: tokens returned by the lexer
  • Semantic actions: code attached to productions to compute:
    • AST nodes
    • intermediate values
    • types (sometimes deferred)
    • error reporting

YACC will generate parsing logic and parsing tables from these rules.

Pro Tip (short-note framing)

In short notes, always mention the pipeline: LEX creates tokens using regex rules; YACC consumes tokens using CFG grammar rules to build/validate parse structure.

Symbol Table (Short Notes)

A Symbol Table stores information about program identifiers (variables, functions, etc.) used by later compiler phases like:

  • semantic analysis (type checking)
  • intermediate code generation
  • optimization and register allocation

Key concepts typically include:

  • Name → entry mapping: fast lookup (often using hashing or balanced trees)
  • Scope handling: identifiers can be declared in nested blocks/functions
  • Attributes stored: type, width, memory location, parameter list, etc.

Why symbol tables matter

When the parser or semantic analyzer encounters an identifier (e.g., x in x = 5;), the compiler needs to know:

  • Is x declared?
  • What is its type?
  • In what scope does it live?
  • Where should it be stored (address/offset) in memory or registers?

Thus, symbol table operations are often coupled with semantic actions in YACC productions.

Symbol table operations during compilation

  1. 1
    Step 1

    When a declaration is parsed (e.g., int x;), create an entry with attributes like type and scope and store it.

  2. 2
    Step 2

    When an identifier is used (e.g., x + 1), search for the most recent visible declaration in current/outer scopes.

  3. 3
    Step 3

    On entering a new block/function, push a new scope. On exit, pop it so inner declarations don’t leak.

  4. 4
    Step 4

    If lookup fails: undeclared identifier error. If redeclared in the same scope: redeclaration error.

  5. 5
    Step 5

    During semantic analysis, update attributes (e.g., inferred types, function signature details).

Typical symbol table entry (conceptual)

A symbol table entry may include:

  • Identifier: the lexeme string (e.g., sum)
  • Scope: current block/function level
  • Type: e.g., int, float
  • Address/Offset
  • For functions: parameter types and return type
  • For arrays: element type and dimensions

Data structures for implementation

Common structures:

  • Hash table: expected O(1)O(1) average-time lookup/insert
  • Stack of hash tables: each scope has its own hash table; pushing/popping manages scope
  • Balanced tree: O(log⁡n)O(\log n) lookup and ordered traversal
Average lookup time≈O(1)(hashing)\text{Average lookup time} \approx O(1) \quad\text{(hashing)}

Visual summary

Knowledge Check

Question 1 of 4
Q1Single choice

LEX and YACC are primarily used for…