You are on page 1of 63

CSM801

Compiler Design

Dr. Sanjay Saini


Assistant Professor,
Department of Physics and Computer Science
Dayalbagh Educational Institute
Introduction to Compilers
Overview of the Course
Why Study Compilers?
• Language processing is an important component of
programming
• A large number of systems software and application programs
require structured input
®Operating Systems (command line processing)
®Databases (Query language processing)
®Type setting systems like Latex, Nroff, Troff, Equation editors, M4
®VLSI design and testing
®Software quality assurance and software testing
®XML, html based systems, Awk, Sed, Emacs, vi ..
®Form processing, extracting information automatically from forms
®Compilers, assemblers and linkers
®High level language to language translators
®Natural language processing
• Where ever input has a structure one can think of language
processing
Example
An example of the banner program of Unix which, as the name suggests is
used specifically to design banners. Here we are trying to print the
alphabet "I".

xxxxxxxxx 9x
xxxxxxxxx 9x
xxxxxxxxx 9x
xxx 3b 3x 3 9x
xxx 3b 3x 6 3b 3x
xxx 3b 3x 3 9x
xxx 3b 3x
xxx 3b 3x
xxx 3b 3x
xxxxxxxxx 9x
xxxxxxxxx 9x
xxxxxxxxx 9x
Compilers
• What is a compiler?
▫ A program that translates an executable program in one language
into an executable program in another language
▫ The compiler should improve the program, in some way
• What is an interpreter?
▫ A program that reads an executable program and produces the
results of executing that program

• C is typically compiled, Scheme is typically interpreted


• Java is compiled to bytecodes (code for the Java VM)
▫ which are then interpreted
▫ Or a hybrid strategy is used
 Just-in-time compilation
Taking a Broader View
• Compiler Technology = Off-Line Processing
▫ Goals: improved performance and language usability
 Making it practical to use the full power of the language
▫ Trade-off: preprocessing time versus execution time (or
space)
▫ Rule: performance of both compiler and application must
be acceptable to the end user
• Examples
▫ Macro expansion
 PL/I macro facility — 10x improvement with compilation
▫ Database query optimization
▫ Emulation acceleration
 TransMeta “code morphing”
Intrinsic Interest

Compiler construction involves ideas from many


different parts of computer science
Greedy algorithms
Artificial intelligence Heuristic search techniques

Graph algorithms, union-find


Algorithms Dynamic programming

DFAs & PDAs, pattern matching


Theory Fixed-point algorithms

Allocation & naming,


Systems Synchronization, locality

Pipeline & hierarchy management


Architecture Instruction set use
Intrinsic Merit
Compiler construction poses challenging and interesting
problems:
▫ Compilers must do a lot but also run fast
▫ Compilers have primary responsibility for run-time
performance
▫ Compilers are responsible for making it acceptable to use
the full power of the programming language
▫ Computer architects perpetually create new challenges for
the compiler by building more complex machines
▫ Compilers must hide that complexity from the programmer
▫ Success requires mastery of complex interactions
A Brief History
• Some early machines and implementations
• IBM developed 704 in 1954. All programming was done
in assembly language. Cost of software development far
exceeded cost of hardware. Low productivity.
• Speedcoding interpreter: programs ran about 10 times
slower than hand written assembly code
• John Backus (in 1954): Proposed a program that
translated high level expressions into native machine
code. Most people thought it was impossible
• Fortran I project . (1954-1957): The first compiler was
released
A Brief History
• Fortran I
• The first compiler had a huge impact on the programming
languages and computer science. The whole new field of
compiler design was started
• More than half the programmers were using Fortran by 1958
• The development time was cut down to half
• Led to enormous amount of theoretical work (lexical
analysis, parsing, optimization, structured programming,
code generation, error recovery etc.)
• Modern compilers preserve the basic structure of the Fortran
I compiler !!!
Making Languages Usable
It was our belief that if FORTRAN, during
its first months, were to translate any
reasonable “scientific” source program into
an object program only half as fast as its
hand-coded counterpart, then acceptance of
our system would be in serious danger... I
believe that had we failed to produce
efficient programs, the widespread use of
languages like FORTRAN would have been
seriously delayed.
— John Backus
References
What is a Compiler?
• Compiler is a program which translates a program written in one
language (the source language) to an equivalent program in other
language (the target language).
• Usually the source language is a high level language like Java, C,
Fortran etc. whereas the target language is machine code or "code"
that a computer's processor understands.
▫ The source language is optimized for humans.
▫ It is more user-friendly, to some extent platform-independent.
▫ They are easier to read, write, and maintain and hence it is easy to
avoid errors.
• Ultimately, programs written in a high-level language must be
translated into machine language by a compiler.
▫ The target machine language is efficient for hardware but lacks
readability.
The Big Picture
Compiler is part of program development environment
How to Translate?
• The high level languages and machine languages
differ in level of abstraction.
• At machine level we deal with memory locations,
registers whereas these resources are never
accessed in high level languages.
• The level of abstraction differs from language to
language and some languages are farther from
machine code than others
Goals of Translation
• Smaller generated code :
▫ What is the ratio between the size of handwritten code and
compiled machine code for same program
▫ A better compiler is one which generates smaller code.
• Faster executable code :
▫ A handwritten machine code is more efficient than a
compiled code in terms of the performance it produces.
▫ If a compiler produces a code which is 20-30% slower than
the handwritten code then it is considered to be acceptable.
▫ In addition to this, the compiler itself must run fast
(compilation time must be proportional to program size).
Goals of Translation
• Correctness :
▫ A compiler's most important goal is correctness -
all valid programs must compile correctly.
▫ How do we check if a compiler is correct i.e.
whether a compiler for a programming language
generates correct machine code for programs in
the language.
▫ The complexity of writing a correct compiler is a
major limitation on the amount of optimization
that can be done.
• Can compilers be proven to be correct? Very
tedious!
How to Translate?

• Translate in steps

• Lexical Analysis
• Syntax Analysis
• Semantic Analysis
• Optimization
• Code Generation
Lexical Analysis

• Recognize the words/ tokens


This is a sentence
• May not be trivial
ist his ase nte nce?
• We must know what the word separators are
Lexical Analysis

Lexical Analysis divides program text into


“words” or “tokens”

If a == b then a = 1 ; else a = 2 ;
- Sequence of words (total ? words)
Lexical Analysis
• Lexical analysis is the process of identifying
the words from an input string of characters,
which may be handled more easily by a parser.
• These words must be separated by some
predefined delimiter or there may be some rules
imposed by the language for breaking the
sentence into tokens or words which are then
passed on to the next phase of syntax analysis.
• In programming languages, a character from a
different class may also be considered as a word
separator.
Syntax Analysis
• Understand sentence structure
• Parsing = Diagramming sentences
▫ The diagram is a tree
Parsing
Parsing
Semantic Analysis
• Understanding the meaning of the sentence
• Too hard for compilers.
• However, compilers do perform analysis to catch
inconsistencies
Semantic Analysis
• Jack said Jerry left his assignment at home

• Jack said Jack left his assignment at home?


Semantic Analysis
• Programming languages define strict rules to avoid
such ambiguities

{
int Jack = 3;
{
int Jack = 4;
cout << Jack;
}
}
Semantic Analysis
• Compilers perform many other checks besides
variable bindings
• Type checking:
▫ Jack left her work at home
▫ There is a type mismatch between her and Jack.
• In the statement:
double y = "Hello World";
• Semantic analysis would reveal that "Hello
World" is a string, and y is of type double,
• This is a type mismatch.
Semantic Analysis
• Semantic analysis is the process of examining
the statements and to make sure that they make
sense.
• During the semantic analysis, the types, values,
and other required information about
statements are recorded, checked, and
transformed appropriately to make sure the
program makes sense.
• Ideally there should be no ambiguity in the
grammar of the language. Each sentence should
have just one meaning.
Optimization
• Automatically modify programs so that they
▫ Run faster
▫ Use less resources (memory, registers, space,
fewer fetches etc.)
• Example: x = 15 * 3 is transformed to x = 45
Optimization
PI = 3.14159 3A+4M+1D+2E
Area = 4 * PI * R^2
Volume = (4/3) * PI * R^3
--------------------------------
X = 3.14159 * R * R 3A+5M
Area = 4 * X
Volume = 1.33 * X * R
--------------------------------
Area = 4 * 3.14159 * R * R
2A+4M+1D
Volume = ( Area / 3 ) * R
--------------------------------
Area = 12.56636 * R * R 2A+3M+1D
Volume = ( Area /3 ) * R
--------------------------------
X=R*R 3A+4M
Area=12.56636*X
Volume=4.1783147*X*R (4/3)*PI = 4.1783147

A : assignment M : multiplication
D : division E : exponent
Optimization
int x = 2;
int y = 3;
int *array[5];
for (i=0; i<5;i++)
*array[i] = x + y;
____________________________________
int x = 2;
int y = 3;
int z = x + y;
int *array[5];
for (i=0; i<5;i++)
*array[i] = z;
Code Generation
• A translation into another language
▫ Similar to human translation
• Usually produces assembly code

Source Code
Intermediate Language should be:
Easy to Produce
Intermediate Code Easy to Translate into Target Language

Target Code
An Observation
• The overall structure of every compiler adheres
to this outline
• Proportions have changed since the first
compiler was written for Fortran

L P S O CG

L P S O CG
How to translate?
• Translate in steps. Each step handles a
reasonably simple, logical, and well defined task
• Design a series of program representations
• Intermediate representations should be
amenable to program manipulation of various
kinds (type checking, optimization, code
generation etc.)
• Representations become more machine specific
and less language specific as the translation
proceeds
How to Translate?
• Many modern compilers share a common 'two stage'
design.
▫ The "front end" translates the source language or the high level
program into an intermediate representation.
▫ The second stage is the "back end", which works with the internal
representation to produce code in the output language which is a
low level code.
• The higher the abstraction a compiler can support, the
better it is.
Structure of a Compiler
Structure of a Compiler
Structure of a Compiler
• Also known as Analysis-Synthesis model of
compilation
▫ Front end phases are known as analysis phases
▫ Back end phases are known as synthesis phases
• Each phase has a well defined work
• Each phase handles a logical activity in the
process of compilation
Advantages of the Model
• Compiler is retargetable
▫ Since each phase handles a logically different phase of
working of a compiler, parts of the code can be reused to
make new compilers.
• Source and machine independent code optimization is
possible.
• Optimization phase can be inserted after the front and
back end phases have been developed and deployed
• In adding optimization, improving the performance of
one phase should not affect the same of the other
phase; this is possible to achieve in this model.
M*N vs M+N problem
For M languages and N machines we need to
develop M*N compilers
M*N vs M+N problem
• We design the front end independent of machines and the
back end independent of the source language.
• We require a Universal Intermediate Language (UIL) that acts
as an interface between front end and back end.
• Thus we need to design only M front ends and N back ends.
• To design a compiler for language L that produces output for
machine C, we take the front end for L and the back end for C.
In this way, we require only M + N compilers for M source
languages and N machine architectures.
• For large M and N, this is a significant reduction in the effort.
Universal Intermediate Language
• Universal Computer/Compiler Oriented Language
(UNCOL)
• Suggested in 1958 to reduce the developmental effort of
compiling many different languages to different
architectures
• Due to vast differences between programming languages
and machine architectures, design of such a language is
not possible.
• We can group programming languages with similar
characteristics together
• Similarly an intermediate language is designed for
similar machines.
How to reduce development and
testing effort?
• DO NOT WRITE COMPILERS, GENERATE
compilers
• A compiler generator should be able to
"generate" compiler from the source language
and target machine specification
Advantages
• Changing specifications of a phase can lead to a new
compiler
▫ If machine specifications are changed then compiler can
generate code for a different machine without changing any
other phase
▫ If front end specifications are changed then we can get
compiler for a new language
• Tool based compiler development cuts down
development/maintenance time by almost 30-40%
• Tool development/testing is one time effort
• Compiler performance can be improved by improving a
tool and/or specification for a particular phase
Types of Compilers – Native vs Cross

• The computer the compiler runs on is called


the host, and the computer the new programs
run on is called the target.
• When the host and target are the same type of
machine, the compiler is a native compiler.
• When the host and target are different, the
compiler is a cross compiler.
Bootstrapping
• A simple language is used to translate a more
complicated program, which in turn may handle
a more complicated program, and so on, is
known as bootstrapping.
Bootstrapping
• A compiler can be characterized by three
languages: the source language (S), the target
language (T), and the implementation language
(I)
Bootstrapping
Bootstrapping
• The compiler of LSN is written in language S.
• This compiler code is compiled once on SMM to
generate the compiler's code in a language that
runs on machine M.
• So, in effect, we get a compiler that converts
code in language L to code that runs on machine
N and the compiler itself is in language M. In
other words, we get LMN.
Bootstrapping Example
Pas C Pas C

J J Py Py

C M C M

A A C C

M
Bootstrapping
Bootstrapping
• Develop a compiler for a language L written in L. For this we require
a compiler of L that runs on machine M and outputs code for
machine M.
• First we write LLN i.e. we have a compiler written in L that converts
code written in L to code that can run on machine N.
• We then compile this compiler program written in L on the available
compiler LMM. So, we get a compiler program that can run on
machine M and convert code written in L to code that can run on
machine N i.e. we get LMN.
• Now, we again compile the original written compiler LLN on this
new compiler LMN we got in last step. This compilation will convert
the compiler code written in L to code that can run on machine N.
• So, we finally have a compiler code that can run on machine N and
converts code in language L to code that will run on machine N. i.e.
we get LNN.
The Economy of Languages
• Why are there so many programming languages?
▫ Application domains have distinctive/ conflicting
requirements
• Why are there new programming languages?
• What is a good programming language?
Why are there new programming
languages?
• Claim: Programmer cost is the dominant cost for
a programming language.
• Predictions
▫ Widely used languages are slow to change
▫ Easy to start a new language
▫ Languages are created/ evolve to fill up a void
• New programming languages tend to look like
existing ones
Role of Programming Languages
• Getting the answer
• Correctness/Precise-ness
• Efficiency
• User friendliness
Influences on Evolution of Language
Design
• Computer Capabilities
• Applications
 Commercial, Military, Scientific, Medical, Astronomical,
Business, Industrial, Personal (Games)
• Programming Methods
• Implementation Methods
• Theoretical Studies
• Standardization
What is a good programming language?
• There is no universally accepted metric for
language design
• A good language is one that most people use?
Characteristics of a Good Languages
• Clarity, Simplicity and Unity
▫ Unified set of concepts that can be used as primitives for
developing an algorithm.
• Orthogonality
▫ Attribute of being able to combine various features of a language in
all possible combinations, with each combination being meaningful.
• Naturalness for the Application
• Support for abstraction
• Ease of program verification
• Programming environment
• Portability of the programs
• Cost
Cost Explained
• Cost
▫ of training
▫ of writing the program
▫ of executing the program
▫ of translation
▫ of implementation
▫ of maintenance
Thank you!

You might also like