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)
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:
- Lexical analysis (turns characters into tokens)
- 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
- 1Step 1
Define regular expressions for tokens (e.g., keywords, identifiers, numbers) and attach actions such as returning token types and setting semantic values.
- 2Step 2
Run LEX to produce C (or target language) code for scanning input and producing a stream of tokens.
- 3Step 3
Provide context-free grammar rules and semantic actions to build AST/parse tree or compute attributes.
- 4Step 4
Run YACC to produce a parser that reads tokens from the lexer and checks if the token stream matches the grammar.
- 5Step 5
Connect tokenization with parsing; lexer supplies tokens via a function (e.g., yylex), and parser calls it during parsing.
- 6Step 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
- return a token code (like
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
xdeclared? - 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
- 1Step 1
When a declaration is parsed (e.g.,
int x;), create an entry with attributes like type and scope and store it. - 2Step 2
When an identifier is used (e.g.,
x + 1), search for the most recent visible declaration in current/outer scopes. - 3Step 3
On entering a new block/function, push a new scope. On exit, pop it so inner declarations don’t leak.
- 4Step 4
If lookup fails: undeclared identifier error. If redeclared in the same scope: redeclaration error.
- 5Step 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 average-time lookup/insert
- Stack of hash tables: each scope has its own hash table; pushing/popping manages scope
- Balanced tree: lookup and ordered traversal
Visual summary
Knowledge Check
LEX and YACC are primarily used for…