0% found this document useful (0 votes)
7 views8 pages

Lec 2 - Compiler Construction

The document discusses the various components involved in converting high-level programming languages to low-level machine code, collectively referred to as the 'Cousins of the Compiler', which include the preprocessor, assembler, linker, and loader. Each component performs specific tasks such as preprocessing, assembly, linking, and loading, which are essential for the final execution of the program. Additionally, it outlines the phases of a compiler, including lexical analysis, syntax analysis, and code generation, and distinguishes between one-pass and two-pass compilation methods.

Uploaded by

fsundas959
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views8 pages

Lec 2 - Compiler Construction

The document discusses the various components involved in converting high-level programming languages to low-level machine code, collectively referred to as the 'Cousins of the Compiler', which include the preprocessor, assembler, linker, and loader. Each component performs specific tasks such as preprocessing, assembly, linking, and loading, which are essential for the final execution of the program. Additionally, it outlines the phases of a compiler, including lexical analysis, syntax analysis, and code generation, and distinguishes between one-pass and two-pass compilation methods.

Uploaded by

fsundas959
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 8

Cousins of Compiler

Converting a high-level language into a low-level language takes multiple steps and involves
many programs apart from the Compiler. Before the compilation can start, our source code
needs to be preprocessed. After the compilation, our code needs to be converted into
executable code to execute on our machine. These essential tasks are performed by the
preprocessor, assembler, Linker, and Loader. They are known as the Cousins of the
Compiler. Let's study them in detail.

Let's see who the cousins of Compiler are and what their contributions are in the process of
converting a high-level language into a low-level language.

Preprocessor
The preprocessor is one of the cousins of the Compiler. It is a program that performs
preprocessing. It performs processing on the given data and produces an output. The output
generated is used as an input for some other program.
The preprocessor increases the readability of the code by replacing a complex expression
with a simpler one by using a macro.
A preprocessor performs multiple types of functionality and operations on the data.
Some of them are-

Macro processing
Macro processing is mapping the input to output data based on a certain set of rules and
defined processes. These rules are known as macros.

Rational Preprocessors
Relational preprocessors are the processors that change older languages with some modern
flow-of-control and data-structuring facilities.

File Inclusion
The preprocessor is also used to include header files in the program text. A header file is a
text file included in our source program file during compilation. When the preprocessor finds
an #include directive in the program, it replaces it with the entire content of the specified
header file.

Language extension
Language extension is used to add new capabilities to the existing language. This is done by
including certain libraries in our program, which provides extra functionality. An example of
this is Equel, a database query language embedded in C.
Error Detection
Some preprocessors are capable of performing error-checking on the source code that is
given as input to them. For example, it can check if the headers files are included properly
and if the macros are defined correctly or not.

Conditional Compilation
Certain preprocessors are capable of including or excluding certain pieces of code based on
the result of a condition. They provide more flexibility to the programmers for writing the code
as they allow the programmers to include or exclude certain features of the program based
upon some condition.

Assembler
Assembler is also one of the cousins of the compiler. A compiler takes the preprocessed
code and then converts it into assembly code. This assembly code is given as input to the
assembler, and the assembler converts it into the machine code. Assembler comes into
effect in the compilation process after the Compiler has finished its job.
There are two types of assemblers-
● One-Pass assembler: They go through the source code (output of Compiler) only
once and assume that all symbols will be defined before any instruction that
references them.

● Two-Pass assembler: Two-pass assemblers work by creating a symbol table with the
symbols and their values in the first pass, and then using the symbol table in a
second pass, they generate code.

Linker
Linker takes the output produced by the assembler as input and combines them to create an
executable file. It merges two or more object files that might be created by different
assemblers and creates a link between them. It also appends all the libraries that will be
required for the execution of the file. A linker's primary function is to search and find referred
modules in a program and establish the memory address where these codes will be loaded.
Multiple tasks that can be performed by linkers include-
● Library Management: Linkers can be used to add external libraries to our code to add
additional functionalities. By adding those libraries, our code can now use the
functions defined in those libraries.

● Code Optimization: Linkers are also used to optimize the code generated by the
compiler by reducing the code size and increasing the program's performance.

● Memory Management: Linkers are also responsible for managing the memory
requirement of the executable code. It allocates the memory to the variables used in
the program and ensures they have a consistent memory location when the code is
executed.
● Symbol Resolution: Linkers link multiple object files, and a symbol can be redefined
in multiple files, giving rise to a conflict. The linker resolves these conflicts by
choosing one definition to use.

Loader
The loader works after the linker has performed its task and created the executable code. It
takes the input of executable files generated from the linker, loads it to the main memory,
and prepares this loaded code for execution by a computer. It also allocates memory space
to the program. The loader is also responsible for the execution of programs by allocating
RAM to the program and initializing specific registers.

Following tasks are performed by the loader


● Loading: The loader loads the executable files in the memory and provides memory
for executing the program.

● Relocation: The loader adjusts the memory addresses of the program to relocate its
location in memory.

● Symbol Resolution: The loader is used to resolve the symbols not defined directly in
the program. They do this by looking for the definition of that symbol in a library
linked to the executable file.

● Dynamic Linking: The loader dynamically links the libraries into the executable file at
runtime to add additional functionality to our program.

Assignment#1

Why do we need a compiler?

What is the difference between a preprocessor and a compiler?

What is the difference between an assembler and a compiler?

Grouping of Phases
A compiler is software that translates a high-level language into
machine-understandable form. Typically, a compiler is made up of six states
and the input code in high-level language also known as Source code passes
through each state one by one, each state processes the code, resulting in
machine-understandable code or object code as an output.
These six states of the compiler are further divided into phases on the basis
of one-pass or two-pass compiler, the state is as follows:

1. Lexical Analysis

2. Syntax Analysis

3. Semantic Analysis

4. Intermediate Code Generation

5. Code Optimization

6. Code Generation

1) Lexical Analysis:

It’s main task is to read the input character and produce as output:

A sequence of tokens that are parser uses for syntax analysis.

2) Syntax analysis:

It is also called parsing . It checks the each line of the code and sports tiny
mistake that the pro

grammar has committed while typing the code. If the code is error free then
the syntax analyzer generated the tree.

3) Semantic analysis:

Semantic analyzer determines the meaning of a source string.

example : matching parenthesis is the expression checking the scope of


operation.

4) Intermediate code generation:

It have two important properties it should be easy to produce and easy to


translate into target program.
Three address code consist of sequence of instruction , each code which has
at most three operands.

5) Code optimization :

The code optimization phase attempt to improve intermediate code.

This is necessary to have faster executing code or less consumption of


memory . Thus by optimising the code the overall improved.

Phases in Compiler:

Generally, phases are divided into two parts:

1. Front End phases: The front end consists of those phases or parts of
phases that are source language-dependent and target machine,
independents. These generally consist of lexical analysis, semantic analysis,
syntactic analysis, symbol table creation, and intermediate code generation. A
little part of code optimization can also be included in the front-end part. The
front-end part also includes the error handling that goes along with each of
the phases.

Front End Phases


2. Back End phases: The portions of compilers that depend on the target
machine and do not depend on the source language are included in the back
end. In the back end, code generation and necessary features of code
optimization phases, along with error handling and symbol table operations
are also included.

Back End Phases

Passes in Compiler:

A pass is a component where parts of one or more phases of the compiler are
combined when a compiler is implemented. A pass reads or scans the
instructions of the source program or the output produced by the previous
pass, which makes necessary transformation specified by its phases.

There are generally two types of passes

1. One-pass

2. Two-pass

Grouping

Several phases are grouped together to a pass so that it can read the input
file and write an output file.

1. One-Pass – In One-pass all the phases are grouped into one phase.

The six phases are included here in one pass.


2. Two-Pass – In Two-pass the phases are divided into two parts i.e.

Analysis or Front End part of the compiler and the synthesis part or

back end part of the compiler.

Purpose of One Pass Compiler

One Pass Compiler

A one-pass compiler generates a structure of machine instructions as it looks


like a stream of instructions and then sums up with machine address for
these guidelines to a rundown of directions to be backpatched once the
machine address for it is generated. It is used to pass the program for one
time. Whenever the line source is handled, it is checked and the token is
removed.
Purpose of Two-Pass Compiler

Two-Pass Compiler

A two-pass compiler utilises its first pass to go into its symbol table a
rundown of identifiers along with the memory areas to which these
identifiers relate. Then, at that point, a second pass replaces mnemonic
operation codes by their machine language equivalent and replaced uses of
identifiers by their machine address. In the second pass, the compiler can
read the result document delivered by the first pass, assemble the syntactic
tree and deliver the syntactical examination. The result of this stage is a
record that contains the syntactical tree.

You might also like