0% found this document useful (0 votes)
63 views15 pages

Practical 01: Aim: Write A Program To Create, Read and Write Into A File. Code

The document contains code for 5 programs related to compiler design concepts: 1. A program to implement a lexical analyzer that takes source code as input and outputs the tokens. 2. A program to remove left recursion from a context-free grammar by adding a non-terminal and modifying productions. 3. A program to remove left factoring from grammar productions to avoid backtracking during parsing. 4. Programs to create, read and write to files, remove comment lines from code, and remove left recursion from grammars. 5. The overall document discusses various compiler design concepts and includes code examples to implement lexical analysis, removal of left recursion and left factoring.

Uploaded by

Ronak Joshi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
63 views15 pages

Practical 01: Aim: Write A Program To Create, Read and Write Into A File. Code

The document contains code for 5 programs related to compiler design concepts: 1. A program to implement a lexical analyzer that takes source code as input and outputs the tokens. 2. A program to remove left recursion from a context-free grammar by adding a non-terminal and modifying productions. 3. A program to remove left factoring from grammar productions to avoid backtracking during parsing. 4. Programs to create, read and write to files, remove comment lines from code, and remove left recursion from grammars. 5. The overall document discusses various compiler design concepts and includes code examples to implement lexical analysis, removal of left recursion and left factoring.

Uploaded by

Ronak Joshi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 15

Practical 01

Aim: Write a program to create, read and write into a file.


Code:
#include<stdio.h>
#include<string.h>
void main()
{
FILE *fp;
char c[30],fname[20];
printf("Enter file name: ");
scanf("%s",fname);
fp=fopen(fname,"w");
printf("File created successfully.\n");
printf("Enter any string: ");
scanf("%s",c);
fputs(c,fp);
printf("Text entered successfully.\n");
fclose(fp);
fp=fopen(fname,"r");
printf("\nFile opened for reading.\n");
fgets(c,30,fp);
printf("String read from file: %s\n",c);
fclose(fp);
}

Output:
Practical 02
Aim: Write a program to remove comment lines from C or CPP file.
Code:
#include<stdio.h>
#include<string.h>
void main()
{
FILE *fp,*fp1;
char c,s,fname[30];
printf("Enter file name: ");
scanf("%s",fname);
fp=fopen(fname,"r");
fp1=fopen("temp.c","w");
printf("Files opened and process started.\n");
c=getc(fp);
while(c!=EOF)
{
if(c=='/')
{
s=getc(fp);
if(s=='/')
{
s=getc(fp);
while(s!='\n')
s=getc(fp);
c=getc(fp);
}
else if(s=='*')
{
c=getc(fp);
while(c!=EOF)
{
if(c=='*')
{
c=getc(fp);
if(c=='/')
break;
else
c=getc(fp);
}
else
c=getc(fp);
}
c=getc(fp);
}
else
{
fputc(c,fp1);
c=getc(fp);
}
}
else
{
fputc(c,fp1);
c=getc(fp);
}
}
printf("Task completed successfully.\n");
fclose(fp);
fclose(fp1);
}

Output:

Source file:
Output file:
Practical 03
Aim: Write a program to implement the lexical analyzer.
Theory Concept:
Lexical analysis is the first phase of a language processor. It takes the modified source code
from language preprocessors that are written in the form of sentences. The lexical analyzer
breaks these syntaxes into a series of tokens, by removing any whitespace or comments in the
source code. If the lexical analyzer finds a token invalid, it generates an error. The lexical
analyzer works closely with the syntax analyzer. It reads character streams from the source
code, checks for legal tokens, and passes the data to the syntax analyzer when it demands.
Creation of symbol table is started in this phase.

Code:
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<string.h>
void main()
{
FILE *fp;
int i=0,j=0,k=0,l=0,m=0,f=0,flag=0;
char c,s,temp[10],fname[20],id[10][10];
char kw[6][7]={"int","char","float","void","main","double"};
char op[13]={'+','-','=',';','*',',','/','(',')','[',']','{','}'};
printf("Enter file name: ");
scanf("%s",fname);
fp=fopen(fname,"r");
c=getc(fp);
while(c!=EOF)
{
m=0;
while(c!=' ' && c!='\n')
{
temp[m]=c;
c=getc(fp);
m++;
}
temp[m]='\0';
printf("%s\t",temp);
for(i=0;i<14;i++)
{
if(temp[0]==op[i])
{
printf("#op%d\n",i);
f=1;
break;
}
}
if(f==0)
{
for(i=0;i<6;i++)
{
if(strcmp(temp,kw[i])==0)
{
printf("#ky%d\n",j);
j++;
f=1;
break;
}
}
}
if(f==0)
{
if(isdigit(temp[0]))
{
printf("#cn%d\n",k);
k++;
}
else
{
for(i=0;i<10;i++)
{
if(strcmp(temp,id[i])==0)
{
printf("#id%d\n",i);
flag=1;
}
}
if(flag==0)
{
strcpy(id[l],temp);
printf("#id%d\n",l);
l++;
}
flag=0;
}
}
c=getc(fp);
f=0;
}
fclose(fp);
}
Output:
Practical 04
Aim: Write a program to left factor the given grammar.
Theory Concept:
Left factoring is removing the common left factor that appears in two productions of the same
non-terminal. It is done to avoid backtracking by the parser. Suppose the parser has a look-
ahead consider this example:
A->qB | qC
where A,B,C are non-terminals and q is a string. In this case, the parser will be confused as to
which of the two productions to choose and it might have to back-trace. After left factoring,
the grammar is converted to:
A->qA’
A’->B | C
In this case, a parser with a look-ahead will always choose the right production.

Code:
#include<stdio.h>
#include<string.h>
void main()
{
int i=0,j=0,k=0,pos=0,c=0,c1=0,f=0;
char p[50],a[10][10],temp[10],b[10][10];
printf("Enter any production: ");
scanf("%s",p);
while(p[i]!='>')
i++;
i++;
while(p[i]!='\0')
{
if(p[i]=='|')
{
a[j][k]='\0';
j++;
k=0;
i++;
}
else
{
a[j][k++]=p[i];
i++;
}
}
a[j][k]='\0';
c=c1=j;
i=0,j=0;
while(c!=0)
{
if(a[i][j]==a[i+1][j] && c!=0 && f==0)
{
f=1;
pos++;
j++;
while(a[i][j]!='\0' && a[i+1][j]!='\0')
{
if(a[i][j]==a[i+1][j])
pos++;
j++;
}
}
else if(f==1)
{
while(a[i][j]!='\0' && a[i+1][j]!='\0' && j+1<=pos)
{
if(a[i][j]!=a[i+1][j])
{
pos=i+1;
break;
}
j++;
}
}
else
printf("No need of removing left factor.\n");
i++;
j=0;
c--;
}
for(i=0,j=0,k=0;j<pos;j++,k++)
temp[k]=a[i][j];
temp[k]='\0';
for(i=0;i<=c1;i++)
{
for(j=0,k=pos;a[i][k]!='\0';j++,k++)
{
b[i][j]=a[i][k];
}
b[i][j]='\0';
}
printf("After removing left factor: \n");
printf("%c->%s%c'\n",p[0],temp,p[0]);
printf("%c'->",p[0]);
for(i=0;i<=c1;i++)
{
if(i==0)
printf("%s",b[i]);
else if(b[i][0]=='\0')
printf("|*");
else
printf("|%s",b[i]);
}
}

Output:
Practical 05
Aim: Write a program to remove Left Recursion from the given grammar.
Theory Concept:
Left recursion is a grammar in which the non-terminal which is defined, appears in the
extreme left of the production. It becomes necessary to remove left recursion in a top down
parsing otherwise the parse tree would go in infinite loop.
Eg:
E->Ea/Eb
Here, E is appearing in the left most position of the production, hence it is a left recursive
grammar.

Code:
#include<stdio.h>
#include<string.h>
void main()
{
char p[20],part1[20],part2[20],part3[20],mp[20],np[20];
int i,j=0,k=0,l=0,pos;
printf("Enter Production : A::=");
scanf("%s",p);
for(i=0;p[i]!='|';i++,j++)
part1[j]=p[i];
part1[j]='\0';
for(j=++i,i=0;p[j]!='|'&&p[j]!='\0';j++,i++)
part2[i]=p[j];
part2[i]='\0';
for(k=++j,j=0;p[k]!='\0';k++,j++)
part3[j]=p[k];
part3[j]='\0';
k=0;
for(i=0;i<strlen(part1)||i<strlen(part2)||i<strlen(part3);i++)
{
if((part1[i]=='A') && (part2[i]=='A'))
{
mp[k]=part3[i];
k++;
pos=i+1;
}
}
for(i=pos,j=0;part1[i]!='\0';i++,j++)
np[j]=part1[i];
if(strlen(part1)==1)
np[j++]='*';
np[j++]='X';
np[j++]='|';
for(i=pos;part2[i]!='\0';i++,j++)
np[j]=part2[i];
if(strlen(part2)==1)
np[j++]='*';
np[j++]='X';
np[j++]='|';
for(i=pos;part3[i]!='\0';i++,j++,k++)
{
mp[k]=part3[i];
np[j]=part3[i];
}
if(strlen(part3)==1)
np[j++]='*';
mp[k]='X';
mp[++k]='\0';
np[j]='\0';
printf(" A::=%s",mp);
printf("\n X::=%s\n",np);
}

Output:
Practical 06
Aim: Write a program to implement Recursive Descent Parsing for the
given grammar.
E --> T+E | T
T --> F*T | F
F --> (E) | i

Theory Concept:
Recursive descent parsing is a top-down method of syntax analysis in which a set of recursive
procedures to process the input is executed.
This parsing technique recursively parses the input to make a parse tree, which may or may
not require back-tracking. But the grammar associated with it (if not left factored) cannot
avoid back-tracking.
A form of recursive-descent parsing that does not require any back-tracking is known as
predictive parsing.
This parsing technique is regarded recursive as it uses context-free grammar which is
recursive in nature.
Consider the following example
E --> iE’
E’ --> +iE’ | ℇ
In Recursive Descent Parsing a procedure is associated with each nonterminal of a grammar.

Code:
#include<stdio.h>
int i=0;
char l,s[10];
void F();
void T();
void match(char );
void E()
{
T();
if(l=='+')
{
match('+');
E();
}
else
T();
}
void T()
{
F();
if(l=='*')
{
match('*');
T();
}
else
F();
}
void F()
{

if(l=='(')
{
match('(');
E();
if(l==')')
match(')');
}
else if(l=='i')
match('i');
}
void match(char t)
{
if(l==t)
{
l=s[i];
i++;
}
else
printf("\nError");
}
void main()
{
printf("\nEnter string: ");
scanf("%s",s);
l=s[i];
E();
if(l=='$')
printf("\nValid String.\n");
else
printf("\nInvalid String!!!\n");
}
Output:

You might also like