Compiler Design Lab

Download as pdf or txt
Download as pdf or txt
You are on page 1of 26

Compiler Design Lab [KCS -552]

FOR
ACADEMIC YEAR 2022-2023

BUNDELKHAND INSTITUTE OF ENGINEERING AND


TECHNOLOGY, JHANSI
(BIET JHANSI)-284128

Submitted to: - Submitted by: -


Er. Hemant Kushwaha Akhilesh Tyagi
Roll No. 2004310012
INDEX

Name: Akhilesh Tyagi Roll No.:2004310012

S.No. Date Aim/Objective T. Sign

1 Design and implement a lexical analyzer for given language


using C and the lexical analyzer should ignore redundant
spaces, tabs, and new lines.

2 Implementation of Lexical Analyzer using Lex Tool

3(a) Program to recognize a valid arithmetic expression that uses


operator +, - , * and /.

3(b) Program to recognize a valid variable which starts with a letter


followed by any number of letters or digits.

4 Write program to find ε – closure of all states of any given NFA


with ε transition.

5 Develop an operator precedence parser for a given language

6 Construct a Shift Reduce Parser for a given language.

7 Write a program to perform loop unrolling

8 Write a program to perform constant propagation.

9 Implement Intermediate code generation for simple


expressions.

10 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.
Practical -1
Design and implement a lexical analyzer for given language using C and
the lexical analyzer should ignore redundant spaces, tabs, and new
lines.

PROGRAM:
#include<string.h>
#include<ctype.h>
#include<stdio.h>
void keyword(char str[10])
{
if(strcmp("for",str)==0||strcmp("while",str)==0||strcmp("do",str)==0||
strcmp("int",str)==0||strcmp("float",str)==0||strcmp("char",str)==0||strcmp("double",str)==
0||

strcmp("static",str)==0||strcmp("switch",str)==0||strcmp("case",str)==0)
printf("\n%s is a keyword",str);
else
printf("\n%s is an identifier",str);
}

main()
{
FILE *f1,*f2,*f3;
char c,str[10],st1[10];
int num[100],lineno=0,tokenvalue=0,i=0,j=0,k=0;
printf("\nEnter the c program");/*gets(st1);*/
f1=fopen("input","w");
while((c=getchar())!=EOF)
putc(c,f1);
fclose(f1);
f1=fopen("input","r");
f2=fopen("identifier","w");
f3=fopen("specialchar","w");
while((c=getc(f1))!=EOF){
if(isdigit(c))
{
tokenvalue=c-'0';
c=getc(f1);
while(isdigit(c)){
tokenvalue*=10+c-'0';
c=getc(f1);
}
num[i++]=tokenvalue;
ungetc(c,f1);
}
else if(isalpha(c))
{
putc(c,f2);
c=getc(f1);
while(isdigit(c)||isalpha(c)||c=='_'||c=='$')
{
putc(c,f2);
c=getc(f1);
}
putc(' ',f2);
ungetc(c,f1);
}
else if(c==' '||c=='\t')
printf(" ");
else
if(c=='\n')
lineno++;
else
putc(c,f3);
}
fclose(f2);
fclose(f3);
fclose(f1);
printf("\nThe no's in the program are");
for(j=0;j<i;j++)
printf("%d",num[j]);
printf("\n");
f2=fopen("identifier","r");
k=0;
printf("The keywords and identifiersare:");
while((c=getc(f2))!=EOF){
if(c!=' ')
str[k++]=c;
else
{
str[k]='\0';
keyword(str);
k=0;
}
}
fclose(f2);
f3=fopen("specialchar","r");
printf("\nSpecial characters are");
while((c=getc(f3))!=EOF)
printf("%c",c);
printf("\n");
fclose(f3);
printf("Total no. of lines are:%d",lineno);
}

Input:
Enter Program $ for termination:
{
int a[3],t1,t2;
t1=2; a[0]=1; a[1]=2; a[t1]=3;
t2=-(a[2]+t1*6)/(a[2]-t1);
if t2>5 then
print(t2);
else {
int t3;
t3=99;
t2=-25;
print(-t1+t2*t3); /* this is a comment on 2 lines */
} endif
}

Output:
Variables : a[3] t1 t2 t3
Operator : - + * / >
Constants : 2 1 3 6 5 99 -25
Keywords : int if then else endif
Special Symbols : , ; ( ) { }
Comments : this is a comment on 2 lines
Practical -2
Implementation of Lexical Analyzer using Lex Tool
Program-
/* program name is lexp.l */
%{
/* program to recognize a c program */
int COMMENT=0;
int cnt=0;
%}
identifier [a-zA-Z][a-zA-Z0-9]*
%%
#.* { printf("\n%s is a PREPROCESSOR DIRECTIVE",yytext);}
int |
float |
char |
double |
while |
for |
do |
if |
break |
continue |
void |
switch |
case |
long |
struct |
const |
typedef |
return |
else |
goto {printf("\n\t%s is a KEYWORD",yytext);}
"/*" {COMMENT = 1;}
"*/" {COMMENT = 0; cnt++;}
{identifier}\( {if(!COMMENT)printf("\n\nFUNCTION\n\t%s",yytext);}
\{ {if(!COMMENT) printf("\n BLOCK BEGINS");}
\} {if(!COMMENT) printf("\n BLOCK ENDS");}
{identifier}(\[[0-9]*\])? {if(!COMMENT) printf("\n %s IDENTIFIER",yytext);}
\".*\" {if(!COMMENT) printf("\n\t%s is a STRING",yytext);}
[0-9]+ {if(!COMMENT) printf("\n\t%s is a NUMBER",yytext);}
\)(\;)? {if(!COMMENT) printf("\n\t");ECHO;printf("\n");}
\( ECHO;
= {if(!COMMENT)printf("\n\t%s is an ASSIGNMENT OPERATOR",yytext);}
\<= |
\>= |
\< |
== |
\> {if(!COMMENT) printf("\n\t%s is a RELATIONAL OPERATOR",yytext);}
%%
int main(int argc,char **argv)
{
if (argc > 1)
{
FILE *file;
file = fopen(argv[1],"r");
if(!file)
{
printf("could not open %s \n",argv[1]);
exit(0);
}
yyin = file;
}
yylex();
printf("\n\n Total No.Of comments are %d",cnt);
return 0;
}
int yywrap()
{
return 1;

Input:
#include<stdio.h>
main()
{
int a,b;
}
Output:
#include<stdio.h> is a PREPROCESSOR DIRECTIVE
FUNCTION
main (
)
BLOCK BEGINS
int is a KEYWORD
a IDENTIFIER
b IDENTIFIER
BLOCK ENDS
Practical -3(a)
Program to recognize a valid arithmetic expression that uses
operator +, - , * and /.

Program:-
%{
/* This LEX program returns the tokens for the expression */
#include “y.tab.h”
%}

%%
“=” {printf(“\n Operator is EQUAL”);}
“+” {printf(“\n Operator is PLUS”);}
“-“ {printf(“\n Operator is MINUS”);}
“/” {printf(“\n Operator is DIVISION”);}
“*” {printf(“\n Operator is MULTIPLICATION”);}

[a-z A-Z]*[0-9]* {
printf(“\n Identifier is %s”,yytext);
return ID;
}
return yytext[0];
\n return 0;
%%

int yywrap()
{
return 1;
}

Program Name : arith_id.y

%{
#include
/* This YYAC program is for recognizing the Expression */
%}
%%
statement: A’=’E
|E{
printf(“\n Valid arithmetic expression”);
$$ = $1;
};

E: E’+’ID
| E’-’ID
| E’*’ID
| E’/’ID
| ID
;
%%
extern FILE *yyin;
main()
{
do
{
yyparse();
}while(!feof(yyin));
}

yyerror(char*s)
{
}

Output:

[root@localhost]# lex arith_id.1


[root@localhost]# yacc –d arith_id.y
[root@localhost]# gcc lex.yy.c y.tab.c
[root@localhost]# ./a.out
x=a+b;

Identifier is x
Operator is EQUAL
Identifier is a
Operator is PLUS
Identifier is b

Practical -3(b)
Program to recognize a valid variable which starts with a letter
followed by any number of letters or digits.
Program name: variable_test.l

%{
/* This LEX program returns the tokens for the Expression */
#include "y.tab.h"
%}
%%
"int " {return INT;}
"float" {return FLOAT;}
"double" {return DOUBLE;}
[a-zA-Z]*[0-9]*{
printf("\nIdentifier is %s",yytext);
return ID;
}
return yytext[0];
\n return 0;
int yywrap()
{
return 1;
}

Program name: variable_test.y

%{
#include
/* This YACC program is for recognising the Expression*/
%}
%token ID INT FLOAT DOUBLE
%%
D;T L
;
L:L,ID
|ID
;
T:INT
|FLOAT
|DOUBLE
;
%%
extern FILE *yyin;
main()
{
do
{
yyparse();
}while(!feof(yyin));
}
Practical -4
Write program to find ε – closure of all states of any given NFA with
ε transition.
Program: -
#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);
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;
}
Input-
q0 0 q0
q0 1 q1
q0 e q1
q1 1 q2
q1 e q2
Output-
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 }

Practical -5
Develop an operator precedence parser for a given language
Program: -
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
// function f to exit from the loop
// if given condition is not true
void f()
{
printf("Not operator grammar");
exit(0);
}
void main()
{
char grm[20][20], c;
// Here using flag variable,
// considering grammar is not operator grammar
int i, n, j = 2, flag = 0;
// taking number of productions from user
scanf("%d", &n);
for (i = 0; i < n; i++)
scanf("%s", grm[i]);
for (i = 0; i < n; i++) {
c = grm[i][2];
while (c != '\0') {
if (grm[i][3] == '+' || grm[i][3] == '-'
|| grm[i][3] == '*' || grm[i][3] == '/')
flag = 1;
else {

flag = 0;
f();
}
if (c == '$') {
flag = 0;
f();
}
c = grm[i][++j];
}
}

if (flag == 1)
printf("Operator grammar");
}
Practical -6
Construct a Shift Reduce Parser for a given language.
Program: -
// Including Libraries
#include <bits/stdc++.h>
using namespace std;

// Global Variables
int z = 0, i = 0, j = 0, c = 0;

// Modify array size to increase


// length of string to be parsed
char a[16], ac[20], stk[15], act[10];

// This Function will check whether


// the stack contain a production rule
// which is to be Reduce.
// Rules can be E->2E2 , E->3E3 , E->4
void check()
{
// Copying string to be printed as action
strcpy(ac,"REDUCE TO E -> ");

// c=length of input string


for(z = 0; z < c; z++)
{
// checking for producing rule E->4
if(stk[z] == '4')
{
printf("%s4", ac);
stk[z] = 'E';
stk[z + 1] = '\0';

//printing action
printf("\n$%s\t%s$\t", stk, a);
}
}

for(z = 0; z < c - 2; z++)


{
// checking for another production
if(stk[z] == '2' && stk[z + 1] == 'E' &&
stk[z + 2] == '2')
{
printf("%s2E2", ac);
stk[z] = 'E';
stk[z + 1] = '\0';
stk[z + 2] = '\0';
printf("\n$%s\t%s$\t", stk, a);
i = i - 2;
}

for (z = 0; z < c - 2; z++)


{
//checking for E->3E3
if(stk[z] == '3' && stk[z + 1] == 'E' && stk[z + 2] == '3')
{
printf("%s3E3", ac);
stk[z]='E';
stk[z + 1]='\0';
stk[z + 1]='\0';
printf("\n$%s\t%s$\t", stk, a);
i = i - 2;
}
}
return; // return to main
}

// Driver Function
int main ()
{
printf("GRAMMAR is -\nE->2E2 \nE->3E3 \nE->4\n");

// a is input string
strcpy(a,"32423");

// strlen(a) will return the length of a to c


c=strlen(a);

// "SHIFT" is copied to act to be printed


strcpy(act,"SHIFT");

// This will print Labels (column name)


printf("\nstack \t input \t action");

// This will print the initial


// values of stack and input
printf("\n$\t%s$\t", a);

// This will Run upto length of input string


for (i = 0; j < c; i++, j++)
{
// Printing action
printf("%s", act);

// Pushing into stack


stk[i] = a[j];
stk[i + 1] = '\0';

// Moving the pointer


a[j]=' ';
// Printing action
printf("\n$%s\t%s$\t", stk, a);

// Call check function ..which will


// check the stack whether its contain
// any production or not
check();
}
// Rechecking last time if contain
// any valid production then it will
// replace otherwise invalid
check();

// if top of the stack is E(starting symbol)


// then it will accept the input
if(stk[0] == 'E' && stk[1] == '\0')
printf("Accept\n");
else //else reject
printf("Reject\n");
}
Practical -7
Write a program to perform loop unrolling
Program 1:
// This program does not use loop unrolling.
#include<stdio.h>

int main(void)
{
for (int i=0; i<5; i++)
printf("Hello\n"); //print hello 5 times

return 0;
}

Program 2:
// This program uses loop unrolling.
#include<stdio.h>

int main(void)
{
// unrolled the for loop in program 1
printf("Hello\n");
printf("Hello\n");
printf("Hello\n");
printf("Hello\n");
printf("Hello\n");

return 0;
}
Practical -8
Write a program to perform constant propagation.
Program: -

#include <stdio.h>
int main ()
{
int c;
float r, pi = floor((22.0 / 7.0)*100)/100;//pi value is calculated by 22/7 and assigned to pi variable
do
{
printf ("\nMENU");
printf
("\n1. Find perimeter and area of circle without constant propagation");
printf
("\n2. Find perimeter and area of circle with constant propagation Code optimization");
printf ("\n3. Exit");
printf ("\nEnter your Option : ");
scanf ("%d", &c);
switch (c)
{
case 1:

printf ("Enter the radius of circle :");


scanf ("%f", &r);
printf ("Perimeter = %0.2f", 2 * pi * r);
printf ("\nArea = %0.2f", pi * r * r);
break;
case 2:
printf ("Enter the radius of circle :");
scanf ("%f", &r);
printf ("Perimeter = %0.2f", 2 * 3.14 * r);
printf ("\nArea = %0.2f", 3.14 * r * r);

break;
}

}
Practical -9
Implement Intermediate code generation for simple expressions.
Program: -
#include <stdio.h>
#include <string.h>
int i = 1, j = 0, no = 0, tmpch = 90;
char str[100], left[15], right[15];

void findopr();
void explore();
void fleft(int);
void fright(int);
struct ex
{
int pos;
char op;
} k[15];
void main()
{
printf("\t\tINTERMEDIATE CODE GENERATION\n\n");
printf("Enter the Expression :");
scanf("%s", str);
printf("The intermediate code:\n");
findopr();
explore();
}
void findopr()

{
for (i = 0; str[i] != '\0'; i++)
if (str[i] == ':')
{
k[j].pos = i;
k[j++].op = ':';
}
for (i = 0; str[i] != '\0'; i++)
if (str[i] == '/')
{
k[j].pos = i;
k[j++].op = '/';
}
for (i = 0; str[i] != '\0'; i++)
if (str[i] == '*')
{
k[j].pos = i;
k[j++].op = '*';
}
for (i = 0; str[i] != '\0'; i++)
if (str[i] == '+')
{ k[j].pos = i;
k[j++].op = '+';
}
for (i = 0; str[i] != '\0'; i++)
if (str[i] == '-')
{
k[j].pos = i;
k[j++].op = '-';
}
}
void explore()
{
i = 1;
while (k[i].op != '\0')
{
fleft(k[i].pos);
fright(k[i].pos);
str[k[i].pos] = tmpch--;
printf("\t%c := %s%c%s\t\t", str[k[i].pos], left, k[i].op, right);
printf("\n");
i++;
}
fright(-1);
if (no == 0)
{ fleft(strlen(str));
printf("\t%s := %s", right, left);
exit(0);
}
printf("\t%s := %c", right, str[k[--i].pos]);
}
void fleft(int x)
{
int w = 0, flag = 0;
x--;
while (x != -1 && str[x] != '+' && str[x] != '*' && str[x] != '=' && str[x] != '\0' && str[x] != '-'
&& str[x] != '/' && str[x] != ':')
{ if (str[x] != '$' && flag == 0)
{ left[w++] = str[x];
left[w] = '\0';
str[x] = '$';
flag = 1;
}
x--;
}
}
void fright(int x)
{ int w = 0, flag = 0;
x++;
while (x != -1 && str[x] != '+' && str[x] != '*' && str[x] != '\0' && str[x] != '=' && str[x] != ':'
&& str[x] != '-' && str[x] != '/')
{
if (str[x] != '$' && flag == 0)
{right[w++] = str[x];
right[w] = '\0';
str[x] = '$';
flag = 1;
}
x++;
}
}
Practical -10
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.
Program: -
#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
{
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();
}

You might also like