cs3501 Compiler Design Lab Manual
cs3501 Compiler Design Lab Manual
9 CONSTRUCTION OF DAG
AIM:
INTRODUCTION:
Lexical analysis is the process of converting a sequence of characters (such as in a
computer program or web page) into a sequence of tokens (strings with an identified
"meaning"). A program that performs lexical analysis may be called a lexer, tokenizer, or
scanner.
TOKEN
A token is a structure representing a lexeme that explicitly indicates its categorization
for the purpose of parsing. A category of tokens is what in linguistics might be called a part-
of-speech. Examples of token categories may include "identifier" and "integer literal",
although the set of token categories differ in different programming languages. The process
of forming tokens from an input stream of characters is called tokenization. Consider this
expression in the C programming language:
sum = 3 + 2;
2
ALGORITHM:
1. Start the program.
2. Include the header files.
3. Allocate memory for the variable by dynamic memory allocation function.
4. Use the file accessing functions to read the file.
5. Get the input file from the user.
6. Separate all the file contents as tokens and match it with the functions.
7. Define all the keywords in a separate file and name it as input.c.
8. Finally print the output after recognizing all the tokens.
9. Stop the program.
PROGRAM:
#include<stdio.h>
#include<ctype.h>
#include<string.h>
void keyw(char
*p);
int i=0,id=0,kw=0,num=0,op=0;
char keys[32][10]={"auto","break","case","char","const","continue","default",
"do","double","else","enum","extern","float","for","goto",
"if","int","long","register","return","short","signed",
"sizeof","static","struct","switch","typedef","union",
"unsigned","void","volatile","while"};
main()
{
char ch,str[25],seps[15]=" \t\n,;(){}[]#\"<>",oper[]="!%^&*-+=~|.<>/?";
int j;
char fname[50];
FILE *f1;
//clrscr();
printf("enter file path (D:\CD\lex.c)\n");
scanf("%s",fname);
f1 = fopen(fname,"r");
//f1 = fopen("Input","r");
if(f1==NULL)
{
printf("file not found");
exit(0);
}
while((ch=fgetc(f1))!=EOF)
{
for(j=0;j<=14;j++)
{
if(ch==oper[j])
{
printf("%c is an operator\n",ch);
op++;
str[i]='\0';
keyw(str);
}
3
4
}
for(j=0;j<=14;j++)
{
if(i==-1)
break;
if(ch==seps[j])
{
if(ch=='#')
{
while(ch!='>')
{
printf("%c",ch);
ch=fgetc(f1);
}
printf("%c is a header file\
n",ch); i=-1;
break;
}
if(ch=='"')
{
do
{
ch=fgetc(f1);
printf("%c",ch);
}while(ch!='"');
printf("\b is an argument\
n"); i=-1;
break;
}
str[i]='\0';
keyw(str);
}
}
if(i!=-1)
{
str[i]=ch; i+
+;
}
else
i=0;
}
printf("Keywords: %d\nIdentifiers: %d\nOperators: %d\nNumbers: %d\n",kw,id,op,num);
//getch();
}
void keyw(char *p)
{
int k,flag=0;
for(k=0;k<=31;k++)
{
if(strcmp(keys[k],p)==0)
5
{
printf("%s is a keyword\n",p);
kw++;
flag=1;
break;
}
}
if(flag==0)
{
if(isdigit(p[0]))
{
printf("%s is a number\n",p);
num++;
}
else
{
//if(p[0]!=13&&p[0]!=10)
if(p[0]!='\0')
{
printf("%s is an identifier\n",p);
id++;
}
}
}
i=-1;
}
Input.C
#include <stdio.h>
#include
<conio.h> void
main()
{
int a=10,b,c;
a=b*c;
getch();
}
6
OUTPUT:
RESULT:
Thus the above program for developing the lexical analyzer and recognizing the few patterns
in c is executed successfully and the output is verified.
7
EX.NO:2 IMPLEMENTATION OF LEXICAL ANALYZER USING LEX
DATE: TOOL
AIM:
To write a program to implement the Lexical Analyzer using Lex Tool.
INTRODUCTION:
THEORY:
LEX:
The lex is used in the manner depicted.A specification of the lexical analyzer is
preferred by creating a program lex.l in the lex language.
Then lex,l is run through the lex compiler to produce a „c‟program lex.yy.c
The program lex.yy.c consists of a tabular representation of a transition diagram
constructed from the regular expression of lex.l together with a standard routine that
uses the table of recognize leximes.
Lex.yy.c is run through the „c‟ compiler to produce as object program a.out,which is
the lexical analyzer that transform as input stream into sequence of tokens.
Creating a lexical analyzer with lex is shown in below.
LEX SOURCE
8
ALGORITHM:
eg $ lex filename.l
$ gcc lex.yy.c –ll
PROGRAM:
Program name: lexana.l
%{
int COMMENT=0;
%}
identifier[a-z][A-Z0-9]*
digit[0-9]
%%
"long" |
"struct" |
"typedef"
|
9
"goto" |
"const" |
"while" |
"printf" |
"scanf" |
"switch" |
"main()" |
"return" {printf("\n\t%s is a keyword",yytext);}
"\*" {COMMENT=1;}
"*/" {COMMENT=0;}
}
yyin=f1;
}
yylex();
printf("\n"); return 1;
}
int yywrap()
return 0;
10
INPUT PROGRAM:
#include<stdio.h>
void main()
{
int a,b,c;
printf("enter the value for
a,b"); scanf("%d%d",&a,&b)';
c=a+b;
printf("the value of c:%d",&c);
}
11
OUTPUT:
RESULT:
Thus the above program is compiled and executed successfully using the LEX tool and the
sample output is verified.
12
EX.NO:3
GENERATE YACC SPECIFICATION FOR A FEW
DATE: SYNTACTIC CATEGORIES
PROGRAM:
LEX PART:
%{
#include "y.tab.h"
%}
%%
[0-9]+(\.[0-9]*)? return
. return yytext[0];
\n return 0;
%%
int yywrap()
13
return 1;
YACC PART:
%{
#include<stdio.h>
int valid=1;
%}
%token num id op
%%
start : id '=' s
';' s : id x
| num x
| '-' num x
| '(' s ')' x
x: op s
| '-' s
%%
int yyerror()
valid=0;
printf("\nInvalid expression!\n");
return 0;
14
int main()
yyparse();
if(valid)
printf("\nValid expression!\n");
OUTPUT:
15
b). Program
to recognize a valid variable which starts with a letter followed
by any number of letters or digits.
AIM :
ALGORITHM:
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
PROGRAM CODE:
LEX PART:
%{
#include "y.tab.h"
%}
%%
[a-zA-Z_][a-zA-Z_0-9]* return
. return yytext[0];
\n return 0;
%%
int yywrap()
return 1;
16
YACC PART:
%{
#include<stdio.h>
int valid=1;
%}
%%
start : letter s
s: letter s
| digit s
%%
int yyerror()
valid=0;
return 0;
int main()
yyparse();
if(valid)
printf("\nIt is a identifier!\n");
17
}
18
OUTPUT:
19
c). Program to recognize a valid control structures syntax of C language
(For loop, while loop, if-else, if-else-if, switch-case, etc.).
AIM :
To write a to recognize a valid control structures syntax of C language (For loop, while loop, if-
else, if-else-if, switch-case, etc.).
ALGORITHM:
Step2: Recognize For Loop, While Loop, If-Else, If-Else-If, Switch Case.
Step3: Checking the validating of the given Control structures according to the rule using yacc.
Step4: Using control structure syntax print the result of the given values
PROGRAM:
%{
#include<stdio.h>
#include<stdlib.h>
%}
%token IF ELSE WHILE FOR SWITCH CASE DEFAULT
%token ID INT_CONST FLOAT_CONST CHAR_CONST
%%
Program:control_structure
| program control_structure
:
Control_structure : if_statement
|if_else_statement
|if_else_if_statement
|switch_case_statement
|while_loop
|for_loop
;
If_statement :IF‟(„expression‟)‟ statement
;
If_else_statement :IF‟(„expression‟)‟ statement ELSE statement
;
RESULT:
Thus the program to implement recognizes a valid control structures was executed and
verified.
21
d.) Implementation of calculator using LEX and YACC
AIM:
ALGORITHM:
PROGRAM:
%{
#include "y.tab.h"
#include<math.h>
%}
NUMBER [0-9]+|([0-9]*"."[0-9]+)
%%
{NUMBER} {yylval.dval=atof(yytext);
return NUMBER;}
sin|SIN {return SIN;} cos|
COS {return COS;} tan|
TAN {return TAN;} sqrt|
SQRT {return SQRT;}
22
[\t]+ ;
\n|. return yytext[0];
%%
int yywrap(void)
{ return 1;
}
%{
#include "y.tab.h"
#include <stdio.h>
#include <math.h>
#define PI 3.141592
int i,j;
%}
%union
{
double dval;
}
%token <dval> NUMBER
%token SIN COS TAN SQRT SQUARE RECI EXP MOD CUBE FACT %left LN LOG
%left '+''-''*''/'
%right '^'
%nonassoc NEG
%type <dval> E
%%
SL : S '\n'
| SL S '\
n'
;
S : E {printf("=%g\n",$1);}
;
E : E '+' E {$$=$1+$3;
printf("Addition is");}
|E '-' E {$$=$1-$3;
printf("substraction is");
}
|E '*' E {$$=$1*$3;
printf("Multiplication
is");
}
|E '/' E {
if($3==0)
printf("Error! Divide by zero!!");
23
else
$$=$1/$3;
printf("Division is");
}
|E '^' E {$$=pow($1,$3);
printf("Power is=");
}
|SIN '(' E ')' {$$=sin($3/180*PI);
printf("SIN is=");
}
|COS '(' E ')' {$$=cos($3/180*PI);
printf("COS is");
}
|TAN '(' E ')' { if($3==90)
printf("Undefined (Infinity)");
else
$$=tan($3/180*PI);
printf("TAN is");
}
|SQRT '(' E ')' {$$=sqrt($3);
printf("Square Root is");
}
|SQUARE '(' E ')' {$$=$3*$3;
printf("square is=");
}
|EXP '(' E ')' {$$=exp($3);
printf("EXPONENTIAL is");
}
|RECI '(' E ')' {$$=1/($3);
printf("Reciprocal is");}
$$=1; for(j=1;j<=$3;j+
+)
$$=$$*j;
printf("Factorial is");
}
|'(' E ')' {$$=$2;
printf("The simple number is");}
|'-' E %prec NEG {$$=-$2;
printf("The number with Negative sign is ");
}
|LOG E {$$=log($2)/log(10);
printf("LOG of base 10 is");
}
|LN E { $$=log($2);
24
printf("LOG with base 2 is");
}
|MOD '(' E','E')' {$$=fmod($3,$5);
}
|NUMBER
;
%%
extern FILE*yyin;
int main()
{
do{
yyparse();
}while(!feof(yyin));
}
yyerror(char*a)
{
fprintf(stderr,"parse error!!!");
}
OUTPUT:
25
The simple number is=9
3^2
Power is==9
3*3
Multiplication is=9
3+4
Addition is=7
4-2
substraction is=2
3/0
Error! Divide by zero!!Division is=3
32/2
Division is=16
fact(5)
Factorial is=120
RESULT:
Thus the program for generation of YAAC specification was executed and verified.
26
EX.NO:4 GENERATE THREE ADDRESS CODE FOR A
DATE: SIMPLE PROGRAM USING LEX AND YACC.
AIM:
To write a program to convert BNF rules into YACC form and write code to generate
Abstract Syntax Tree using LEX and YACC.
ALGORITHM:
1. Start a program
2. Declare the declarations as a header file {include<ctype.h>}
3. Token digit
4. Define the translations rules like line, expr, term, factor
Line:exp „\n‟ {print(“\n %d \n”,$1)} Expr:expr‟+‟ term ($$=$1=$3}
Term:term „+‟ factor($$ =$1*$3}
Factor
PROGRAM:
Program Name : lex.l
%{
%{
#include<stdio.h>
#include"y.tab.h"
int k=1;
%}
%%
[0-9]+ {
yylval.dval=yytext[0];
return NUM;
}
\n {return 0;}
. {return yytext[0];}
%%
27
sprintf(temp,"%d",k);
strcat(word,temp); k+
+;
printf("%s = %c %c %c\n",word,first,op,second);
main()
{
yyparse();
return 0;
}
%union{ ch
ar dval;
}
%%
statement : E {printf("\nt = %c \n",$1);}
;
E : E '+' E
{
char word[]="t";
char *test=gencode(word,$1,'+',$3);
$$=test;
}
| E '-' E
{
char word[]="t";
char *test=gencode(word,$1,'-',$3);
$$=test;
}
28
| E '%' E
{
char word[]="t";
char *test=gencode(word,$1,'%',$3);
$$=test;
}
| E '*' E
{
char word[]="t";
char *test=gencode(word,$1,'*',$3);
$$=test;
}
| E '/' E
{
char word[]="t";
char *test=gencode(word,$1,'/',$3);
$$=test;
}
| '(' E ')'
{
$$=$2;
}
| NUM
{
$$=$1;
}
;
%%
OUTPUT:
A = 1+2
B = 3*3
C = B/1
D = A-C
E = 4*5
F = D+E
X=F
[a40@localhost ~]$ ./a.out
29
A = 3+4
B = 2*A
C = B/5
D = 1+C
X=D
[a40@localhost ~]$ ./a.out
A = -3
B = -6
C = B/1
D = A+C
E = 2*D
F = E*3
G = 1+F
X=G
RESULT:
Thus the program to implement three address code was executed and verified.
30
EX.NO:5 IMPLEMENTATION OF TYPE CHECKING USING LEX
DATE: AND YAAC
AIM:
ALGORITHM:
Step1: Track the global scope type information (e.g. classes and their members)
Step2: Determine the type of expressions recursively, i.e. bottom-up, passing the resulting types
upwards.
31
break; } }
for(i=0;i<n;i++)
{
if(b[0]==vari[i])
{
if(flag==1)
{
if(typ[i]=='f')
{ printf("\nthe datatype is correctly defined..!\n");
break; }
else
{ printf("Identifier %c must be a float type..!\n",vari[i]);
break; } }
else
{ printf("\nthe datatype is correctly defined..!\n");
break; } }
}
return 0;
}
OUTPUT:
RESULT:
Thus the program to implement type checking was executed and verified.
32
EX.NO:6 IMPLEMENTATION OF SIMPLE CODE OPTIMIZATION
DATE: TECHNIQUES (CONSTANT FOLDING., ETC.)
AIM:
To write a C program to implement Code Optimization Techniques.
INTRODUCTION:
Optimization is a program transformation technique, which tries to improve the code
by making it consume less resource (i.e. CPU, Memory) and deliver high speed.
Optimization should increase the speed of the program and if possible, the program
should demand less number of resources.
Optimization should itself be fast and should not delay the overall compiling process.
Efforts for an optimized code can be made at various levels of compiling the process.
At the beginning, users can change/rearrange the code or use better algorithms to
write the code.
After generating intermediate code, the compiler can modify the intermediate code by
address calculations and improving loops.
While producing the target machine code, the compiler can make use of memory
hierarchy and CPU registers.
Optimization can be categorized broadly into two types : machine independent and
machine dependent.
Machine-Independent Optimization
In this optimization, the compiler takes in the intermediate code and transforms a part
of the code that does not involve any CPU registers and/or absolute memory locations. For
example:
33
This code involves repeated assignment of the identifier item, which if we put this
Machine-Dependent Optimization
Machine-dependent optimization is done after the target code has been generated and
when the code is transformed according to the target machine architecture. It involves CPU
registers and may have absolute memory references rather than relative references. Machine-
dependent optimizers put efforts to take maximum advantage of memory hierarchy.
ALGORITHM:
PROGRAM:
#include<stdio.h>
#include<conio.h>
#include<string.h>
struct op
{ char l;
char r[20];
}
op[10],pr[10];
void main()
{ int
a,i,k,j,n,z=0,m,q;
char *p,*l;
char temp,t;
char *tem;
clrscr();
printf("Enter the
Number of
Values:");
scanf("%d",&n);
for(i=0;i<n;i++)
{
printf("left: ");
op[i].l=getche();
printf("\tright: ");
scanf("%s",op[i].r);
}
printf("Intermediate
34
Code\n") ;
for(i=0;i<n;i++)
{
printf("%c=",op[i].l
);
printf("%s\n",op[i].r);
}
for(i=0;i<n-1;i++)
{ temp=op[i].l;
for(j=0;j<n;j++)
{
p=strchr(op[j].r,tem
p);
if(p)
{
pr[z].l=op[i].l;
strcpy(pr[z].r,op[i].
r);
z++; }}}
pr[z].l=op[n-1].l;
strcpy(pr[z].r,op[n-
1].r);
z++;
printf("nAfter Dead
Code
Eliminationn");
for(k=0;k<z;k++) {
printf("%ct=",pr[k].
l);
printf("%sn",pr[k].r
);
}
for(m=0;m<z;m++)
{
tem=pr[m].r;
for(j=m+1;j<z;j++)
{
p=strstr(tem,pr[j].r)
;
if(p) {
t=pr[j].l;
pr[j].l=pr[m].l;
for(i=0;i<z;i++)
{ l=strchr(pr[i].r,t)
; if(l) {
a=l-pr[i].r;
printf("pos: %d",a);
pr[i].r[a]=pr[m].l;
}}}}}
printf("Eliminate
Common
Expression\n");
for(i=0;i<z;i++)
{
35
printf("%c\t=",pr[i].l)
36
printf("%s\n",pr[i].r
);
}
for(i=0;i<z;i++)
{
for(j=i+1;j<z;j++)
{
q=strcmp(pr[i].r,pr[ j
].r);
if((pr[i].l==pr[j].l)
&&!q)
{
pr[i].l='\0';
strcpy(pr[i].r,'\0');
}}}
printf("Optimized Code\
n"); for(i=0;i<z;i++)
{ if(pr[i].l!='\0')
{
printf("%c=",pr[i].l
);
printf("%s\n",pr[i].r
);
}
}
getch();
}
37
OUTPUT:
RESULT:
Thus the implementation of simple code optimization technique e was executed and verified
38
EX.NO:7 IMPLEMENT BACK-END OF THE COMPILER FOR
WHICH THE THREE ADDRESS CODE IS GIVEN AS
DATE: INPUT AND THE 8086 ASSEMBLY LANGUAGE CODE
IS PRODUCED AS OUTPUT
AIM:
To write a program C Program to implement the Back end of the compiler.
ALGORITHM:
1. Start
2. Get the three variables from statements and stored in text file k.txt
3. Compile the program and give the path of the source file.
4. Execute the Program
5. Target code for the given statement was produced
6. Stop.
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
{
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;
39
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();
}
OUTPUT:
Result:
Thus the above program is compiled and executed successfully and output is verified
40
EX.NO:8
IMPLEMENTATION OF STORAGE ALLOCATION
DATE: STRATEGY USING HEAP
AIM:
INTRODUCTION:
Storage Allocation
Runtime environment manages runtime memory requirements for the following entities:
Code: It is known as the text part of a program that does not change at runtime. Its memory
requirements are known at the compile time.
Procedures: Their text part is static but they are called in a random manner. That is why, stack
storage is used to manage procedure calls and activations.
Variables: Variables are known at the runtime only, unless they are global or constant. Heap
memory allocation scheme is used for managing allocation and de-allocation of memory for variables
in runtime.
Static Allocation
In this allocation scheme, the compilation data is bound to a fixed location in the memory and
it does not change when the program executes. As the memory requirement and storage locations are
known in advance, runtime support package for memory allocation and de-allocation is not required.
Stack Allocation
Procedure calls and their activations are managed by means of stack memory allocation. It
works in last-in-first-out (LIFO) method and this allocation strategy is very useful for recursive
procedure calls.
Heap Allocation
Variables local to a procedure are allocated and de-allocated only at runtime. Heap allocation
is used to dynamically allocate memory to the variables and claim it back when the variables are no
more required.
Except statically allocated memory area, both stack and heap memory can grow and shrink
dynamically and unexpectedly. Therefore, they cannot be provided with a fixed amount of memory
in the system.
41
As shown in the image above, the text part of the code is
allocated a fixed amount of memory.
Stack and heap memory are arranged at the extremes of total
memory allocated to the program. Both shrink and grow against
each other.
ALGORITHM:
PROGRAM:
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
typedef struct Heap
{
int data;
struct Heap *next;
}node;
node *create();
void main()
{
int choice, val;
char ans;
node *head;
void display(node *);
node *search(node *,int);
node *insert(node *);
void dele(node **);
head=NULL;
do
{
clrscr();
printf("\n Program to perform various operations on heap using dynamic memory management");
printf ("\n1.Create");
printf ("\n2.Display");
printf ("\n3.Insert an element in a list");
42
printf ("\n4.Delete an element from list");
printf ("\n5.Quit");
printf ("\n Enter Your Choice(1-
5)"); scanf("%d",&choice);
switch(choice)
{
case 1:head=create();
break;
case 2:display(head);
break;
case 3:head=insert(head);
break;
case 4:dele(&head);
break;
case 5:exit(0);
default:clrscr();
printf("Invalid Choice,Try again");
getch();
}
}
while(choice!=5);
}
node *create()
{
node *temp,*new1,*head;
int val,flag;
char ans='y';
node *get_node();
temp=NULL;
flag=TRUE;
do
{
printf("\n Enter the Element");
scanf("%d",&val);
/*allocate new node*/
new1=get_node();
if(new1==NULL)
printf("\n Memory is not
allocated"); new1-> data=val;
if (flag==TRUE)/* Executed only for the first time*/ {
head=new1;
temp=head; /*head is the first node in the heap*/
flag=FALSE;}
else
{
temp->next=new1;
temp=new1;
}
43
}
while(ans=='y'); printf("\
nThe list is created");
getch();
clrscr();
return head;
}
node *get_node()
{
node *temp;
temp=(node*)malloc(sizeof(node));
//using the mem. Allocation
function temp->next=NULL;
return temp;
}
void display(node*head)
{
node *temp;
temp=head;
if(temp==NULL)
{
printf("\n The list is empty\n");
getch();
clrscr();
return;
}
while(temp!= NULL)
{
printf("%d->",temp->
data); temp=temp->next;
}
printf("NULL");
getch();
clrscr();
}
node *search(node *head,int key)
{
node *temp;
int found;
temp=head;
if (temp==NULL)
{
printf("The linked list is empty\n");
getch();
clrscr();
return
NULL;
}
found=FALSE;
44
while(temp!=NULL&&found==FALSE)
{
if(temp->data != key)
temp = temp->next;
else
found=TRUE;
}
if(found == TRUE)
{
printf("\n The Elements is present in the list\n");
getch();
return temp;
}
else
printf("\n The Element is not present in the list\n");
getch();
return NULL;
}
node *insert(node *head)
{
int choice;
node *insert_head(node*);
void insert_after(node*);
void insert_last(node*);
printf("\n 1.Insert a node as a head
node"); printf("\n 1.Insert a node as a last
node");
printf("\n 1.Insert a node as at the intermediate position in the list ");
printf("\n 1.Enter your choice for insertion of node ");
scanf("%d",&choice);
switch(choice)
{
case 1:head = insert_head(head);
break;
case 2:insert_last(head);
break;
case 3:insert_after (head);
break;
}
return head;
}
node *insert_head(node*head)
{
node *New,*temp;
New=get_node();
printf ("\n Enter the element which you want to insert ");
scanf("%d",&New->data);
if(head == NULL)
head = New;
45
else
{
temp=head;
New->next = temp;
head= New;
}
return head;
}
void insert_last(node *head)
{
node *New,*temp;
New = get_node();
printf ("\n Enter the element which you want to insert
"); scanf("%d",&New->data);
if(head == NULL)
{
head = New;
}
else
{
temp=head;
while(temp->next!=NULL)
temp=temp->next;
temp->next=New;
New->next=NULL;
}
}
void insert_after(node *head)
{
int key;
node *New,*temp;
New = get_node();
printf("Enter the element after which you want to insert
"); scanf("%d",&key);
temp=head;
do
{
if(temp->data==key)
{
printf ("Enter element which you want to insert
"); scanf("%d",&New->data);
New->next=temp->next;
temp->next=New;
return;
}
else
temp=temp->next;
46
while(temp!=NULL);
}
node *get_prev(node *head,int val)
{
node *temp,*prev;
int flag;
temp = head;
if(temp == NULL)
return NULL;
flag=FALSE;
prev=NULL;
while(temp!=NULL && !flag)
{
if(temp->data!=val)
{
prev = temp;
temp = temp->next;
}
else
flag = TRUE;
}
if(flag) /*if Flag is true*/
return prev;
else
return NULL;
}
void dele(node **head)
{
int key;
node *New,*temp,*prev;
temp=*head;
if (temp== NULL)
{
printf ("\n The list is empty\n ");
getch();
clrscr();
return;
}
clrscr();
printf("\nENTER the Element you want to delete:");
scanf("%d",&key);
temp=search(*head,key);
if(temp!=NULL)
{
prev=get_prev(*head,key); if(prev!
=NULL)
{
prev->next = temp-> next;
free(temp);
47
}
else
{
*head = temp->next;
OUTPUT:
48
Enter Your Choice(1-5)4
RESULT:
Thus the above program was successfully executed and output was verified.
49
EX.NO:9
CONSTRUCTION OF DAG
DATE:
AIM:
For a general weighted graph, we can calculate single source shortest distances in O(VE) time
using Bellman–Ford Algorithm. For a graph with no negative weights, we can do better and calculate
single source shortest distances in O(E + VLogV) time using Dijkstra‟s algorithm. Can we do even
better for Directed Acyclic Graph (DAG)? We can calculate single source shortest distances in
O(V+E) time for DAGs. The idea is to use Topological Sorting.
We initialize distances to all vertices as infinite and distance to source as 0, then we find a
topological sorting of the graph. Topological Sorting of a graph represents a linear ordering of the
graph (See below, figure (b) is a linear representation of figure (a) ). Once we have topological order
(or linear representation), we one by one process all vertices in topological order. For every vertex
being processed, we update distances of its adjacent using distance of current vertex.
Following figure is taken from this source. It shows step by step process of finding shortest
paths.
50
ALGORITHM:
1. Start the program.
2. Include all the header files.
3. Check for postfix expression and construct the inorder DAG representation.
4. Print the output.
5. Stop the program.
PROGRAM:
#include<stdio.h>
#include<conio.h>
#include<ctype.h>
#define size 20
typedef struct node
{
char data;
struct node *left;
struct node *right;
}btree;
btree *stack[size];
int top;
void main()
{
btree *root;
char exp[80];
btree *create(char exp[80]);
void dag(btree *root);
clrscr();
printf("\nEnter the postfix expression:\n");
scanf("%s",exp);
top=-1;
root=create(exp);
printf("\nThe tree is created.....\n");
printf("\nInorder DAG is : \n\n");
dag(root);
getch();
}
void push(btree*);
btree *pop();
pos=0;
ch=exp[pos];
while(ch!='\0')
{
temp=((btree*)malloc(sizeof(btree)));
51
temp->left=temp->right=NULL;
temp->data=ch;
if(isalpha(ch))
push(temp);
else if(ch=='+' ||ch=='-' || ch=='*' || ch=='/')
{
temp->right=pop();
temp->left=pop();
push(temp);
}
else
printf("\n Invalid char Expression\n");
pos++;
ch=exp[pos];
}
temp=pop();
return(temp);
}
btree* pop()
{
btree *Node;
if(top==-1)
printf("\nerror: stack is empty..\n");
Node=stack[top];
top--;
return(Node);
}
void dag(btree *root)
{
btree *temp;
temp=root;
if(temp!=NULL)
{
dag(temp->left);
printf("%c",temp->data);
dag(temp->right);
}
}
52
OUTPUT:
Inorder DAG is :
a+b*c-d
Process returned 13 (0xD) execution time : 40.135 s
Press any key to continue.
RESULT:
Thus the above program was successfully executed and output is verified.
53
EX.NO:10
IMPLEMENTATION OF CODE GENERATION
DATE:
AIM:
To write a program to generate the three address code and produces the 8086 assembly
language instructions that can be assembled and run using a 8086 assembler.
INTRODUCTION:
Back end
some local optimization
register allocation
peep-hole optimization
code generation
instruction scheduling
Analysis: This is the gathering of program information from the intermediate representation
derived from the input; data-flow analysis is used to build use-define chains, together with
dependence analysis, alias analysis, pointer analysis, escape analysis, etc. Accurate analysis is the
basis for any compiler optimization. The call graph and control are usually also built during the
analysis phase.
Code Generation: The transformed intermediate language is translated into the output language,
usually the native machine language of the system. This involves resource and storage decisions,
such as deciding which variables to fit into registers and memory and the selection and scheduling of
appropriate machine instructions along with their associated addressing modes. Debug data may also
need to be generated to facilitate debugging.
54
ALGORITHM:
Input: Set of three address code sequence.
Output: Assembly code sequence for three address codes (opd1=opd2, op, opd3).
Method:
1. Start
2. Get address code sequence.
3. Determine current location of 3 using address (for 1st operand).
4. If current location not already exist generate move (B,O).
5. Update address of A(for 2nd operand).
6. If current value of B and () is null,exist.
7. If they generate operator () A,3 ADPR.
8. Store the move instruction in memory
9. Stop.
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
{
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;
}
55
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();
}
OUTPUT:
RESULT:
Thus the program to 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 a
8086 assembler was executed and output is verified.
56