2 - Lab Manual - Compiler Design
2 - Lab Manual - Compiler Design
2 - Lab Manual - Compiler Design
Experiment-1: Develop a Lexical Analyzer using C/C++ for a simple grammar/language of your
choice.
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 key.c
8. Define all the operators in a separate file and name it as oper.c
9. Give the input program in a file and name it as input.c
10. Finally print the output after recognizing all the tokens.
11. Stop the program.
Program:
#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");
fo = fopen("inter.c", "w");
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);
else
{
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);
flag = 1;
}
fscanf(fop, "%s", ch);
}
rewind(fop);
fscanf(fk, "%s", ch);
while(!feof(fk))
{
if(strcmp(ch, a) == 0)
{
fscanf(fk, "%s", ch);
printf("\t\t%s\t:\tKeyword\n", a);
flag = 1;
}
fscanf(fk, "%s", ch);
}
rewind(fk);
if(flag == 0)
{
if(isdigit(a[0]))
printf("\t\t%s\t:\tConstant\n", a);
else
printf("\t\t%s\t:\tIdentifier\n", a);
}
flag = 0;
fscanf(fi, "%s", a);
}
//getch();
}
key.c:
int
void
main
char
if
for
while
else
printf
scanf
FILE
Include
stdio.h
conio.h
iostream.h
oper.c:
( open para
) closepara
{ openbrace
} closebrace
< lesser
> greater
" doublequote ' singlequote
: colon
; semicolon
# preprocessor
= equal
== asign
% percentage
^ bitwise
& reference
* star
+ add
- sub
\ backslash
/ slash
input.c:
#include "stdio.h"
#include "conio.h"
void main()
{
int a=10,b,c;
a=b*c;
getch();
}
Output:
Experiment-2: Generate a Scientific Calculator using LEX/YACC tools.
Program:
advance_calc.l
%{
#include <math.h>
#include "y.tab.h"
%}
%%
[0-9]+|[0-9]*\.[0-9]+ {
yylval.p = atof(yytext);
return num;
}
advance_calc.y
%{
#include<stdio.h>
#include<math.h>
%%
/* for storing the answer */
ss: exp {printf("Answer =%g\n",$1);}
|'-'exp {$$=-$2;}
|SIN'('exp')' {$$=sin($3);}
|COS'('exp')' {$$=cos($3);}
|TAN'('exp')' {$$=tan($3);}
|LOG'('exp')' {$$=log($3);}
|SQRT'('exp')' {$$=sqrt($3);}
|num;
|'('exp')' {$$=$2;}
%%
void yyerror(s)
char *s;
{
printf("ERROR");
}
Output:
Experiment-3: Develop a Lexical Analyzer using LEX tool for a simple grammar of your choice
that displays the list of keywords and identifiers present in a given program.
Algorithm:
1. Write program in an editor and save it with .lex or .l extension.
2. Compile the lex program with lex compiler to produce output file as lex.yy.c.
3. Eg. $ lex filename.l
4. $gcc lex.yy.c -ll
5. Compile that file with C compiler and verify the output.
Program:
lexer.l
%{
int COMMENT=0;
%}
identifier[a-z][A-Z0-9]*
digit[0-9]
%%
#.* {printf("\n%s is a peprocessor diective",yytext);}
"int" |
"float" |
"char" |
"double" |
"for" |
"do" |
"if" |
"else" |
"break" |
"continue" |
"void" |
"case" |
"long" |
"struct" |
"typedef" |
"goto" |
"const" |
"while" |
"printf" |
"scanf" |
"switch" |
"main()" |
"return" {printf("\n\t%s is a keyword",yytext);}
"\*" {COMMENT=1;}
"*/" {COMMENT=0;}
\{ {if(!COMMENT) printf("\nblocks starts");}
\} {if(!COMMENT) printf("\n block end");}
{identifier} {if(!COMMENT) printf("\n\t%s is an identifier",yytext);}
\".*\" {if(!COMMENT) printf("\n\t%s is a string",yytext);}
{digit} {if(!COMMENT) printf("\n\t%s is a number",yytext);}
\)(\;)? {if(!COMMENT) printf("\n\t"); ECHO; printf("\n");}
\ECHO;
= {if(!COMMENT) printf("\n\t= is an assignment operator");}
\<= |
\>= |
\< |
== |
\> {if(!COMMENT) printf("\n\t%s is an relational operator",yytext);}
%%
int yywrap()
{
return 0;
}
input.c
#include <stdio.h>
int main()
{
int a,b,c;
scanf("%d%d",&a,&b);
c=a+b;
return 0;
}
Output:
if(E())
{
if(input[i+1]=='\0')
printf("\nString is accepted");
else
printf("\nString is not accepted");
}
else
printf("\nString not accepted");
getch();
}
E()
{
if(T())
{
if(EP())
return(1);
else
return(0);
}
else
return(0);
}
EP()
{
if(input[i]=='+')
{
i++;
if(T())
{
if(EP())
return(1);
else
return(0);
}
else
return(0);
}
else
return(1);
}
T()
{
if(F())
{
if(TP())
return(1);
else
return(0);
}
else
return(0);
}
TP()
{
if(input[i]=='*')
{
i++;
if(F())
{
if(TP())
return(1);
else
return(0);
}
else
return(0);
}
else
return(1);
}
F()
{
if(input[i]=='(')
{
i++;
if(E())
{
if(input[i]==')')
{
i++;
return(1);
}
else
return(0);
}
else
return(0);
}
else if(input[i]>='a'&&input[i]<='z'||input[i]>='A'&&input[i]<='Z')
{
i++;
return(1);
}
else
return(0);
}
Output:
Recursive descent parsing for the following grammar
E->TE'
E'->+TE'/@
T->FT'
T'->*FT'/@
F->(E)/ID
Program Logic:
1. Read the input string.
2. Using predictive parsing table parse the given input using stack .
3. If stack[i] matches with token input string pop the token else shift it, repeat the process until
it reaches to $.
Program:
#include<stdio.h>
#include<conio.h>
#include<string.h>
char s[20], stack[20];
void main()
{
char m[5][6][3]={"tb"," "," ","tb"," "," "," ","+tb"," "," ","n","n","fc"," "," ","fc"," "," ","
","n","*fc","a","n","n","i"," "," ","(e)"," "," "};
int size[5][6]={2,0,0,2,0,0,0,3,0,0,1,1,2,0,0,2,0,0,0,1,3,0,1,1,1,0,0,3,0,0};
int i,j,k,n,str1,str2;
clrscr();
printf("\n Enter the input string: ");
scanf("%s",s);
strcat(s,"$");
n=strlen(s);
stack[0]='$';
stack[1]='e';
i=1;
j=0;
printf("\nStack Input\n");
printf("__________________\n");
while((stack[i]!='$')&&(s[j]!='$'))
{
if(stack[i]==s[j])
{
i--;
j++;
}
switch(stack[i])
{
case 'e': str1=0;
break;
case 'b': str1=1;
break;
case 't': str1=2;
break;
case 'c': str1=3;
break;
case 'f': str1=4;
break;
}
switch(s[j])
{
case 'i': str2=0;
break;
case '+': str2=1;
break;
case '*': str2=2;
break;
case '(': str2=3;
break;
case ')': str2=4;
break;
case '$': str2=5;
break;
}
if(m[str1][str2][0]=='\0')
{
printf("\nERROR");
exit(0);
}
else if(m[str1][str2][0]=='n')
i--;
else if(m[str1][str2][0]=='i')
stack[i]='i';
else
{
for(k=size[str1][str2]-1;k>=0;k--)
{
stack[i]=m[str1][str2][k];
i++;
}
i--;
}
for(k=0;k<=i;k++)
printf(" %c",stack[k]);
printf("\n");
for(k=j;k<=n;k++)
printf("%c",s[k]);
printf(" \n ");
}
printf("\n SUCCESS");
getch();
}
Input & Output:
Enter the input string:i*i+i
Stack INPUT
$bt i*i+i$
$bcf i*i+i$
$bci i*i+i$
$bc *i+i$
$bcf* *i+i$
$bcf i+i$
$bci i+i$
$bc +i$
$b +i$
$bt+ +i$
$bt i$
$bcf i$
$ bci i$
$bc $
$b $
$ $
success
Program Logic:
1. Read the arithmetic input string.
2. Verify the precedence between terminals and symbols.
3. Find the handle enclosed in < . > and reduce it to production symbol.
4. Repeat the process until we reach the start node.
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;
void swt()
{
switch(c)
{
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);
break;
}
}
void 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;
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
{
opstr[j]='=';
j++;
}
i++;
}
opstr[j]='$';
opstr[++j]='\0';
printf("\nPrecedence Input:%s\n",opstr);
i=0;
j=0;
while(opstr[i]!='\0')
{
foundg=0;
while(foundg!=1)
{
if(opstr[i]=='\0')
goto redone;
if(opstr[i]=='>')
foundg=1;
t1=i;
i++;
}
if(foundg==1)
for(i=t1;i>0;i--)
if(opstr[i]=='<')
break;
if(i==0)
{
printf("\nERROR\n");
exit(1);
}
cn=i;
j=0;
i=t1+1;
while(opstr[i]!='\0')
{
temp[j]=opstr[i];
j++;
i++;
}
temp[j]='\0';
opstr[cn]='E';
opstr[++cn]='\0';
strcat(opstr,temp);
printf("\n%s",opstr);
i=1;
}
redone:
k=0;
while(opstr[k]!='\0')
{
k++;
if(opstr[k]=='<')
{
Printf("\nError");
exit(1);
}
}
if((opstr[0]=='$')&&(opstr[2]=='$'))
goto sue;
i=1;
while(opstr[i]!='\0')
{
c=opstr[i];
if(c=='+'||c=='*'||c=='/'||c=='$')
{
temp[j]=c;
j++;
}
i++;
}
temp[j]='\0';
strcpy(str,temp);
goto come;
sue:
printf("\n success");
return 0;
}
Output:
(d*d)+d$
Precedence input:$<(<d>*<d>)>+<d>$
$<(E*<d>)>+<d>$
$<(E*E)>+<E>$
$E+<E>$
$E+E$
Precedence input:$<+>$
$E$
success
Program Logic:
1. Read the input string.
2. Push the input symbol with its state symbol into the stack by referring lookaheads
3. Perform shift and reduce actions to parse the grammar.
4. Parsing is completed when we reach $ symbol.
/*Input Grammar
E->E+T
E->T
T->T*F
T->F
F->(E)
F->i
*/
Program:
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<string.h>
void push(char *,int *,char);
char stacktop(char *);
void isproduct(char,char);
int ister(char);
int isnter(char);
int isstate(char);
void error();
void isreduce(char,char);
char pop(char *,int *);
void printt(char *,int *,char [],int);
void rep(char [],int);
struct action
{
char row[6][5];
};
const struct action A[12]={
{"sf","emp","emp","se","emp","emp"},
{"emp","sg","emp","emp","emp","acc"},
{"emp","rc","sh","emp","rc","rc"},
{"emp","re","re","emp","re","re"},
{"sf","emp","emp","se","emp","emp"},
{"emp","rg","rg","emp","rg","rg"},
{"sf","emp","emp","se","emp","emp"},
{"sf","emp","emp","se","emp","emp"},
{"emp","sg","emp","emp","sl","emp"},
{"emp","rb","sh","emp","rb","rb"},
{"emp","rb","rd","emp","rd","rd"},
{"emp","rf","rf","emp","rf","rf"}
};
struct gotol
{
char r[3][4];
};
struct grammar
{
char left;
char right[5];
};
const struct grammar rl[6]={
{'E',"e+T"},
{'E',"T"},
{'T',"T*F"},
{'T',"F"},
{'F',"(E)"},
{'F',"i"},
};
void main()
{
char inp[80], x, p, dl[80], y, bl='a';
int i=0, j, k, l, n, m, c, len;
clrscr();
printf(" Enter the input :");
scanf("%s",inp);
len=strlen(inp);
inp[len]='$';
inp[len+1]='\0';
push(stack,&top,bl);
printf("\n stack \t\t\t input");
printt(stack,&top,inp,i);
do
{
x=inp[i];
p=stacktop(stack);
isproduct(x,p);
if(strcmp(temp,"emp")==0)
error();
if(strcmp(temp,"acc")==0)
break;
else
{
if(temp[0]=='s')
{
push(stack,&top,inp[i]);
push(stack,&top,temp[1]);
i++;
}
else
{
if(temp[0]=='r')
{
j=isstate(temp[1]);
strcpy(temp,rl[j-2].right);
dl[0]=rl[j-2].left;
dl[1]='\0';
n=strlen(temp);
for(k=0;k<2*n;k++)
pop(stack,&top);
for(m=0;dl[m]!='\0';m++)
push(stack,&top,dl[m]);
l=top;
y=stack[l-1];
isreduce(y,dl[0]);
for(m=0;temp[m]!='\0';m++)
push(stack,&top,temp[m]);
}
}
}
printt(stack,&top,inp,i);
}while(inp[i]!='\0');
if(strcmp(temp,"acc")==0)
printf(" \n accepts the input ");
else
printf(" \n does not accept the input ");
getch();
}
void push(char *s,int *sp,char item)
{
if(*sp==100)
printf(" stack is full ");
else
{
*sp=*sp+1;
s[*sp]=item;
}
}
int ister(char x)
{
int i;
for(i=0;i<6;i++)
if(x==ter[i])
return i+1;
return 0;
}
int isnter(char x)
{
int i;
for(i=0;i<3;i++)
if(x==nter[i])
return i+1;
return 0;
}
int isstate(char p)
{
int i;
for(i=0;i<12;i++)
if(p==states[i])
return i+1;
return 0;
}
void error()
{
printf(" error in the input ");
exit(0);
}
Output
Stack input
0 i*i+i$
0i5 *i+i$
0F3 *i+i$
0T2 *i+i$
0T2*7 i+i$
0T2*7i5 +i$
0T2*7i5F10 +i$
0T2 +i$
0E1 +i$
0E1+6 i$
0E1+6i5 $
0E1+6F3 $
0E1+6T9 $
0E1 $
accepts the input
Experiment-8: Implement the Intermediate Code Generator for WHILE construct using LEX &
YACC.
Program:
whilef.l
%%
while return WHILE;
[A-Za-z]([A-Za-z]|[0-9])* return ID;
[0-9]+ return NUM;
[\t] ;
\n yyterminate();
. return yytext[0];
%%
whilef.y
%{
#include "lex.yy.c"
#include <stdio.h>
#include <string.h>
char stack[100][10];
int top = 0;
char temp[3] = "t0";
%}
%%
S : WHILE {L1();} '(' E ')'{Lcond();} E ';' {End();}
V : ID {push();}
;
%%
void main()
{
printf("Enter expression: ");
yyparse();
}
void codegen()
{
printf("%s = %s %s %s\n", temp, stack[top - 2], stack [top - 1], stack[top]); //display like t0 = a*b
top -= 2;
strcpy(stack[top], temp);
temp[1]++; //generating new temporary variable
}
void codegen_umin()
{
printf("%s = -%s\n", temp, stack[top]); //display like t0 = -a
top--;
strcpy(stack[top], temp);
temp[1]++; //generating new temporary variable
}
void codegen_assign()
{
printf("%s = %s\n", stack[top-2], stack[top]); //display like c = t0
top -= 2;
}
void L1()
{
printf("\nL1: \n");
}
void Lcond()
{
printf("%s = not %s\n", temp, stack[top]);
printf("if %s goto End\n", temp);
temp[1]++; //generating new temporary variable
}
void End()
{
printf("goto L1\n");
printf("End: end of while loop \n\n");
}
Output:
Program:
#include<stdio.h>
#include<conio.h>
#include<string.h>
char s[20], o[20];
void main()
{
int i = 0, j = 0, k, f1 = 1, f = 1, k1 = 0;
void part();
clrscr();
printf("\n Enter the input string\n");
scanf("%s",o);
strlen(o);
while(o[k1]!='\0')
{
if((o[k1]=='=')==1)
{
break;
}
k1++;
}
for(j=k1+1;j<strlen(o);j++)
{
s[i]=o[j];
i++;
}
s[i]='\0';
i=strlen(s);
j=0;
printf("\n Three address code is\n");
if(i>3)
{
while(s[j]!='\0')
{
if((s[j]=='*')==1||(s[j]=='/')==1)
{
k=j;
if(f1!=0)
{
printf("t1=%c\n",s[k+1]);
printf("t2=%c%ct1",s[k-1],s[k]);
}
else
{
if(k>3)
{
printf("t2=t1%c%c\n",s[k],s[k+1]);
}
else
{
printf("\t2=t1%c%c\n",s[k],s[k-1]);
}
}
f=0;
break;
}
j++;
}
j=0;
while(s[j]!='\0')
{
if((s[j]=='+')==1||(s[j]=='-')==1)
{
k=j;
if(f==0)
{
if(k<3)
{
printf("\nt3=t2%c%c\n",s[k],s[k-1]);
}
else
{
printf("\nt3=t2%c%c\n",s[k],s[k+1])
}
}
else
{
printf("t1=%c%c%c\n",s[k-1],s[k],s[k+1]);
}
f1=0;
}
j++;
}
printf("%c=t3",o[0]);
}
else
{
printf("t1=%s\n",s);
printf("%c=t1",o[0]);
}
part();
getch();
}
void part()
{
int i=0, j=0, k, f1=1, f=1, k1=0;
while(o[k1]!='\0')
{
if((o[k1]=='=')==1)
{
break;
}
k1++;
}
for(j=k1+1;j<strlen(o);j++)
{
s[i]=o[j];
i++;
}
s[i]='\0';
i=strlen(s);
j=0;
printf("\n OPTIMIZED CODE\n");
if(i>3)
{
while(s[j]!='\0')
{
if((s[j]=='*')==1||(s[j]=='/')==1)
{
k=j;
if(f1!=0)
{
printf("t1=%c%c%c\n",s[k-1],s[k],s[k+1]);
}
else
{
if(k>3)
{
printf("t2=t1%c%c\n",s[k],s[k+1]);
}
else
{
printf("\t2=t1%c%c\n",s[k],s[k-1]);
}
}
f=0;
break;
}
j++;
}
j=0;
while(s[j]!='\0')
{
if((s[j]=='+')==1||(s[j]=='-')==1)
{
k=j;
if(f==0)
{
if(k<3)
{
printf("t2=t1%c%c\n",s[k],s[k-1]);
}
else
{
printf("t2=t1%c%c\n",s[k],s[k+1]);
}
}
else
{
printf("t1=%c%c%c\n",s[k-1],s[k],s[k+1]);
}
f1=0;
}
j++;
}
printf("%c=t2",o[0]);
}
else
{
printf("t1=%s\n",s);
printf("%c=t1",o[0]);
}
}
Experiment-10: Implement a simple Code Generator for arithmetic expression using C/C++.
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("\nEnter the set of intermediate codes for any simple arithmetic expression(terminated
by exit):\n");
do
{
scanf("%s",icode[i]);
}while(strcmp(icode[i++],"exit")!=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);
printf("\n");
//getch();
}
Output: