Introduction to Compiler Design Lab (JNTUH R22)
The Compiler Design Laboratory is a core component of the Computer Science and
Engineering (CSE) curriculum under the R22 regulation at JNTUH. This lab is designed to
provide students with practical exposure to the fundamental concepts of compiler construction
and implementation. It complements the theoretical knowledge gained in the Compiler Design
course and allows students to build parts of a compiler through hands-on programming.
Objectives:
To understand the phases of a compiler: lexical analysis, syntax analysis, semantic
analysis, intermediate code generation, code optimization, and code generation.
To implement lexical analyzers and parsers using tools like Lex and Yacc.
To develop symbol tables and perform syntax-directed translation.
To gain exposure to error handling, intermediate representations, and basic optimizations.
Outcomes:
After successful completion of this lab, students will be able to:
Implement the lexical analyzer using regular expressions and finite automata.
Construct the syntax analyzer using context-free grammars and parsing techniques.
Develop symbol tables and perform syntax-directed translation.
Generate intermediate code representations.
Understand the working of tools such as Lex and Yacc for language processing.
Tools/Technologies Used:
C / C++ Programming
Lex (for lexical analysis)
Yacc (for syntax analysis)
Python (optional, for modern compiler frameworks)
Experiments Typically Include:
1. Implementation of a lexical analyzer.
2. Construction of a recursive descent parser.
3. Implementation of operator precedence parsing.
4. Construction and maintenance of symbol tables.
5. Syntax-directed translation and intermediate code generation.
6. Simple code optimization techniques.
7. Use of Lex and Yacc for scanner and parser generation.
Compiler Design Lab Manual Format (JNTUH R-22)
Experiment X: [Title]
Aim:
State the goal of the experiment clearly.
Example:
To implement a symbol table that supports insertion, lookup, and scope management using C.
List of Tools and Software:
C / C++ compiler (e.g., gcc)
Lex & Yacc (or flex & bison)
Text editor (e.g., VS Code, Sublime, or vim)
Optional: Python 3.x (if experimenting in Python)
Theory:
Provide a concise overview of the concepts used:
Role of lexers, parsers, and syntax trees
Symbol table structure and its importance in semantic analysis
Data structures used (e.g. hash tables, linked lists)
Nested scopes and scope resolution rules
Algorithm / Flowchart:
Break down the steps or control logic:
1. Read input source code
2. Tokenize using Lex/flex or manual scanner
3. Detect declarations and invoke insert() into symbol table
4. Perform lookup on usage
5. Handle scope entry/exit (e.g. push/pop scope stack)
6. Display or output contents of the symbol table
Flowchart: You might sketch: Input → Token Analysis → Symbol Table module → Lookup/Insert
→ Output or Error Handling.
Pseudocode:
initialize symbolTable
initialize scopeStack with global scope
for each token in source:
if token is declaration:
insert(identifier, type, current scope) into symbolTable
else if token is usage:
if lookup(identifier) in current or parent scopes:
OK
else:
report undefined identifier error
if token is `{`:
create new nested scope; push on scopeStack
if token is `}`:
pop scope; delete scope’s symbols from symbolTable
Source Code:
Signature and comments-enhanced code in your chosen language.
Example snippet (C):
void insert(char *name, char *type, int scope) { ... }
Symbol* lookup(char *name) { ... }
void enterScope() { ... }
void exitScope() { ... }
Include full code listing with comments explaining key parts.
Test Cases / Sample Input:
Provide a small source code file:
int x;
float y;
int x;
x = 5;
y = 4.5;
x = 10;
Expected Output:
Symbol insertions and messages
Scope entries and exits
Lookup messages
Final symbol table printed for each scope
Observations:
Log what you noticed when you:
Used same identifier in nested scopes
Assigned wrong types
Skipped variable declarations
Result:
Summarize:
The symbol table was correctly built. Nested scopes were handled, lookup of identifiers across
scopes worked correctly, and undefined usages were detected. The experiment outcomes align
with theoretical expectations.
Precautions:
Use consistent naming conventions
Clear delimiters for entering and exiting scope
Graceful error messages for undefined identifiers
A proper hash function if using a table for fast lookup
References:
Textbook: Compilers: Principles, Techniques, and Tools by Aho, Lam, Sethi & Ullman
JNTUH R-22 syllabus section on symbol table and semantic analysis
Manuals for Lex/Flex and Yacc/Bison
Using This Template for Other Experiments
Simply replace the “Aim” and adapt:
lexical analyzer
parser (recursive-descent / operator-precedence)
syntax-directed translation
intermediate code generation
optimization exercises
Each experiment would follow the same template structure—just plug in the specifics.
Would you like me to generate an example for a specific experiment now? For instance:
Lexical Analyzer using Lex
Recursive-descent parser
Intermediate Code Generation
Just say which one you’d like!
Basic Things to Learn in Compiler Design Lab
1. Compiler Phases (Theoretical Foundation)
Before writing any code, you should understand the phases of a compiler:
Phase Purpose
Lexical Analysis Breaks input into tokens
Syntax Analysis Builds a parse tree using grammar
Semantic Analysis Checks for type and scope correctness
Intermediate Code Generation Translates to an intermediate form
Code Optimization Improves the performance of intermediate code
Code Generation Produces assembly or machine code
Symbol Table Management Tracks identifiers and their attributes
2. Lexical Analysis
Lex tool (or Flex): Write a program to recognize tokens like keywords, identifiers,
numbers, etc.
Regular expressions: Learn to define patterns for tokens.
Finite automata: Theoretical model behind lexers.
Sample Experiment:
Recognize keywords, identifiers, numbers using Lex.
3. Syntax Analysis (Parsing)
Understand CFG (Context-Free Grammar)
Recursive descent parsing
Operator precedence parsing
Write custom parsers or use Yacc (or Bison)
Sample Experiment:
Implement a parser to check whether an expression is syntactically valid.
4. Symbol Table
Data structure to store information about variables, functions, etc.
Must support:
o Insertion
o Lookup
o Scope management
Sample Experiment:
Implement a symbol table using hash table or linked list.
5. Intermediate Code Generation
Learn how source code gets translated into:
o 3-address code (TAC)
o Postfix notation
Use syntax-directed translation.
Sample Experiment:
Generate 3AC for arithmetic expressions.
6. Code Optimization
Learn simple optimizations like:
o Constant folding
o Common subexpression elimination
o Dead code elimination
Sample Experiment:
Apply constant folding to simplify expressions.
7. Tools You Should Know
Tool Use
Lex / Flex Token recognition (lexer generation)
Yacc / Bison Parser generation
C / C++ Implementation language
Python (optional) Modern compiler prototyping
VS Code / GCC Editor and compiler
8. Sample Lab Experiments (JNTUH R22 aligned)
Exp. No. Title
1 Lex program to recognize keywords, identifiers
2 Lex to count lines, words, characters
3 Yacc to validate arithmetic expressions
4 Recursive descent parser for expressions
5 Operator precedence parser
6 Symbol table implementation
7 Syntax-directed translation (TAC)
8 Code optimization techniques
9. Skills You’ll Gain
Understanding of compiler internals
Building parsers and interpreters
Regular expressions and grammars
Code generation logic
Error detection and reporting
10. Tips for Success
Understand the theory behind each lab before coding
Practice writing regular expressions and grammars
Get comfortable with C programming
Break each experiment into small steps: input → logic → output
Debugging Lex/Yacc output is crucial — trace tokens and grammar flow