Professional Documents
Culture Documents
Technology, Vadapudupatti, Theni - 625 531: Nadar Saraswathi College of Engineering and
Technology, Vadapudupatti, Theni - 625 531: Nadar Saraswathi College of Engineering and
LAB MANUAL
YEAR/SEMESTER : III/VI
LIST OF EXPERIMENTS:
TOTAL: 45 PERIODS
INDEX
SIGNATURE OF
S.No DATE NAME OF THE EXPERIMENT REMARKS
THE STAFF
1 Symbol table
8 Type Checking
11 Construction of DAG
INTRODUCTION:
#include<stdio.h>
#include<conio.h>
#include<malloc.h>
#include<string.h>
#include<math.h>
#include<ctype.h>
void main()
ch,srch,b[15],d[15],c; //clrscr();
while((c=getchar())!='$') {
b[i]=c; i++;
n=i-1;
printf("given expression:");
i=0;
while(i<=n)
printf("%c",b[i]); i++;
printf("symbol table\n");
printf("symbol\taddr\ttype\n");
while(j<=n)
c=b[j]; if(isalpha(toascii(c)))
if(j==n)
p=malloc(c); add[x]=p;
d[x]=c;
printf("%c\t%d\tidentifier\n",c,p);
else
ch=b[j+1];
if(ch=='+'||ch=='-'||ch=='*'||ch=='=')
p=malloc(c);
add[x]=p;
d[x]=c;
printf("%c\t%d\tidentifier\n",c,p);
x++;
} j++;
DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING
NSCET – LAB MANUAL
srch=getch();
for(i=0;i<=x;i++)
if(srch==d[i])
printf("symbol found\n");
printf("%c%s%d\n",srch,"@address",add[i]);
flag=1;
if(flag==0)
//getch();
OUTPUT:
RESULT:
Thus the C program to implement the symbol table was executed and the output is verified.
INTRODUCTION:
TOKEN
A token is a structure representing a lexeme that explicitly indicates its categorization for
the Purpose of parsing. A category of token 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 differ in different programming languages.
The process of forming tokens from an input stream of characters is called tokenization.
ALGORITHM:
#include<stdio.h>
#include<conio.h>
#include<ctype.h>
#include<string.h>
void main()
{
FILE *fi,*fo,*fop,*fk;
int flag=0,i=1;
char c,t,a[15],ch[15],file[20];
clrscr();
printf("\n Enter the File Name:");
scanf("%s",&file);
fi=fopen(file,"r");
fop=fopen("oper.c","r");
fk=fopen("key.c","r");
c=getc(fi);
while(!feof(fi))
{
if(isalpha(c)||isdigit(c)||(c=='['||c==']'||c=='.'==1))
fputc(c,fo);
lse
{
if(c=='\n')
fprintf(fo,"\t$\t");
else fprintf(fo,"\t%c\t",c);
}
c=getc(fi);
}
fclose(fi);
fclose(fo);
fi=fopen("inter.c","r");
printf("\n Lexical Analysis");
fscanf(fi,"%s",a);
printf("\n Line: %d\n",i++);
while(!feof(fi))
{
if(strcmp(a,"$")==0)
{
printf("\n Line: %d \n",i++);
fscanf(fi,"%s",a);
}
fscanf(fop,"%s",ch);
while(!feof(fop))
{
if(strcmp(ch,a)==0)
{
fscanf(fop,"%s",ch);
printf("\t\t%s\t:\t%s\n",a,ch);
Input.C:
#include "stdio.h"
#include "conio.h"
void main()
{
int a=10,b,c;
a=b*c;
getch();
}
OUTPUT:
RESULT:
Thus the above program for developing the lexical the lexical analyzer and
recognizing the few pattern s in C is executed successfully and the output is verified.
EX.NO:3
DATE:
AIM:
INTRODUCTION:
THEORY:
The lex is used in the manner depicted. A specification of the lexical analyzer
is preferred by creating a program lex.1 in the lex language.
Then lex.1 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.1 together with a standard routine
that uses 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.
LEX SOURCE:
ALGORITHM:
%{
%}
identifier [a-zA-Z] [a-zA-Z0-9]*
%%
#.* {printf("\n %s is a preprocessor directive",yytext);}
int |
float |
char |
double |
while |
for |
if |
do |
break |
void |
main |
printf |
exit |
\+ |
\- |
\* |
\/ {printf("\n\t%s ia an Operator",yytext);}
\<= |
\>= |
\< |
== |
\> {printf("\n\t%s is a Relational Operator",yytext);}
%%
int main(int argc,char **argv)
{
if(argc>1)
{
FILE *f;
f=fopen(argv[1],"r");
if(!f)
{
printf("Could not open %s\n",argv[1]);
exit(0);
}
yyin=f;
}
yylex();
printf("\n\n");
return 0;
}
int yywrap()
{
return 0;}
OUTPUT
if(a<b) a=a+b;
Keyword
Parenthesis
Identifier:a
Relational Operator
Identifier:b
Parenthesis
Identifier:a
Assignment Operator
Identifier:a
Operator
Identifier:b
RESULT:
Thus the program for the exercise on lexical analysis using lex has
been successfully executed and output is verified.
AIM :
To write a c program to do exercise on syntax analysis using YACC.
INTRODUCTION :
YACC (yet another compiler) is a program designed to produce designed to compile
a LALR (1) grammar and to produce the source code of the synthetically analyses of
the language produced by the grammar.
ALGORITHM :
1. Start the program.
2. Write the code for parser. l in the declaration port.
3. Write the code for the „y‟ parser.
4. Also write the code for different arithmetical operations.
5. Write additional code to print the result of computation.
6. Execute and verify it.
7. Stop the program.
PROGRAM TO RECOGNIZE A VALID ARITHMETIC EXPRESSION
THAT USES OPERATOR +, - , * AND /.
PROGRAM:
validex.l
%{
#include "y.tab.h"
%}
%%
[a-zA-z] {return ID;}
[0-9]+ {return NUMBER;}
[ \t] ;
\n return 0;
. return yytext[0];
%%
yywrap()
{
}
validex.y
%{
DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING
NSCET – LAB MANUAL
#include<stdio.h>
main()
{
printf("Enter expression:\n");
yyparse();
printf("Vlid Expression");
}
yyerror()
{
printf("Invalid Expression");
}
Output
bachmanlab5@bachmanlab5-ThinkCentre-M71e:~/Desktop/maha$ lex validex.l
bachmanlab5@bachmanlab5-ThinkCentre-M71e:~/Desktop/maha$ yacc -d validex.y
bachmanlab5@bachmanlab5-ThinkCentre-M71e:~/Desktop/maha$ cc lex.yy.c y.tab.c
bachmanlab5@bachmanlab5-ThinkCentre-M71e:~/Desktop/maha$ ./a.out
Enter expression:
a+b
Vlid Expression
Output
bachmanlab5@bachmanlab5-ThinkCentre-M71e:~/Desktop/maha$ ./a.out
Enter expression:
a+b
Vlid Expression
RESULT:
Thus the program for the exercise on the syntax using YACC has been executed
successfully and Output is verified.
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;
}
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;
DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING
NSCET – LAB MANUAL
main()
OUTPUT:
RESULT:
Thus the program for the exercise on the syntax using YACC has
been executed successfully and Output is verified.
EX.NO.6
DATE:
PROGRAM:
%{
#include<stdio.h>
int op=0,i;
float a,b;
%}
dig[0-9]+|([0-9]*)"."([0-9]+)
add "+"
sub "-"
mul"*"
div "/"
pow "^"
ln \n
%%
{dig}{digi();}
{add}{op=1;}
{sub}{op=2;}
{mul}{op=3;}
{div}{op=4;}
{pow}{op=5;}
%%
digi()
if(op==0)
a=atof(yytext);
b=atof(yytext);
switch(op)
case 1:a=a+b;
break;
case 2:a=a-b;
break;
case 3:a=a*b;
break;
case 4:a=a/b;
break;
case 5:for(i=a;b>1;b--)
a=a*i;
break;
op=0;
yylex();
yywrap()
return 1;
OUTPUT:
Lex cal.l
Cc lex.yy.c-ll
a.out
4*8
The result=32
RESULT:
Thus the program for the exercise on the syntax using YACC has been executed
EX.NO:7
DATE:
INTRODUCTION:
The type analysis and type checking is an important activity done in the
semantic analysis phase. The need for type checking is
1. To detect the errors arising in the expression due to incompatible operand.
2. To generate intermediate code for expressions due to incompatible operand
ALGORITHM:
1. Start a program.
2. Include all the header files.
3. Initialize all the functions and variables.
4. Get the expression from the user and separate into the tokens.
5. After separation, specify the identifiers, operators and number.
6. Print the output.
7. Stop the program.
#include<stdio.h>
char str[50],opstr[75];
int f[2][9]={2,3,4,4,4,0,6,6,0,1,1,3,3,5,5,0,5,0};
int col,col1,col2;
char c;
swt()
{
switch(c)
{
DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING
NSCET – LAB MANUAL
case'+':col=0;break;
case'-':col=1;break;
case'*':col=2;break;
case'/':col=3;break;
case'^':col=4;break;
case'(':col=5;break;
case')':col=6;break;
case'd':col=7;break;
case'$':col=8;break;
default:printf("\nTERMINAL MISSMATCH\n");
exit(1);
}
// return 0;
}
main()
{
int i=0,j=0,col1,cn,k=0;
int t1=0,foundg=0;
char temp[20];
clrscr();
printf("\nEnter arithmetic expression:");
scanf("%s",&str);
while(str[i]!='\0')
i++;
str[i]='$';
str[++i]='\0';
printf("%s\n",str);
come:
i=0;
opstr[0]='$';
j=1;
c='$';
swt();
col1=col;
c=str[i];
swt();
col2=col;
DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING
NSCET – LAB MANUAL
if(f[1][col1]>f[2][col2])
{
opstr[j]='>';
j++;
}
else if(f[1][col1]<f[2][col2])
{
opstr[j]='<';
j++;
}
else
{
opstr[j]='=';j++;
}
while(str[i]!='$')
{
c=str[i];
swt();
col1=col;
c=str[++i];
swt();
col2=col;
opstr[j]=str[--i];
j++;
if(f[0][col1]>f[1][col2])
{
opstr[j]='>';
j++;
}
else if(f[0][col1]<f[1][col2])
{
opstr[j]='<';
j++;
}
else
{
OUTPUT:
RESULT:
Thus the program has been executed successfully and Output is verified.
EX.NO:8
DATE:
AIM:
INTRODUCTION:
BNF-Backus Naur form is formal notationfor encoding grammars intended for human
ALGORITHM:
<int.l>
%{
#include"y.tab.h"
#include<stdio.h>
#include<string.h>
int LineNo=1;
%}
%%
if return IF;
int |
char |
{number} {strcpy(yylval.var,yytext);
return NUM;}
\< |
\> |
\>= |
\<= |
== {strcpy(yylval.var,yytext);
return RELOP;}
[ \t] ;
\n LineNo++;
return yytext[0];
%%
<int.y>
%{
#include<string.h>
#include<stdio.h>
struct quad
char op[5];
char arg1[10];
char arg2[10];
char result[10];
}QUAD[30];
struct stack
int items[100];
int top;
}stk;
LineNo; %}
%union
char var[10];
%%
CODE: BLOCK
| STATEMENT CODE
| STATEMENT
| ASSIGNMENT ';'
| CONDST
| WHILEST
| VAR
strcpy(QUAD[Index].op,"=");
strcpy(QUAD[Index].arg1,$3);
strcpy(QUAD[Index].arg2,"");
strcpy(QUAD[Index].result,$1);
strcpy($$,QUAD[Index++].result);
{AddQuadruple("-",$1,$3,$$);}
| VAR
| NUM
CONDST: IFST{
Ind=pop();
sprintf(QUAD[Ind].result,"%d",Index);
Ind=pop();
sprintf(QUAD[Ind].result,"%d",Index);
| IFST ELSEST
strcpy(QUAD[Index].op,"==");
strcpy(QUAD[Index].arg1,$3);
strcpy(QUAD[Index].arg2,"FALSE");
strcpy(QUAD[Index].result,"- 1");
push(Index);
Index++;
strcpy(QUAD[Index].op,"GOTO");
strcpy(QUAD[Index].arg1,"");
strcpy(QUAD[Index].arg2,"");
strcpy(QUAD[Index].result,"- 1");
push(Index);
Index++;
};
ELSEST: ELSE{
tInd=pop();
Ind=pop();
push(tInd);
sprintf(QUAD[Ind].result,"%d",Index);
BLOCK{
Ind=pop();
sprintf(QUAD[Ind].result,"%d",Index);
};
StNo=Index- 1;
| VAR
| NUM
WHILEST: WHILELOOP{
Ind=pop();
sprintf(QUAD[Ind].result,"%d",StNo);
Ind=pop();
sprintf(QUAD[Ind].result,"%d",Index);
strcpy(QUAD[Index].op,"==");
strcpy(QUAD[Index].arg1,$3);
strcpy(QUAD[Index].result,"-
push(Index);
Index++;
BLOCK {
strcpy(QUAD[Index].op,"GOTO");
strcpy(QUAD[Index].arg1,"");
strcpy(QUAD[Index].arg2,"");
strcpy(QUAD[Index].result,"- 1");
push(Index);
Index++;
%%
FILE *fp;
int i;
if(argc>1)
fp=fopen(argv[1],"r");
if(!fp)
exit(0);
yyin=fp;
for(i=0;i<Index;i++)
%s",i,QUAD[i].op,QUAD[i].arg1,QUAD[i].arg2,QUAD[i].result); }
printf("\n\n");
return 0;
stk.top++;
if(stk.top==100)
exit(0);
stk.items[stk.top]=data;
int pop()
int data;
if(stk.top==- 1)
exit(0);
data=stk.items[stk.top--];
return data;
strcpy(QUAD[Index].op,op);
strcpy(QUAD[Index].arg1,arg1);
strcpy(QUAD[Index].arg2,arg2);
sprintf(QUAD[Index].result,"t%d",tIndex++);
strcpy(result,QUAD[Index++].result);
yyerror()
Input:
$vi test.c
main()
int a,b,c;
if(a<b)
a=a+b;
while(a<b)
{ a=a+b;
if(a<=b)
{ c=a- b;
DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING
NSCET – LAB MANUAL
else
{ c=a+b;
OUTPUT:
$ lex int.l
$ yacc –d int.y
$ ./a.out test.c
RESULT:
EX.NO:9
DATE:
AIM:
INTRODUCTION:
Data flow analysis is a technique for gathering information about the possible
set of value calculated at various points in a computer program.
Control flow analysis can be represent by basic blocks. It depicts how th program
control is being passed among the blocks.
ALGORITHM:
#include<conio.h>
struct stack
{
int no;
struct stack *next;
}
*start=null
typedef struct stack st;
voidpush();
int pop();
voiddisplay();
voidmain()
{
char ch;
int choice, item;
do
{
clrscr();
printf(“\n1:push”);
printf(“\n2:pop”);
printf(“\n3:display”);
printf(“\n enter your choice”);
scanf(“%d”,&choice);
switch(choice)
{
case1:push();
break;
case2:item=pop();
printf(“the delete element in %d”,item);
break;
case3:display();
break;
default:printf(“\nwrong choice”);
DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING
NSCET – LAB MANUAL
};
printf(“\nno=%d”,temp->no);
temp=temp->next;
}
printf(“\nno=%d”,temp->no);
OUTPUT:
RESULT:
Thus the C program to implement data flow and control flow analysis was
executed successfully.
DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING
NSCET – LAB MANUAL
CS6612 COMPILER LABORATORY
EX.NO:10
DATE:
IMPLEMENT ANY ONE STORAGE ALLOCATION STRATEGIES
(HEAP,STACK,STATIC)
AIM:
#include <conio.h>
#include <process.h>
#include <alloc.h>
struct node
int label;
};
void main()
int ch = 0;
int k;
head->next = NULL;
while(1)
printf("1->Push ");
printf("2->Pop ");
printf("3->View");
printf("4->Exit \n");
scanf("%d", &ch);
switch(ch)
case 1:
temp->next = h->next;
h->next = temp;
break;
case 2:
h = head->next;
head->next = h->next;
free(h);
break;
case 3:
h = head;
while(h->next != NULL)
h = h->next;
printf("NULL \n");
break;
case 4:
exit(0);
}}
OUTPUT:
RESULT:
Thus the program for implement storage allocation to use dynamic process for
stack has been successfully executed
EX.NO:11
DATE:
CONSTRUCTION OF DAG
AIM:
INTRODUCTION:
The code optimization is required to produce an efficient target code. These are two important
issues that used to be considered while applying the techniques for code optimization.
They are:
The semantics equivalences of the source program must not be changed.
The improvement over the program efficiency must be achieved without
changing the algorithm.
ALGORITHM:
#include<stdio.h>
main()
{
struct da
{
int ptr,left,right;
char label;
}dag[25];
int ptr,l,j,change,n=0,i=0,state=1,x,y,k;
char store,*input1,input[25],var;
clrscr();
DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING
NSCET – LAB MANUAL
for(i=0;i<25;i++)
dag[i].ptr=NULL;
dag[i].left=NULL;
dag[i].right=NULL;
dag[i].label=NULL;
}
/*EX:((a*b-c))+((b-c)*d)) like this give with paranthesis.limit is 25 char ucan change that*/
for(i=0;i<25;i++)
input[i]=NULL;
l=strlen(input1);
a:
for(i=0;input1[i]!=')';i++);
for(j=i;input1[j]!='(';j--);
for(x=j+1;x<i;x++)
if(isalpha(input1[x]))
input[n++]=input1[x];
else
if(input1[x]!='0')
store=input1[x];
input[n++]=store;
for(x=j;x<=i;x++)
input1[x]='0';
if(input1[0]!='0')goto a;
for(i=0;i<n;i++)
{
dag[i].label=input[i];
dag[i].ptr=i;
if(!isalpha(input[i])&&!isdigit(input[i]))
{
dag[i].right=i-1;
var=input[i-1];
if(isalpha(var))
ptr=ptr-2;
else
{
ptr=i-1;
b:
if(!isalpha(var)&&!isdigit(var))
{
ptr=dag[ptr].left;
var=input[ptr];
goto b;
}
else
ptr=ptr-1;
}
dag[i].left=ptr;
}
}
printf("\n SYNTAX TREE FOR GIVEN EXPRESSION\n\n");
printf("\n\n PTR \t\t LEFT PTR \t\t RIGHT PTR \t\t LABEL \n\n");
for(i=0;i<n;i++)/* draw the syntax tree for the following output with
pointer value*/
printf("\n
%d\t%d\t%d\t%c\n",dag[i].ptr,dag[i].left,dag[i].right,dag[i].la
bel);
getch();
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if((dag[i].label==dag[j].label&&dag[i].left==dag[j].left)&&dag[ i].right==dag[j].right)
for(k=0;k<n;k++)
{
if(dag[k].left==dag[j].ptr)dag[k].left=dag[i].ptr;
if(dag[k].right==dag[j].ptr)dag[k].right=dag[i].ptr;
}
dag[j].ptr=dag[i].ptr;
}
}
}
printf("\n DAG FOR GIVEN EXPRESSION\n\n");
printf("\n\n PTR \t LEFT PTR \t RIGHT PTR \t LABEL \n\n");
OUTPUT:
RESULT:
Thus the program for implementation of DAG has been successfully executed and
output is verified.
EX.NO.12
DATE:
IMPLEMENT THE BACK END OF THE COMPILER
AIM:
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. The target assembly instructions can be simple move, add, sub, jump. Also
simple addressing modes are used.
INTRODUCTION:
A compiler is a computer program that implements a programming language specification to
“translate” programs, usually as a set of files which constitute the source code written in source
language, into their equivalent machine readable instructions(the target language, often having a
binary form known as object code). This translation process is called compilation.
BACK END:
Some local optimization
Register allocation
Peep-hole optimization
Code generation
Instruction scheduling
The main phases of the back end include the following:
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.
Optimization: The intermediate language representation is transformed into
functionally equivalent but faster (or smaller) forms. Popular optimizations are
expansion, dead, constant, propagation, loop transformation, register allocation and
even automatic parallelization.
Code generation: The transformed 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 modes. Debug data may also need to be generated to facilitate debugging.
ALGORITHM:
#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();
do
scanf("%s",icode[i]);
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();
OUTPUT:
RESULT:
Thus the program was implemented to the TAC has been successfully executed.
EX.NO:13
DATE:
INTRODUCTION:
The output code must not, in any way, change the meaning of the program.
Optimization should increases the speed of the program and if possible, the
program should demand less number of resources.
Optimization should itself be fast and 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.
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:
do
item=10;
This code involves repeated assignment of the identifier item, which if we put this way:
item=10;
do
value=value+item;
}while(value<100);
Should not only save the cpu cycles, but can be used on any processor.
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:
#include<stdio.h>
#include<conio.h>
#include<string.h>
char s[20],p[20];
void main()
{
int i=0,j=0,k,f1=1,k1=0,f=1;
void part();
clrscr();
printf("\n Enter the input string:");
scanf("%s",p);
strlen(p);
while(p[k1]!='\0')
{
Output:
RESULT: