You are on page 1of 66

Royal College of Engineering and Technology

NAAC Accredited Institution


(Approved by AICTE & Affiliated to APJ Abdul Kalam Technological University)
Akkikavu, Chiramanangad PO,Thrissur – 680 604.
(Sponsored by Royal Educational Society & Research Foundation)

CSL411

COMPILER LAB
Lab Manual(2019 Scheme)
Royal College of Engineering and Technology
NAAC Accredited Institution
(Affiliated to APJ Abdul Kalam Technological University)
Akkikavu, Chiramanangad PO., Thrissur – 680 604.
(Sponsored by Royal Educational Society & Research Foundation)

Compiler Lab
(Academic Year – 20__ / 20__)

Name of the Student


:………………………………………
Roll No : ………………..… Register No
:……………
Branch :…………………. Semester : S7
Faculty-in-charge
:……………………………………….

2
Royal College of Engineering and Technology
NAAC Accredited Institution
(Affiliated to APJ Abdul Kalam Technological University)
Akkikavu, Chiramanangad PO., Thrissur – 680 604.
(Sponsored by Royal Educational Society & Research Foundation)

Compiler Lab Manual


Bonafide Certificate
Registration No

Certified that this is the bonafide record of work done by Mr / Ms


……………………...………..

……………………………………………… of …………… Semester of B.Tech


………………

……………………………………………………………… branch during the academic year


……… in the Compiler Lab.

Date : Department Seal

Staff-in-charge Head of Department

Submitted for the End Semester Practical Examination held on ......................... at

…………........

…………………………………………………………….………laboratory of Royal College

of Engineering and Technology.

Name and Signature of Examiner (s)

1.

2.

3
Department Vision

 To grow as a globally premier department of Computer Science and Engineering


capable of facing challenges of the fast pace of changes in modern Computing
industry for the betterment of Society through most appropriate and Ethical practices.

Department Mission

 To impart high quality education to students with strong foundation of Computer


Science and Engineering through Outcome Based Learning(OBE).
 To empower the students with the required skills to solve the complex technological
problems of modern society and to conduct multidisciplinary research for developing
innovative solutions.
 To provide a learning ambience to enhance innovative, problem solving skills,
leadership qualities, team spirits and ethical responsibilities with a commitment to
lifelong learning.
 To establish industry institute interaction activities to enhance the entrepreneurship
skills.

Program Educational Objectives(PEOs)

 To enable the students as an engineering specialist, who would help to solve


engineering problems in the field of Computer Science based on Industry
requirements.
 To impart the students in undergoing innovative projects which enable them to
become leaders, entrepreneurs and social reformers.
 To inculcate our students in their profession with social awareness and responsibility.
 To encourage our students in pursuing higher studies in engineering who can pursue
career paths in teaching or research.
Program Specific Outcomes (PSOs)

 Ability to analyze, design and implement ethical sustainable solutions in the field
of computer science.
 Ability to use problem solving skills in the broad area of programming concepts
and manage different projects in interdisciplinary field.
 Ability to understand the evolutionary changes in computing and creating an
innovative career path to be an entrepreneur and lifelong learner with moral values
and ethics.
Program Outcomes(POs)

1.Engineering Knowledge: Apply the knowledge of mathematics, science, engineering


fundamentals, and an engineering specialization to the solution of complex engineering
problems.

2.Problem Analysis: Identify, formulate, review research literature, and analyse complex
engineering problems reaching substantiated conclusions using first principles of
mathematics, natural sciences and engineering sciences.

4
3.Design/Development of Solutions: Design solutions for complex engineering problems
and design system components or processes that meet the specified needs with appropriate
consideration for the public health and safety, and the cultural, societal, and environmental
considerations.

4.Conduct Investigations of Complex Problems: Use research-based knowledge and


research methods including design of experiments, analysis and interpretation of data, and
synthesis of the information to provide valid conclusions for complex problems:

5.Modern Tool Usage: Create, select, and apply appropriate techniques, resources, and
modern engineering and IT tools including prediction and modelling to complex engineering
activities with an understanding of the limitations.

6.The Engineer and Society: Apply reasoning informed by the contextual knowledge to
assess societal, health, safety, legal and cultural issues and the consequent responsibilities
relevant to the professional engineering practice.

7.Environment and Sustainability: Understand the impact of the professional engineering


solutions in societal and environmental contexts, and demonstrate the knowledge of, and need
for sustainable development.

8.Ethics: Apply ethical principles and commit to professional ethics and responsibilities and
norms of the engineering practice.

9.Individual and Team Work: Function effectively as an individual, and as a member or


leader in diverse teams, and in multidisciplinary settings.

10.Communication: Communicate effectively on complex engineering activities with the


engineering community and with society at large, such as, being able to comprehend and
write effective reports and design documentation, make effective presentations, and give and
receive clear instructions.

11.Project Management and Finance: Demonstrate knowledge and understanding of the


engineering and management principles and apply these to one’s own work, as a member and
leader in a team, to manage projects and in multidisciplinary environments.

12.Life-long Learning: Recognize the need for, and have the preparation and ability to
engage in independent and lifelong learning in the broadest context of technological change.

5
Syllabus(As per University)

1. Implementation of lexical analyzer using the tool LEX.

2. Implementation of Syntax analyzer using the tool YACC.

3. Application problems using NFA and DFA.

4. Implement Top-Down Parser.

5. Implement Bottom-up parser.

6. Simulation of code optimization Techniques.

7. Implement Intermediate code generation for simple expressions.

8. Implement the back end of the compiler.

Course Outcomes

 Implement lexical analyzer using the tool LEX. (Cognitive Knowledge Level:Apply)

 Implement Syntax analyzer using the tool YACC. (Cognitive Knowledge


Level:Apply)

 Design NFA and DFA for a problem and write programs to perform operations on
it.(Cognitive Knowledge Level: Apply)

 Design and Implement Top-Down parsers. (Cognitive Knowledge Level: Apply)

 Design and Implement Bottom-Up parsers. (Cognitive Knowledge Level: Apply)

 Implement intermediate code for expressions. (Cognitive Knowledge Level: Apply)

6
Syllabus (As per University)

3 hours practical per week


Objectives
This course aims to offer students hands-on experience on compiler design concepts.
Students will be able to familiarize with tools such as LEX and YACC and automate different
phases of a compiler. This course helps the learners to enhance the capability to design and
implement a compiler.

Continuous Internal Evaluation Pattern:


Attendance : 15 marks
Continuous Evaluation in Lab : 30 marks
Continuous Assessment Test : 15 marks
Viva-voce : 15 marks

Internal Examination Pattern:


The marks will be distributed as Algorithm 30 marks,Program 20 marks, Output 20 marks
and Viva 30 marks. Total 100 marks which will be converted out of 15 while calculating
Internal Evaluation marks.

End Semester Examination Pattern:


The marks will be distributed as Algorithm 30 marks,Program 20 marks, Output 20 marks
and Viva 30 marks. Total 100 marks will be converted out of 75 for End Semester
Examination.

LABORATORY CLASSES -INSTRUCTIONS TO STUDENTS

 All students should wear neat and clean uniform with ID Cards in the lab.
 Students are not allowed to use footwear inside the lab.
 Student should enter the roll number, name, login time, logout time, and system
number in the issue register.
 Students should submit the rough record & fair record on time.
 Mobile phones are strictly prohibited inside the Lab.
 Perfect order and silence must be maintained with in the lab
 No student is permitted to enter and leave the lab without the permission of the
faculty concerned.
 Students should shut down the system and arrange the chair in proper place before
leaving the lab.
 If any damage is caused to any of the mission in the lab by any student of group of
students - the cost of the same will be recovered with fine from the particular student
or group of students.
 Students are requested to be in their lab a few minutes prior to the stroke of the bell.
 Personal chatting, mail checking, accessing unnecessary sites of not allowed in the lab

7
CONTENTS

Exp
Name of the Experiment Page No:
No:

1 Implementation of lexical analyzer using the tool LEX.

2 Implementation of Syntax analyzer using the tool YACC.

3 Application problems using NFA and DFA

4 Implement Top-Down Parser.

5 Implement Bottom-up parser

6 Simulation of code optimization Techniques.

7 Implement Intermediate code generation for simple


expressions

8 Implement the back end of the compiler

8
Practical Report Card

Contin
uous Viva- Contin
Atte
Evaluat Voice uous Signature
Sl Page nda Remar
Name of the Experiment Date ion in Mark assess of
No No nce ks
Lab(30 s ment(1 Faculty
(15)
) (15) 5)

Avg Marks

Total No of Practical Total No of


Sessions Conducted Practical Sessions
Attended

Signature of the faculty in charge Signature of Head of the Department

9
Experiment No: 1 Date: ....................

LEXICAL ANALYZER USING C

Aim:
Design and implement a lexical analyzer using C language to recognize all valid tokens in the
input program. The lexical analyzer should ignore redundant spaces, tabs and newlines. It
should also ignore comments.

Practice questions:
1. Design and implement a lexical analyzer using C language to recognize all valid
tokens in the input program. The lexical analyzer should ignore redundant spaces, tabs
and newlines. It should also ignore comments

Algorithm

Step 1 : Start the program


Step 2 : Include necessary header files.
Step 3: The ctype header file is to load the file with predicate isdigit.
Step 4 : The define directive defines the buffer size, numerics,assignment operator, relational
operator.
Step 5 : Initialize the necessary variables.
Step 6: To return index of new string S, token t using insert() function.
Step 7 : Initialize the length of every string.
Step 8: Check the necessary condition.
Step 9: Call the initialize() function. This function loads the
keywords into the symbol table.
Step 10 : Check the conditions such as white spaces, digits,letters and alphanumerics
Step 11 : To return index of entry for string S, or 0 if S is not found using lookup( ) function.
Step 12 : Check this until EOF is found.
Step 13 : Otherwise initialize the token value to be none.
Step 14 : In the main function if lookahead equals numeric then the value of attribute num is
given by the global variable tokenval.
Step 15 : Check the necessary conditions such as arithmetic operators , parenthesis ,
identifiers, assignment operators and relational operators.
Step 16 : Stop the program
10
Program

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
int isKeyword(char buffer[]){char keywords[32]
[10]={"int","char","float","for","do","double","else","if","for","goto","long","register","void"
,"whil
e","switch","return","printf"};
int i, flag = 0;
for(i = 0; i < 32; ++i){
if(strcmp(keywords[i], buffer) == 0){
flag = 1;
break;
}
}
return flag;
}
int main(){
char ch, buffer[15], operators[] = "+-*/%=";
FILE *fp;
int i,j=0;
fp=fopen("program.txt","r");
if(fp==NULL){
printf("error while opening the file\n");
exit(0);
}
while((ch=fgetc(fp))!=EOF){
for(i=0;i<6;++i){
if(ch==operators[i])
printf("%c is operator\n",ch);
}
if(isalnum(ch)){
buffer[j++] = ch;
}
else if((ch == ' ' || ch == '\n') && (j != 0)){
buffer[j] = '\0';
j = 0;
if(isKeyword(buffer) == 1)
printf("%s is keyword\n",buffer);
else
printf("%s is indentifier\n",buffer);
}
}
fclose(fp);
return 0;
}

Input
File name : program.txt
void main()
{
int a,ab,sum;
11
sum=a+ab;
printf("sum);
}

output

void is keyword
main is identifier
int is keyword
a is identifier
b is identifier
c is identifier
= is operator
+ is operator

Result:The student is able to get knowledge about designing and implementation of a lexical
analyzer using C language to recognize all valid tokens in the input program.

12
Experiment No: 2 Date: ....................

LEXICAL ANALYZER USING LEX


Aim:
Implement a Lexical Analyzer for a given program using Lex Tool.

Practice questions:
2.a.Implement a Lexical Analyzer for a given program using Lex Tool.
2.b.Write a lex program to display the number of lines, words and characters in an input text.
2.c. Write a LEX Program to convert the substring abc to ABC from the given input string.
2.d.Write a lex program to find out total number of vowels and consonants from the given
input string

Lex Tool
Lex helps write programs whose control flow is directed by instances of regular expressions
in the input stream. It is well suited for editor-script type transformations and for segmenting
input in preparation for a parsing routine.Lex source is a table of regular expressions and
corresponding program fragments. The table is translated to a program which reads an input
stream, copying it to an output stream and partitioning the input into strings which match the
given expressions. As each such string is recognized the corresponding program fragment is
executed. The recognition of the expressions is performed by a deterministic finite automaton
generated by Lex.
The program fragments written by the user are executed in the order in which the
corresponding regular expressions occur in the input stream.The lexical analysis programs
written with Lex accept ambiguous specifications and choose the longest match possible at
each input point. If necessary, substantial lookahead is performed on the input, but the input
stream will be backed up to the end of the current partition, so that the user has general
freedom to manipulate it.Lex can generate analyzers in C .
A token is a string of characters, categorized according to the rules as a symbol (e.g.,
IDENTIFIER, NUMBER, COMMA). The process of forming tokens from an input stream of
characters is called tokenization, and the lexer categorizes them according to a symbol type.
A token can look like anything that is useful for processing an input text stream or text file.

13
Algorithm:
1: Lex program contains three sections: definitions, rules, and user subroutines. Each section
must be separated from the others by a line containing only the delimiter, %%. The format
is as follows: definitions %% rules %% user_subroutines
2: In definition section, the variables make up the left column, and their definitions make up
the right column. Any C statements should be enclosed in %{..}%. Identifier is defined such
that the first letter of an identifier is alphabet and remaining letters are alphanumeric.

3: In rules section, the left column contains the pattern to be recognized in an input file to
yylex(). The right column contains the C program fragment executed when that pattern is
recognized. The various patterns are keywords, operators, new line character, number, string,
identifier, beginning and end of block, comment statements, preprocessor directive
statements etc.

4: Each pattern may have a corresponding action, that is, a fragment of C source code to
execute when the pattern is matched.

5: When yylex() matches a string in the input stream, it copies the matched text to an external
character array, yytext, before it executes any actions in the rules section.

6: In user subroutine section, main routine calls yylex(). yywrap() is used to get more input.

7: The lex command uses the rules and actions contained in file to generate a program,
lex.yy.c, which can be compiled with the cc command. That program can then receive input,
break the input into the logical pieces defined by the rules in file, and run program fragments
contained in the actions in file.

Program2.a

%option noyywrap
%{
#include<stdio.h>
%}
%%
"#include<"[a-zA-Z]+.h">" {fprintf(yyout, "%s is a header file\n",yytext);}
"main"/"int"|"float"|"for"|"if"|"printf" {fprintf(yyout, "%s is a keyword\n",yytext);}
[a-zA-Z] {fprintf(yyout, "%s is a identifier\n",yytext);}
^[a-zA-Z]+ {fprintf(yyout, "%s is a identifier\n",yytext);}
"{" {fprintf(yyout, "%s is a left brace\n",yytext);}
"}" {fprintf(yyout, "%s is a right brace\n",yytext);}
"(" {fprintf(yyout, "%s is a left paranthesis\n",yytext);}
")" {fprintf(yyout, "%s is a right paranthesis\n",yytext);}
[0-9]+ {fprintf(yyout, "%s is a number \n",yytext);}
"=" {fprintf(yyout, "%s is a assignment operator\n",yytext);}
"+"|"-"|"*"|"/" {fprintf(yyout, "%s is a operator\n",yytext);}
"++"|"--" {fprintf(yyout, "%s is a unary operator\n",yytext);}
[;:"] {fprintf(yyout, "%s is a delimiter or terminal\n",yytext);}
"&"|"|"|"&&"|"-" {fprintf(yyout, "%s is a logical operator\n",yytext);}
14
%%
int main()
{
yyin=fopen("a.c","r");
yylex();
return 0;
}

Input:
File name : a.c
a=(b+c)-(d+f)

Output:
lex lexical.l
gcc lex.yy.c
./a.out

program 2.b
Lex program to display number of lines,words and characters

%{
#include<stdio.h>
int sc=0,wc=0,lc=0,cc=0;
%}

%%
[\n] { lc++; cc+=yyleng;}
[ \t] { sc++; cc+=yyleng;}
[^\t\n ]+ { wc++; cc+=yyleng;}
%%

int main(int argc ,char* argv[ ])


{
printf("Enter the input:\n");
yylex();
printf("The number of lines=%d\n",lc);
printf("The number of spaces=%d\n",sc);
printf("The number of words=%d\n",wc);
printf("The number of characters are=%d\n",cc);
}

int yywrap( )
{
return 1;
}

Output:
lex lw.l
gcc lex.yy.c
./a.out

Enter the input:

Hello all how are you

15
we are fine
The number of lines=2
The number of spaces=6
The number of words=8
The number of characters are=34

Program 2.c
%{
#include
#include
int i;
%}
%%
[a-z A-Z]* {
for(i=0;i<=yyleng;i++)
{
if((yytext[i]=='a')&&(yytext[i+1]=='b')&&(yytext[i+2]=='c'))
{
yytext[i]='A';
yytext[i+1]='B';
yytext[i+2]='C';
}
}
printf("%s",yytext);
}
[\t]* return;
.* {ECHO;}
\n {printf("%s",yytext);}
%%
main()
{
yylex();
}
int yywrap()
{
return 1;
}

Output:

[CSE@localhost ~]$ lex lex1.l

[CSE@localhost ~]$ cc lex.yy.c

[CSE@localhost ~]$. /a.out

abc

ABC

16
Program 2.d:

/*Lex program to count the number of vowels & consonants from the given input
string.*/
%{
int ac=0;
int bc=0;
%}
%%
[aeiouAEIOU] {ac++;}
[a-zA-z] {bc++;}
%%
int yywrap() {}
int main()
{
printf("Enter the string \n");
yylex();
printf("THe number of vowels are %d\n",ac);
printf("The number of consonant is %d",bc);
return 0;
}

Output
lex demo.l
gcc lex.yy.c
./a.out
Enter some input string:Hello everyone(press contol+d after input)
Number of vowels:6
Number of consonants:7

Result:
Program to implement Lexical Analyzer using Lex is implemented and concept of Lex tool is
understood.Application programs like displaying the number of lines, words and characters in
an input text,conversion of substring abc to ABC from the given input string and counting
total number of vowels and consonants from the given input string

17
Experiment No: 3 Date: ....................

Syntax analyzer using the tool YACC

Aim:
Generate a YACC specification to recognize a valid arithmetic expression that uses operators
+, – , *,/ and parenthesis

Practice questions:
3.a Generate a YACC specification to recognize a valid arithmetic expression that
uses
operators +, – , *,/ and parenthesis.

3.b Generate a YACC specification to recognize a valid identifier which starts with a
letter followed by any number of letters or digits.

3.c Implementation of Calculator using LEX and YACC

Program 3.a:

Algorithm:

1:Start the program.

2: Reading an expression .

3: Checking the validating of the given expression according to the rule using yacc.

4: Using expression rule print the result of the given values

5: Stop the program.

Lex part
%{
#include<stdio.h>
#include "y.tab.h"
extern int yylval;
%}

%%
[0-9]+ {
yylval=atoi(yytext);

18
return NUMBER;
}
[\t] ;
[\n] return 0;
. return yytext[0];
%%
int yywrap()
{
return 1;
}
yacc part:
%{
#include<stdio.h>
int flag=0;

%}
%token NUMBER

%left '+' '-'

%left '*' '/' '%'


%left '(' ')'
%%
ArithmeticExpression: E{
printf("\nResult=%d\n",$$);
return 0;
};
E:E'+'E {$$=$1+$3;}
|E'-'E {$$=$1-$3;}
|E'*'E {$$=$1*$3;}
|E'/'E {$$=$1/$3;}
|E'%'E {$$=$1%$3;}
|'('E')' {$$=$2;}

19
| NUMBER {$$=$1;}
;
%%
void main()
{
printf("\nEnter Any Arithmetic Expression which can have operations Addition, Subtraction,
Multiplication, Divison, Modulus and Round brackets:\n");
yyparse();
if(flag==0)
printf("\nEntered arithmetic expression is Valid\n\n");
}
void yyerror()
{
printf("\nEntered arithmetic expression is Invalid\n\n");
flag=1;
}

Output:
lex h.l
yacc -d h.y
h.y:25 parser name defined to default :"parse"
gcc lex.yy.c y.tab.c -w
./a.out

Enter Any Arithmetic Expression which can have operations Addition, Subtraction,
Multiplication, Divison, Modulus and Round brackets:
(3+4)*5

Result=35
Entered arithmetic expression is Valid

20
program 3.b:
Algorithm:
Step1: Start the program

Step2: Reading an expression

Step3: Checking the validating of the given expression according to the rule using yacc.

Step4: Using expression rule print the result of the given values

Step5: Stop the program

LEX PART:

%{

#include "y.tab.h"

%}

%%

[a-zA-Z_][a-zA-Z_0-9]* return letter;

[0-9] return digit;

. return yytext[0];

\n return 0;

%%

int yywrap()

return 1;

YACC PART:

%{

#include<stdio.h>

21
int valid=1;

%}

%token digit letter

%%

start : letter s

s :letter s

digit s

%%
int yyerror()
{
printf("\nIts not a identifier!\n");
valid=0;
return 0;
}
int main()
{
printf("\nEnter a name to tested for identifier ");
yyparse();
if(valid)
{
printf("\nIt is a identifier!\n");
}}

output:

22
Program 3.c:
Algorithm:
1:A Yacc source program has three parts as follows:
Declarations %% translation rules %% supporting C routines

2: Declarations Section: This section contains entries that:

i. Include standard I/O header file.

ii. Define global variables.

iii. Define the list rule as the place to start processing.

iv. Define the tokens used by the parser. v. Define the operators and their precedence.

3: Rules Section: The rules section defines the rules that parse the input stream. Each rule of
a grammar production and the associated semantic action.

4: Programs Section: The programs section contains the following subroutines. Because
these subroutines are included in this file, it is not necessary to use the yacc library when
processing this file.

5: Main- The required main program that calls the yyparse subroutine to start the program.

6: yyerror(s) -This error-handling subroutine only prints a syntax error message.

7: yywrap -The wrap-up subroutine that returns a value of 1 when the end of input occurs.
The calc.lex file contains include statements for standard input and output, as programmar
file information if we use the -d flag with the yacc command. The y.tab.h file contains
definitions for the tokens that the parser program uses.

8: calc.lex contains the rules to generate these tokens from the input stream.

LEX PART:

%{

#include<stdio.h>

#include "y.tab.h"

extern int yylval;

%}

23
%%

[0-9]+ {

yylval=atoi(yytext);

return NUMBER;

[\t] ;

[\n] return 0;

. return yytext[0];

%%

int yywrap()

return 1;

YACC PART:

%{

#include<stdio.h>

int flag=0;

%}

%token NUMBER

%left '+' '-'

%left '*' '/' '%'

%left '(' ')'


24
%%

ArithmeticExpression: E{

printf("\nResult=%d\n",$$);

return 0;

};

E:E'+'E {$$=$1+$3;}

|E'-'E {$$=$1-$3;}

|E'*'E {$$=$1*$3;}

|E'/'E {$$=$1/$3;}

|E'%'E {$$=$1%$3;}

|'('E')' {$$=$2;}

| NUMBER {$$=$1;}

%%

void main()
{
printf("\nEnter Any Arithmetic Expression which can have operations Addition, Subtraction,
Multiplication, Divison, Modulus and Round brackets:\n");
yyparse();
if(flag==0)
printf("\nEntered arithmetic expression is Valid\n\n");
}
void yyerror()
{
printf("\nEntered arithmetic expression is Invalid\n\n");
flag=1;
}

25
output

Result:
Implementation of YACC programs and application problems including
calculator,verification of identifier,checking valid arithmetic expression etc are done.

26
Experiment No: 4 Date: ....................

Application problems using NFA and DFA

4 a) C Program to find epsilon-closure of a given NFA

Aim:

To compile a program to find epsilon closure of all states of any given nfa with epsilon
transition.

Program

// Program to find epsilon closure of a given NFA

#include<stdio.h>
#include<string.h>

char result[20][20],copy[3],states[20][20];

void add_state(char a[3],int i){


strcpy(result[i],a);
}

void display(int n){


int k=0;
printf("nnn Epsilon closure of %s = { ",copy);
while(k < n){
printf(" %s",result[k]);
k++;
}
printf(" } nnn");
}

int main(){
FILE *INPUT;
INPUT=fopen("input.dat","r");
char state[3];
int end,i=0,n,k=0;
char state1[3],input[3],state2[3];
printf("n Enter the no of states: ");
scanf("%d",&n);
printf("n Enter the states n");
for(k=0;k<3;k++){
scanf("%s",states[k]);

for( k=0;k<n;k++){
i=0;
strcpy(state,states[k]);
strcpy(copy,state);
27
add_state(state,i++);
while(1){
end = fscanf(INPUT,"%s%s%s",state1,input,state2);
if (end == EOF ){
break;
}

if( strcmp(state,state1) == 0 ){
if( strcmp(input,"e") == 0 ) {
add_state(state2,i++);
strcpy(state, state2);
}
}

}
display(i);
rewind(INPUT);
}

return 0;
}

Output:

input.dat
q0 0 q0
q0 1 q1
q0 e q1
q1 1 q2
q1 e q2

Enter the no of states: 3

Enter the states

q0
q1
q2

Epsilon closure of q0 = { q0 q1 q2 }
Epsilon closure of q1 = { q1 q2 }
Epsilon closure of q2 = { q2 }

Result: The program was executed successfully and output was obtained.

The student was able to gain the concept regarding epsilon closure,i.e, it is the initial state
and all states that can be reached directly by one or more epsilon moves.

28
4 b) C program to minimize any given dfa

Aim: To minimize a given DFA.

Algorithm:

Let the given DFA be D(Q, Σ, q0, δ, F). The output of DFA minimization D’(Q’, Σ, q0, δ’,
F’) can be created by compressing equivalent states. Two states (p, q) are called equivalent
if for every string w, either {δ(p, w), δ(q, w)} belongs to F or does not belong to F. We can
find equivalent states using the following:

1. Remove all the states that are unreachable from the initial start state.
2. Create a table of pairs (p, q) where p, q denotes some two states of Q. Initially, all the
table cells are unmarked.
3. Mark all the pairs (p, q) such that p belongs to F and q does not belong to F, or vice
versa.
4. If (p, q) is unmarked and there exists a symbol such that {δ(p, a), δ(q, a)} is marked,
then mark p and q.
5. Repeat step-4 until no new pairs get marked.
6. After completing the above process, p is equivalent to q if and only if (p, q) is
unmarked. The equivalent states can be compressed to get the minimum number of
states.

After this, we will just compress the equivalent states into a single state to get the DFA with
the minimum number of states. The above DFA minimization algorithm is called Moore’s
Algorithm.

Program:

#include <stdio.h>

#include <string.h>

#define STATES 99

#define SYMBOLS 20

int N_symbols; /* number of input symbols */

int N_DFA_states; /* number of DFA states */

char *DFA_finals; /* final-state string */

int DFAtab[STATES][SYMBOLS];

29
char StateName[STATES][STATES+1]; /* state-name table
*/

int N_optDFA_states; /* number of optimized DFA states */

int OptDFA[STATES][SYMBOLS];

char NEW_finals[STATES+1];

/*

Print state-transition table.

State names: 'A', 'B', 'C', ...

*/

void print_dfa_table(

int tab[][SYMBOLS], /* DFA table */

int nstates, /* number of states */

int nsymbols, /* number of input symbols */

char *finals)

int i, j;

puts("\nDFA: STATE TRANSITION TABLE");

/* input symbols: '0', '1', ... */

printf(" | ");

for (i = 0; i < nsymbols; i++) printf(" %c ", '0'+i);

printf("\n-----+--");

for (i = 0; i < nsymbols; i++) printf("-----");

30
printf("\n");

for (i = 0; i < nstates; i++) {

printf(" %c | ", 'A'+i); /* state */

for (j = 0; j < nsymbols; j++)

printf(" %c ", tab[i][j]); /* next state */

printf("\n");

printf("Final states = %s\n", finals);

/*

Initialize NFA table.

*/

void load_DFA_table()

DFAtab[0][0] = 'B'; DFAtab[0][1] = 'C';

DFAtab[1][0] = 'E'; DFAtab[1][1] = 'F';

DFAtab[2][0] = 'A'; DFAtab[2][1] = 'A';

DFAtab[3][0] = 'F'; DFAtab[3][1] = 'E';

DFAtab[4][0] = 'D'; DFAtab[4][1] = 'F';

DFAtab[5][0] = 'D'; DFAtab[5][1] = 'E';

DFA_finals = "EF";

N_DFA_states = 6;

N_symbols = 2;

31
}

/*

Get next-state string for current-state string.

*/

void get_next_state(char *nextstates, char *cur_states,

int dfa[STATES][SYMBOLS], int symbol)

int i, ch;

for (i = 0; i < strlen(cur_states); i++)

*nextstates++ = dfa[cur_states[i]-'A'][symbol];

*nextstates = '\0';

/*

Get index of the equivalence states for state 'ch'.

Equiv. class id's are '0', '1', '2', ...

*/

char equiv_class_ndx(char ch, char stnt[][STATES+1], int n)

int i;

for (i = 0; i < n; i++)

if (strchr(stnt[i], ch)) return i+'0';

return -1; /* next state is NOT defined */

32
/*

Check if all the next states belongs to same equivalence class.

Return value:

If next state is NOT unique, return 0.

If next state is unique, return next state --> 'A/B/C/...'

's' is a '0/1' string: state-id's

*/

char is_one_nextstate(char *s)

char equiv_class; /* first equiv. class */

while (*s == '@') s++;

equiv_class = *s++; /* index of equiv. class */

while (*s) {

if (*s != '@' && *s != equiv_class) return 0;

s++;

return equiv_class; /* next state: char type */

int state_index(char *state, char stnt[][STATES+1], int n, int *pn,

int cur) /* 'cur' is added only for 'printf()' */

int i;

33
char state_flags[STATES+1]; /* next state info. */

if (!*state) return -1; /* no next state */

for (i = 0; i < strlen(state); i++)

state_flags[i] = equiv_class_ndx(state[i], stnt, n);

state_flags[i] = '\0';

printf(" %d:[%s]\t--> [%s] (%s)\n",

cur, stnt[cur], state, state_flags);

if (i=is_one_nextstate(state_flags))

return i-'0'; /* deterministic next states */

else {

strcpy(stnt[*pn], state_flags); /* state-division info */

return (*pn)++;

/*

Divide DFA states into finals and non-finals.

*/

int init_equiv_class(char statename[][STATES+1], int n, char *finals)

int i, j;

if (strlen(finals) == n) { /* all states are final states */

34
strcpy(statename[0], finals);

return 1;

strcpy(statename[1], finals); /* final state group */

for (i=j=0; i < n; i++) {

if (i == *finals-'A') {

finals++;

} else statename[0][j++] = i+'A';

statename[0][j] = '\0';

return 2;

/*

Get optimized DFA 'newdfa' for equiv. class 'stnt'.

*/

int get_optimized_DFA(char stnt[][STATES+1], int n,

int dfa[][SYMBOLS], int n_sym, int newdfa[][SYMBOLS])

int n2=n; /* 'n' + <num. of state-division info> */

int i, j;

char nextstate[STATES+1];

for (i = 0; i < n; i++) { /* for each pseudo-DFA state */

35
for (j = 0; j < n_sym; j++) { /* for each input symbol */

get_next_state(nextstate, stnt[i], dfa, j);

newdfa[i][j] = state_index(nextstate, stnt, n, &n2, i)+'A';

return n2;

/*

char 'ch' is appended at the end of 's'.

*/

void chr_append(char *s, char ch)

int n=strlen(s);

*(s+n) = ch;

*(s+n+1) = '\0';

void sort(char stnt[][STATES+1], int n)

int i, j;

char temp[STATES+1];

for (i = 0; i < n-1; i++)

for (j = i+1; j < n; j++)

36
if (stnt[i][0] > stnt[j][0]) {

strcpy(temp, stnt[i]);

strcpy(stnt[i], stnt[j]);

strcpy(stnt[j], temp);

/*

Divide first equivalent class into subclasses.

stnt[i1] : equiv. class to be segmented

stnt[i2] : equiv. vector for next state of stnt[i1]

Algorithm:

- stnt[i1] is splitted into 2 or more classes 's1/s2/...'

- old equiv. classes are NOT changed, except stnt[i1]

- stnt[i1]=s1, stnt[n]=s2, stnt[n+1]=s3, ...

Return value: number of NEW equiv. classses in 'stnt'.

*/

int split_equiv_class(char stnt[][STATES+1],

int i1, /* index of 'i1'-th equiv. class */

int i2, /* index of equiv. vector for 'i1'-th class */

int n, /* number of entries in 'stnt' */

int n_dfa) /* number of source DFA entries */

char *old=stnt[i1], *vec=stnt[i2];

int i, n2, flag=0;


char newstates[STATES][STATES+1]; /* max. 'n' subclasses
*/

37
for (i=0; i < STATES; i++) newstates[i][0] =
'\0';

for (i=0; vec[i]; i++)

chr_append(newstates[vec[i]-'0'], old[i]);

for (i=0, n2=n; i < n_dfa; i++) {

if (newstates[i][0]) {

if (!flag) { /* stnt[i1] = s1 */

strcpy(stnt[i1], newstates[i]);

flag = 1; /* overwrite parent class */

} else /* newstate is appended in 'stnt' */

strcpy(stnt[n2++], newstates[i]);

sort(stnt, n2); /* sort equiv. classes */

return n2; /* number of NEW states(equiv. classes) */

/*

Equiv. classes are segmented and get NEW equiv. classes.

*/

int set_new_equiv_class(char stnt[][STATES+1], int n,

int newdfa[][SYMBOLS], int n_sym, int n_dfa)

int i, j, k;

38
for (i = 0; i < n; i++) {

for (j = 0; j < n_sym; j++) {

k = newdfa[i][j]-'A'; /* index of equiv. vector */

if (k >= n) /* equiv. class 'i' should be segmented */

return split_equiv_class(stnt, i, k, n, n_dfa);

return n;

void print_equiv_classes(char stnt[][STATES+1], int n)

int i;

printf("\nEQUIV. CLASS CANDIDATE ==>");

for (i = 0; i < n; i++)

printf(" %d:[%s]", i, stnt[i]);

printf("\n");

/*

State-minimization of DFA: 'dfa' --> 'newdfa'

Return value: number of DFA states.

*/

int optimize_DFA(

39
int dfa[][SYMBOLS], /* DFA state-transition table */

int n_dfa, /* number of DFA states */

int n_sym, /* number of input symbols */

char *finals, /* final states of DFA */

char stnt[][STATES+1], /* state name table */

int newdfa[][SYMBOLS]) /* reduced DFA table */

char nextstate[STATES+1];

int n; /* number of new DFA states */

int n2; /* 'n' + <num. of state-dividing info> */

n = init_equiv_class(stnt, n_dfa, finals);

while (1) {

print_equiv_classes(stnt, n);

n2 = get_optimized_DFA(stnt, n, dfa, n_sym, newdfa);

if (n != n2)

n = set_new_equiv_class(stnt, n, newdfa, n_sym, n_dfa);

else break; /* equiv. class segmentation ended!!! */

return n; /* number of DFA states */

/*

Check if 't' is a subset of 's'.

*/

40
int is_subset(char *s, char *t)

int i;

for (i = 0; *t; i++)

if (!strchr(s, *t++)) return 0;

return 1;

/*

New finals states of reduced DFA.

*/

void get_NEW_finals(

char *newfinals, /* new DFA finals */

char *oldfinals, /* source DFA finals */

char stnt[][STATES+1], /* state name table */

int n) /* number of states in 'stnt' */

int i;

for (i = 0; i < n; i++)

if (is_subset(oldfinals, stnt[i])) *newfinals++ = i+'A';

*newfinals++ = '\0';

void main()

41
load_DFA_table();

print_dfa_table(DFAtab, N_DFA_states, N_symbols, DFA_finals);

N_optDFA_states = optimize_DFA(DFAtab, N_DFA_states,

N_symbols, DFA_finals, StateName, OptDFA);


get_NEW_finals(NEW_finals, DFA_finals, StateName, N_optDFA_states);

print_dfa_table(OptDFA, N_optDFA_states, N_symbols, NEW_finals);


}

Output:

DFA: STATE TRANSITION TABLE

| 0 1

-----+------------

A | B C

B | E F

C | A A

D | F E

E | D F

F | D E

Final states = EF

EQUIV. CLASS CANDIDATE ==> 0:[ABCD] 1:[EF]

0:[ABCD] --> [BEAF] (0101)

0:[ABCD] --> [CFAE] (0101)

1:[EF] --> [DD] (00)

1:[EF] --> [FE] (11)

EQUIV. CLASS CANDIDATE ==> 0:[AC] 1:[BD] 2:[EF]


42
0:[AC] --> [BA] (10)

0:[AC] --> [CA] (00)

1:[BD] --> [EF] (22)

1:[BD] --> [FE] (22)

2:[EF] --> [DD] (11)

2:[EF] --> [FE] (22)

EQUIV. CLASS CANDIDATE ==> 0:[A] 1:[BD] 2:[C] 3:[EF]

0:[A] --> [B] (1)

0:[A] --> [C] (2)

1:[BD] --> [EF] (33)

1:[BD] --> [FE] (33)

2:[C] --> [A] (0)

2:[C] --> [A] (0)

3:[EF] --> [DD] (11)

3:[EF] --> [FE] (33)

DFA: STATE TRANSITION TABLE

| 0 1

-----+------------

A | B C

B | D D

C | A A

D | B D

Final states = D

Result: The program was executed successfully and output was obtained. The student was
able to gain the idea about Moore’s law and the concept of DFA Minimization by
compressing equivalent states.Eevery pair of states are compared to check for equivalence
until no new equivalent states are found.

43
Experiment No: 5 Date: ....................

Simulation of Parsing Techniques

5 a) Write a program to find first and follow of a given grammar.

Aim: To write a C program to find first and follow of a given grammar.

ALGORITHM:

FIRST (α) is defined as the collection of terminal symbols which are the first letters of
strings derived from α.

FIRST (α) = {α |α →∗ αβ for some string β }


If X is Grammar Symbol, then First (X) will be −
 If X is a terminal symbol, then FIRST(X) = {X}
 If X → ε, then FIRST(X) = {ε}
 If X is non-terminal & X → a α, then FIRST (X) = {a}
 If X → Y1, Y2, Y3, then FIRST (X) will be

(a) If Y is terminal, then

FIRST (X) = FIRST (Y1, Y2, Y3) = {Y1}


(b) If Y1 is Non-terminal and

If Y1 does not derive to an empty string i.e., If FIRST (Y 1) does not contain ε then,
FIRST (X) = FIRST (Y1, Y2, Y3) = FIRST(Y1)
(c) If FIRST (Y1) contains ε, then.

FIRST (X) = FIRST (Y1, Y2, Y3) = FIRST(Y1) − {ε} ∪ FIRST(Y2, Y3)
Similarly, FIRST (Y2, Y3) = {Y2}, If Y2 is terminal otherwise if Y2 is Non-terminal then

 FIRST (Y2, Y3) = FIRST (Y2), if FIRST (Y2) does not contain ε.

 If FIRST (Y2) contain ε, then

 FIRST (Y2, Y3) = FIRST (Y2) − {ε} ∪ FIRST (Y3)

Similarly, this method will be repeated for further Grammar symbols, i.e., for Y4, Y5, Y6
… . YK.

Computation of FOLLOW
Follow (A) is defined as the collection of terminal symbols that occur directly to the
right of A.
FOLLOW(A) = {a|S ⇒* αAaβ where α, β can be any strings}

Rules to find FOLLOW


 If S is the start symbol, FOLLOW (S) ={$}

44
 If production is of form A → α B β, β ≠ ε.

(a) If FIRST (β) does not contain ε then, FOLLOW (B) = {FIRST (β)}

Or

(b) If FIRST (β) contains ε (i. e. , β ⇒* ε), then


FOLLOW (B) = FIRST (β) − {ε} ∪ FOLLOW (A)
∵ when β derives ε, then terminal after A will follow B.
 If production is of form A → αB, then Follow (B) ={FOLLOW (A)}.

Program:

#include<stdio.h>

#include<string.h>

int i,j,l,m,n=0,o,p,nv,z=0,x=0;

char str[10],temp,temp2[10],temp3[20],*ptr;

struct prod

char lhs[10],rhs[10][10],ft[10],fol[10];

int n;

}pro[10];

void findter()

int k,t;

for(k=0;k<n;k++)

if(temp==pro[k].lhs[0])

for(t=0;t<pro[k].n;t++)

{
45
if( pro[k].rhs[t][0]<65 || pro[k].rhs[t][0]>90 )

pro[i].ft[strlen(pro[i].ft)]=pro[k].rhs[t][0];

else if( pro[k].rhs[t][0]>=65 && pro[k].rhs[t][0]<=90 )

temp=pro[k].rhs[t][0];

if(temp=='S')

pro[i].ft[strlen(pro[i].ft)]='#';

findter();

break;

void findfol()

int k,t,p1,o1,chk;

char *ptr1;

for(k=0;k<n;k++)

chk=0;

for(t=0;t<pro[k].n;t++)

ptr1=strchr(pro[k].rhs[t],temp);

if( ptr1 )

p1=ptr1-pro[k].rhs[t];

if(pro[k].rhs[t][p1+1]>=65 && pro[k].rhs[t][p1+1]<=90)

46
{

for(o1=0;o1<n;o1++)

if(pro[o1].lhs[0]==pro[k].rhs[t][p1+1])

strcat(pro[i].fol,pro[o1].ft);

chk++;

else if(pro[k].rhs[t][p1+1]=='\0')

temp=pro[k].lhs[0];

if(pro[l].rhs[j][p]==temp)

continue;

if(temp=='S')

strcat(pro[i].fol,"$");

findfol();

chk++;

else

pro[i].fol[strlen(pro[i].fol)]=pro[k].rhs[t][p1+1];

chk++;

if(chk>0)

break;

47
int main()

FILE *f;

//clrscr();

for(i=0;i<10;i++)

pro[i].n=0;

f=fopen("tab5.txt","r");

while(!feof(f))

fscanf(f,"%s",pro[n].lhs);

if(n>0)

if( strcmp(pro[n].lhs,pro[n-1].lhs) == 0 )

pro[n].lhs[0]='\0';

fscanf(f,"%s",pro[n-1].rhs[pro[n-1].n]);

pro[n-1].n++;

continue;

fscanf(f,"%s",pro[n].rhs[pro[n].n]);

pro[n].n++;

n++;

printf("\n\nTHE GRAMMAR IS AS FOLLOWS\n\n");

48
for(i=0;i<n;i++)

for(j=0;j<pro[i].n;j++)

printf("%s -> %s\n",pro[i].lhs,pro[i].rhs[j]);

pro[0].ft[0]='#';

for(i=0;i<n;i++)

for(j=0;j<pro[i].n;j++)

if( pro[i].rhs[j][0]<65 || pro[i].rhs[j][0]>90 )

pro[i].ft[strlen(pro[i].ft)]=pro[i].rhs[j][0];

else if( pro[i].rhs[j][0]>=65 && pro[i].rhs[j][0]<=90 )

temp=pro[i].rhs[j][0];

if(temp=='S')

pro[i].ft[strlen(pro[i].ft)]='#';

findter();

printf("\n\nFIRST\n");

for(i=0;i<n;i++)

printf("\n%s -> ",pro[i].lhs);

for(j=0;j<strlen(pro[i].ft);j++)

49
for(l=j-1;l>=0;l--)

if(pro[i].ft[l]==pro[i].ft[j])

break;

if(l==-1)

printf("%c",pro[i].ft[j]);

for(i=0;i<n;i++)

temp2[i]=pro[i].lhs[0];

pro[0].fol[0]='$';

for(i=0;i<n;i++)

for(l=0;l<n;l++)

for(j=0;j<pro[i].n;j++)

ptr=strchr(pro[l].rhs[j],temp2[i]);

if( ptr )

p=ptr-pro[l].rhs[j];

if(pro[l].rhs[j][p+1]>=65 && pro[l].rhs[j][p+1]<=90)

for(o=0;o<n;o++)

if(pro[o].lhs[0]==pro[l].rhs[j][p+1])

strcat(pro[i].fol,pro[o].ft);

else if(pro[l].rhs[j][p+1]=='\0')

50
temp=pro[l].lhs[0];

if(pro[l].rhs[j][p]==temp)

continue;

if(temp=='S')

strcat(pro[i].fol,"$");

findfol();

else

pro[i].fol[strlen(pro[i].fol)]=pro[l].rhs[j][p+1];

printf("\n\nFOLLOW\n");

for(i=0;i<n;i++)

printf("\n%s -> ",pro[i].lhs);

for(j=0;j<strlen(pro[i].fol);j++)

for(l=j-1;l>=0;l--)

if(pro[i].fol[l]==pro[i].fol[j])

break;

if(l==-1)

printf("%c",pro[i].fol[j]);

printf("\n");

//getch();

51
}

Output:

gedit tab5.txt

S ABE

Sa

Ap

At

B Aq

Sf

Aw

THE GRAMMAR IS AS FOLLOWS

S -> ABE

S -> a

A -> p

A -> t

B -> Aq

S -> f

A -> w

->

FIRST

S -> #pta

A -> pt

B -> pt

52
S -> f

A -> w

->

FOLLOW

S -> $

A -> ptq

B ->

S ->

A -> ptq

Result:

The program was executed successfully and output was obtained. The student was able to
gain the concept of First and Follow.

FIRST is a function that gives the set of terminals that begin the strings derived from the
production rule.

FOLLOW (A) is defined as the collection of terminal symbols that occur directly to the
right of A.

5 b) Program to implement a recursive descent parser for a given language.

Aim: To write a C program to design and implement a recursive descent parser for a given
language.

Algorithm:

Recursive-descent parsing is one of the simplest parsing techniques that is used in practice.
Recursive-descent parsers are also called top-down parsers, since they construct the parse
tree top down (rather than bottom up).

The basic idea of recursive-descent parsing is to associate each non-terminal with a


procedure. The goal of each such procedure is to read a sequence of input characters that can
be generated by the corresponding non-terminal, and return a pointer to the root of the parse
tree for the non-terminal. The structure of the procedure is dictated by the productions for
the corresponding non-terminal.
The procedure attempts to "match" the right hand side of some production for a non-
terminal.

53
 To match a terminal symbol, the procedure compares the terminal symbol to the
input; if they agree, then the procedure is successful, and it consumes the terminal
symbol in the input (that is, moves the input cursor over one symbol).

 To match a non-terminal symbol, the procedure simply calls the corresponding


procedure for that non-terminal symbol (which may be a recursive call, hence the
name of the technique).

Program:

#include<stdio.h>

#include<string.h>

#include<ctype.h>

char input[10];

int i,error;

void E();

void T();

void Eprime();

void Tprime();

void F();

main()

i=0;

error=0;

printf("Enter an arithmetic expression : "); // Eg: a+a*a

gets(input);

E();

if(strlen(input)==i&&error==0)

printf("\nAccepted..!!!\n");

else printf("\nRejected..!!!\n");

54
void E()

T();

Eprime();

void Eprime()

if(input[i]=='+')

i++;

T();

Eprime();

void T()

F();

Tprime();

void Tprime()

if(input[i]=='*')

i++;

F();

Tprime();

55
}

void F()

if(isalnum(input[i]))i++;

else if(input[i]=='(')

i++;

E();

if(input[i]==')')

i++;

else error=1;

else error=1;

Output:

Enter an arithmetic expression : a+a*a

Accepted..!!!

Enter an arithmetic expression : ++a

Rejected..!!!

Result:

The program was executed successfully and output was obtained. The student was able to
gain the concept and come to conclusion that :

a+(a*a) a+a*a , (a), a , a+a+a*a+a.... etc are accepted


++a, a***a, +a, a*, ((a . . . etc are rejected.

56
Experiment No: 6 Date: ....................

Simulation of code optimization Techniques

Aim:
To simulate code optimization technique for constant propagation
Practice questions:
1.Write a program to perform constant propagation.
Algorithm:
1. For all 4-tuples do
1.1 get next 4-tuple
1.2 If the operator is "Label" then
1.2.1 free the constant table
1.2.2 write the 4-tuple
1.3 If either or both of the operands are in the constant table then
1.3.1 substitute the constant value(s) for the operand(s)
1.3.2 if either of the operands are intermediate results then
1.3.2.1 remove those operand(s) from the constant table.
1.4 if 4-tuple operand(s) are constant then
1.4.1 if operator is "JPCT" then
1.4.1.1 if the operand is true then
1.4.1.1.1 replace the JPCT with JP
1.4.1.1.2 write the new 4-tuple else
1.4.1.1.3 eliminate the 4-tuple
1.4.2 if operator is "=" then
1.4.2.1 place the variable and constant in the constant table
57
1.4.2.2 write the 4-tuple with the constant operand
1.4.3 else
1.4.3.1 Perform the operation.
1.4.3.2 Place the intermediate result name and constant value in the constant
table.Else
1.4.4 write the 4-tuple Consider the following sequence.

PROGRAM:

#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<conio.h>
void input();
void output();
void change(int p,char *res);
void constant();
struct expr
{
char op[2],op1[5],op2[5],res[5];
int flag;
}arr[10];
int n;
void main()
{
clrscr();
input();
constant();
output();
getch();
}
void input()
{
int i;
printf("\n\nEnter the maximum number of expressions : ");
scanf("%d",&n);
printf("\nEnter the input : \n");
for(i=0;i<n;i++)
{
scanf("%s",arr[i].op);
scanf("%s",arr[i].op1);
scanf("%s",arr[i].op2);
scanf("%s",arr[i].res);
arr[i].flag=0;
}
}
58
void constant()
{
int i;
int op1,op2,res;
char op,res1[5];
for(i=0;i<n;i++)
{
if(isdigit(arr[i].op1[0]) && isdigit(arr[i].op2[0]) || strcmp(arr[i].op,"=")==0) /*if both digits,
store them in variables*/
{
op1=atoi(arr[i].op1);
op2=atoi(arr[i].op2);
op=arr[i].op[0];
switch(op)
{
case '+':
res=op1+op2;
break;
case '-':
res=op1-op2;
break;
case '*':
res=op1*op2;
break;
case '/':
res=op1/op2;
break;
case '=':
res=op1;
break;
}
sprintf(res1,"%d",res);
arr[i].flag=1; /*eliminate expr and replace any operand below that uses result of this expr */
change(i,res1);
}
}
}
void output()
{
int i=0;
printf("\nOptimized code is : ");
for(i=0;i<n;i++)
{
if(!arr[i].flag)
{
printf("\n%s %s %s %s",arr[i].op,arr[i].op1,arr[i].op2,arr[i].res);
}
}
59
}
void change(int p,char *res)
{
int i;
for(i=p+1;i<n;i++)
{
if(strcmp(arr[p].res,arr[i].op1)==0)
strcpy(arr[i].op1,res);
else if(strcmp(arr[p].res,arr[i].op2)==0)
strcpy(arr[i].op2,res);
}
}

INPUT:

Enter the maximum number of expressions : 4

Enter the input :


=3-a
+ a b t1
+ a c t2
+ t1 t2 t3

OUTPUT:

Optimized code is :
+ 3 b t1
+ 3 c t2
+ t1 t2 t3

Result:
optimization using constant propagation is implemented and optimized code is obatined.

60
Experiment No: 7 Date: ....................
Intermediate code generation for simple expressions.
Aim:
Implement Intermediate code generation for simple expressions.
Practice question:
1.Generate code for intermediate code generation of a simple expression.

Algorithm
1.Start
2.Read variables,
3.Open file input.txt and output.text
4.Read the contents of the file input.text and evaluate the expression
5.Close the files
6.Stop
PROGRAM:

#include<stdio.h>
#include<conio.h>
#include<string.h>
char op[2],arg1[5],arg2[5],result[5];
void main()
{
FILE *fp1,*fp2;
fp1=fopen("input.txt","r");
fp2=fopen("output.txt","w");
while(!feof(fp1))
{

fscanf(fp1,"%s%s%s%s",op,arg1,arg2,result);
if(strcmp(op,"+")==0)
{
fprintf(fp2,"\nMOV R0,%s",arg1);
fprintf(fp2,"\nADD R0,%s",arg2);
fprintf(fp2,"\nMOV %s,R0",result);
}
if(strcmp(op,"*")==0)
{
fprintf(fp2,"\nMOV R0,%s",arg1);
fprintf(fp2,"\nMUL R0,%s",arg2);
fprintf(fp2,"\nMOV %s,R0",result);
}
if(strcmp(op,"-")==0)
{

61
fprintf(fp2,"\nMOV R0,%s",arg1);
fprintf(fp2,"\nSUB R0,%s",arg2);
fprintf(fp2,"\nMOV %s,R0",result);
}
if(strcmp(op,"/")==0)
{
fprintf(fp2,"\nMOV R0,%s",arg1);
fprintf(fp2,"\nDIV R0,%s",arg2);
fprintf(fp2,"\nMOV %s,R0",result);
}
if(strcmp(op,"=")==0)
{
fprintf(fp2,"\nMOV R0,%s",arg1);
fprintf(fp2,"\nMOV %s,R0",result);
}
}
fclose(fp1);
fclose(fp2);
getch();
}
}
Input.txt

+ a b t1
* c d t2
- t1 t2 t
=t?x

Output.txt

MOV R0,a
ADD R0,b
MOV t1,R0
MOV R0,c
MUL R0,d
MOV t2,R0
MOV R0,t1
SUB R0,t2
MOV t,R0
MOV R0,t
MOV x,R0

Result:
Intermediate code generation for simple expressions is implemented.

62
Experiment :8 Date……………..

Implement the back end of the compiler.

Aim:

Implement the back end of the compiler.

Practice question:

Implement the back end of the compiler which takes the three address code and produces the
8086 assembly language instructions that can be assembled and run using an 8086 assembler.
The target assembly instructions can be simple move, add, sub, jump etc.

ALGORITHM:
1. Start the program
2. Open the source file and store the contents as quadruples.
3. Check for operators, in quadruples, if it is an arithmetic operator generator it or if
assignment operator generates it, else perform unary minus on register C.
4. Write the generated code into output definition of the file in outp.c
5. Print the output.
6. Stop the program.

Program

#include <stdio.h>

#include <stdio.h>

//#include<conio.h>

#include <string.h>

void main()

char icode[10][30], str[20], opr[10];

int i = 0;

//clrscr();

printf("\n Enter the set of intermediate code (terminated by exit) :\n ");

do
63
{

scanf("%s", icode[i]);

} while (strcmp(icode[i++], "exit") != 0);

printf("\n target code generation");

printf("\n************************");

i = 0;

do

strcpy(str, icode[i]);

switch (str[3])

case '+':

strcpy(opr, "ADD");

break;

case '-':

strcpy(opr, "SUB");

break;

case '*':

strcpy(opr, "MUL");

break;

case '/':

strcpy(opr, "DIV");

break;

printf("\n\tMov %c,R%d", str[2], i);

printf("\n\t%s%c,R%d", opr, str[4], i);

printf("\n\tMov R%d,%c", i, str[0]);

} while (strcmp(icode[++i], "exit") != 0);

//getch();

64
}

Result:
Program for the back end of the compiler which takes the three address code and produces
the 8086 assembly language instructions that can be assembled and run using an 8086
assembler is implemented.

65
66

You might also like