0% found this document useful (0 votes)
34 views

Compiler Design Final Record

The program implements a lexical analyzer in C++ to tokenize an input program. It reads the program line by line and classifies each word as a keyword, identifier, constant, or operator. It generates a corresponding token for each lexeme and stores identifiers in a symbol table. It then displays the generated tokens and writes the symbol table contents to an output file. The program was compiled, executed, and verified successfully.
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)
34 views

Compiler Design Final Record

The program implements a lexical analyzer in C++ to tokenize an input program. It reads the program line by line and classifies each word as a keyword, identifier, constant, or operator. It generates a corresponding token for each lexeme and stores identifiers in a symbol table. It then displays the generated tokens and writes the symbol table contents to an output file. The program was compiled, executed, and verified successfully.
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/ 37

LEXICAL ANALYZER

EX. NO. 1
AIM: To write a program to implement a lexical analyzer in C++.
ALGORITHM:
1. Start.
2. Get the input program from the file prog.txt.
3. Read the program line by line and check if each word in a line is a keyword, identifier,
constant or an operator.
4. If the word read is an identifier, assign a number to the identifier and make an entry into
the symbol table stored in sybol.txt.
5. For each lexeme read, generate a token as follows:
a. If the lexeme is an identifier, then the token generated is of the form <id, number>
b. If the lexeme is an operator, then the token generated is <op, operator>.
c. If the lexeme is a constant, then the token generated is <const, value>.
d. If the lexeme is a keyword, then the token is the keyword itself.
6. The stream of tokens generated are displayed in the console output.
7. Stop.
PROGRAM:
#include <bits/stdc++.h>
using namespace std;
vector<string> split(string s)
{
vector<string> v;
int i;
for(i = 0; i < s.length() && s[i] != ';'; i++)
{
string word = "";
if(s[i] == ' ')
continue;
while(true)
{
if(isalnum(s[i])||s[i] == '_')
word += s[i];
else if(s[i]=='+'||s[i]=='-'||s[i]=='*'||s[i]=='=')
{
string op = "";
op += s[i];
if(s[i-1] != ' ')
v.push_back(word);
v.push_back(op);
break;
}
else if(s[i] == '(')
{
string p = "";
if(s[i-1] != ' ')
v.push_back(word);
p += s[i];
while(s[i++] != ')')
p += s[i];
p += s[i];
v.push_back(p);
break;
}
i++;
if(s[i] == ',' || s[i] == ' ' || s[i] == ';')
{
v.push_back(word);
break;
}
}
}
return v;
}
bool is_keyword(string s)
{
set<string, greater<string> > keywords;
keywords.insert("void"); keywords.insert("int");
keywords.insert("return"); keywords.insert("using");
keywords.insert("namespace");
if(keywords.find(s) != keywords.end()) return true;
else return false;
}
bool is_operator(string s)
{
set<string, greater<string> > oper;
oper.insert("+"); oper.insert("-");
oper.insert("*"); oper.insert("/");
oper.insert("="); oper.insert("%%");
oper.insert("()"); oper.insert(";");
if(oper.find(s) != oper.end()) return true;
else return false;
}
bool is_valid_id(string s)
{
int i;
if(!(isalpha(s[0])||s[0] == '_')) return false;
for(i = 0; i < s.length(); i++)
if(!(isalnum(s[i])||s[i] == '_'))
return false;
return true;
}
bool is_num_const(string s)
{
int i;
for(i = 0; i != s.length(); i++)
if(!isdigit(s[i]))
return false;
return true;
}

int main()
{
ifstream fin("prog.txt");
string line;
vector<string> program;
vector<string>::iterator ptr;
set<string,greater<string> > keywords, oper;
set<string,greater<string> >::iterator itr;
vector<string> cons;
int id_no = 1;
map <string,int> id;
map <string,int>::iterator idtr;
if(fin.is_open())
{
while(getline(fin, line))
program.push_back(line);
fin.close();
}
for(ptr=program.begin(); ptr!=program.end(); ptr++)
{
line = *ptr;
if(line[0]=='#'||line.compare("{")==0||line.compare("}") == 0)
continue;
vector<string> words = split(line);
for(vector<string>::iterator it=words.begin();it!=words.end();
it++)
{
string word = *it;
if(word.compare("}")==0||word.compare("{")==0)
break;
if(is_keyword(word))
{
keywords.insert(word);
cout<<"<"<<word<<">";
}
else if(is_valid_id(word))
{
idtr = id.find(word);
if(idtr == id.end())
{
id.insert(make_pair(word,id_no));
cout<<"<id,"<<id_no<<">";
id_no++;
}
else
cout<<"<id,"<<idtr->second<<">";

}
else if(is_operator(word))
{
oper.insert(word);
if(word.compare(";") != 0)
cout<<"<op,"<<word<<">";
}
else if(is_num_const(word))
{
cons.push_back(word);
cout<<"<const,"<<word<<">";
}
}
cout<<"\n";
}
ofstream fout("symbol.txt");
fout<<"\nKeywords:\n";
for(itr = keywords.begin(); itr != keywords.end(); itr++)
fout<<*itr<<"\n";
fout<<"\nOperators:\n";
for(itr = oper.begin(); itr != oper.end(); itr++)
fout<<*itr<<"\n";
fout<<"\nIdentifiers:\n";
for(idtr = id.begin(); idtr != id.end(); idtr++)
fout<< idtr->first <<"\t <id,"<< idtr->second <<">\n";
fout.close();
return 0;
}

OUTPUT:
Contents of prog.txt:
#include <iostream>
using namespace std;
int main()
{
int a, b = 15, c;
a = 10;
c = a + b;
return;
}
Contents of symbol.txt:
Keywords: using, return, namespace, int
Operators: = +
Identifiers:
a <id,3>
b <id,4>
c <id,5>
main <id,2>
std <id,1>
Console output:
<using> <namespace> <id,1>
<int> <id,2>
<int> <id,3> <id,4> <op,=> <const,15> <id,5>
<id,3> <op,=> <const,10>
<id,5> <op,=> <id,3> <op,+> <id,4>
<return>

RESULT: The implementation of lexical analyser in C++ was compiled, executed and
verified successfully.
CONVERSION FROM REGULAR EXPRESSION TO ε-NFA
EX. NO. 2
AIM: To write a program for converting Regular Expression to ε-NFA using C++ Language.
ALGORITHM:
1. Start
2. Get the input from the user
3. Initialize separate variables and functions for Postfix , Display and NFA
4. Create separate methods for different operators like +,*, .
5. By using Switch case Initialize different cases for the input
6. For ' . ' operator Initialize a separate method by using various stack functions do the
same for the other operators like ' * ' and ' + '.
7. Regular expression is in the form like a.b (or) a+b
8. Display the output
9. Stop
PROGRAM:
#include<bits/stdc++.h>
using namespace std;
char reg[20];
void postfix();
void e_nfa();
void disp(int,char,int);
int main()
{
cout<<”Enter RE: ”;
cin>>reg;
postfix();
cout<<”Postfix : “<<reg<<endl;
e_nfa();
return 0;
}
void postfix()
{
char string[10],stack[10];
int string_n=0,stack_n=0;
int n=0;
strcat(reg,"X");
while(reg[n]!='\0')
{
switch(reg[n])
{
case 'a': string [string_n]='a';
string_n++;
string[string_n]='\0';
break;
case 'b': string[string_n]='b';
string_n++;
string[string_n]='\0';
break;
case '*' : string[string_n]='*';
string_n++;
string[string_n]='\0';
break;
case '(' : stack[stack_n]='(';
stack_n++;
break;
case ')' : stack_n--;
while(stack[stack_n]!='(')
{
string[string_n]=stack[stack_n];
stack[stack_n]='\0';
string_n++;
string[string_n]='\0';
stack_n--;
}
stack[stack_n]='\0';
break;
case 'X' : while(stack_n!=0)
{
stack_n--;
string[string_n]=stack[stack_n];
stack[stack_n]='\0';
string_n++;
string[string_n]='\0';
}
break;
case '+':
if(stack[stack_n-1]!='+' && stack[stack_n-1]!='.')
{
stack[stack_n]='+';
stack_n++;
stack[stack_n]='\0';
break;
}
else
{
string[string_n]=stack[stack_n-1];
string_n++;
stack[stack_n-1]='+';
break;
}
case '.' :
if(stack[stack_n-1]!='+'&&stack[stack_n-1]!='.')
{
stack[stack_n]='.';
stack_n++;
stack[stack_n]='\0';
break;
}
else
{
string[string_n]=stack[stack_n-1];
string_n++;
stack[stack_n-1]='.';
break;
}
default:break;
}
n++;
}
strcpy(reg,string);
}
void e_nfa()
{
int strt[3],last[3],s,l;
int n=0,x=0,i=-1;
cout<<”\nTransitions:\n”;
while(reg[n]!='\0')
{
switch(reg[n])
{
case 'a':i++;
strt[i]=x++;
last[i]=x++;
disp(strt[i],'a',last[i]);
break;
case 'b':i++;
strt[i]=x++;
last[i]=x++;
disp(strt[i],'b',last[i]);
break;
case '+' : s=x++;
l=x++;
disp(s,'e',strt[i]);
disp(s,'e',strt[i-1]);
disp(last[i],'e',l);
disp(last[i-1],'e',l);
i--;
strt[i]=s;
last[i]=l;
break;
case '.' : disp(last[i-1],'e',strt[i]);
last[i-1]=last[i];
i--;
break;
case '*' : s=x++;
l=x++;
disp(s,'e',strt[i]);
disp(s,'e',l);
disp(last[i],'e',strt[i]);
disp(last[i],'e',l);
strt[i]=s;
last[i]=l;
break;
default:break;
}
n++;
}
cout<<i<<" "<<strt[i]<<" "<<last[i];
}

void disp(int qs,char a,int qf)


{
cout<<qs<<"-->\t"<<a<<"-->\t"<<qf<<"\n";
}
OUTPUT:
Enter RE: a.(a+b)*
Postfix: aab+*.
Transitions:
0--> a--> 1
2--> a--> 3
4--> b--> 5
6--> e--> 4
6--> e--> 2
5--> e--> 7
3--> e--> 7
8--> e--> 6
8--> e--> 9
7--> e--> 6
7--> e--> 9
1--> e--> 8
0 0 9

RESULT: The program to convert regular expression to ε-NFA was implemented


successfully.
CONVERSION OF NFA TO DFA
EX. NO. 3
AIM: To write a program for converting NFA to DFA using C++ Language.
ALGORITHM:
1. Start
2. Get the input from the user
3. Set the only state in SDFA to “unmarked”.
4. while SDFA contains an unmarked state do:
a. Let T be that unmarked state
b. for each a in % do S = e-Closure(MoveNFA(T,a))
c. if S is not in SDFA already then, add S to SDFA (as an “unmarked” state)
d. Set MoveDFA(T,a) to S
5. For each S in SDFA if any s & S is a final state in the NFA then, mark S an a final state in
the DFA
6. Print the result.
7. Stop the program
PROGRAM:
#include <bits/stdc++.h>
#define STATES 50
using namespace std;
struct Dstate
{
char name;
char StateString[STATES+1];
char trans[10];
int is_final;
}Dstates[50];
struct tran
{
char sym;
int tostates[50];
int notran;
};
struct state
{
int no;
struct tran tranlist[50];
};
int stackA[100],stackB[100],C[100],Cptr=-1,Aptr=-1,Bptr=-1;
struct state States[STATES];
char temp[STATES+1],inp[10];
int nos,noi,nof,j,k,nods=-1;
void pushA(int z)
{
stackA[++Aptr]=z;
}
void pushB(int z)
{
stackB[++Bptr]=z;
}
int popA()
{
return stackA[Aptr--];
}
void copy(int i)
{
char temp[STATES+1]=" ";
int k=0;
Bptr=-1;
strcpy(temp,Dstates[i].StateString);
while(temp[k]!='\0')
{
pushB(temp[k]-'0');
k++;
}
}
int popB()
{
return stackB[Bptr--];
}
int peekB()
{
return stackA[Bptr];
}
int peekA()
{
return stackA[Aptr];
}
int seek(int arr[],int ptr,int s)
{
int i;
for(i=0;i<=ptr;i++)
if(s==arr[i]) return 1;
return 0;
}
void sort()
{
int i,j,temp;
for(i=0;i<Bptr;i++)
for(j=0;j<(Bptr-i);j++)
if(stackB[j]>stackB[j+1])
{
temp=stackB[j];
stackB[j]=stackB[j+1];
stackB[j+1]=temp;
}
}
void tostring()
{
int i=0;
sort();
for(i=0;i<=Bptr;i++)
temp[i]=stackB[i]+'0';
temp[i]='\0';
}
void display_DTran()
{
int i,j;
cout<<"\n\t\t DFA Transition Table ";
cout<<"\n\t\t -------------------- ";
cout<<"\nStates\tString\tInputs\n ";
for(i=0;i<noi;i++)
cout<<"\t"<<inp[i];
cout<<"\n \t----------";
for(i=0;i<nods;i++)
{
if(Dstates[i].is_final==0)cout<<"\n"<<Dstates[i].name;
else cout<<"\n"<<Dstates[i].name;
cout<<"\t"<<Dstates[i].StateString;
for(j=0;j<noi;j++)
cout<<"\t"<<Dstates[i].trans[j];
}
cout<<"\n";
}
void move(int st,int j)
{
int ctr=0;
while(ctr<States[st].tranlist[j].notran)
{
pushA(States[st].tranlist[j].tostates[ctr++]);
}
}
void lambda_closure(int st)
{
int ctr=0,in_state=st,curst=st,chk;
while(Aptr!=-1)
{
curst=popA();
ctr=0;
in_state=curst;
while(ctr<=States[curst].tranlist[noi].notran)
{
chk=seek(stackB,Bptr,in_state);
if(chk==0)
pushB(in_state);
in_state=States[curst].tranlist[noi].tostates[ctr++];
chk=seek(stackA,Aptr,in_state);
if(chk==0 && ctr<=States[curst].tranlist[noi].notran)
pushA(in_state);
}
}
}
int main()
{
int final[20],start,fin=0,i;
char c,ans,st[20];
cout<<"\nEnter no. of states in NFA : ";
cin>>nos;
for(i=0;i<nos;i++)
States[i].no=i;
cout<<"\nEnter the start state : ";
cin>>start;
cout<<"Enter the no. of final states : ";
cin>>nof;
cout<<"\nEnter the final states : \n";
for(i=0;i<nof;i++)
cin>>final[i];
cout<<"\nEnter the no. of input symbols : ";
cin>>noi;
c=getchar();
cout<<"\nEnter the input symbols : \n ";
for(i=0;i<noi;i++)
{
cin>>inp[i];
c=getchar();
}
inp[i]='e';
cout<<"\nEnter the transitions : (-1 to stop)\n";
for(i=0;i<nos;i++)
{
for(j=0;j<=noi;j++)
{
States[i].tranlist[j].sym=inp[j];
k=0;
ans='y';
while(ans=='y')
{
cout<<"move("<<i<<","<<inp[j]<< ") :";
cin>>States[i].tranlist[j].tostates[k++];
if(States[i].tranlist[j].tostates[k-1]==-1)
{
k--; ans='n';
break;
}
}
States[i].tranlist[j].notran=k;
}
}
i=0;nods=0;fin=0;
pushA(start);
lambda_closure(peekA());
tostring();
Dstates[nods].name='A';
nods++;
strcpy(Dstates[0].StateString,temp);
while(i<nods)
{
for(j=0;j<noi;j++)
{
fin=0;
copy(i);
while(Bptr!=-1)
{
move(popB(),j);
}
while(Aptr!=-1)
lambda_closure(peekA());
tostring();
for(k=0;k<nods;k++)
{
if((strcmp(temp,Dstates[k].StateString)==0))
{
Dstates[i].trans[j]=Dstates[k].name;
break;
}
}
if(k==nods)
{
nods++;
for(k=0;k<nof;k++)
{
fin=seek(stackB,Bptr,final[k]);
if(fin==1)
{
Dstates[nods-1].is_final=1;
break;
}
}
strcpy(Dstates[nods-1].StateString,temp);
Dstates[nods-1].name='A'+nods-1;
Dstates[i].trans[j]=Dstates[nods-1].name;
}
}
i++;
}
display_DTran();
}
OUTPUT:

Enter no. of states in NFA : 3

Enter the start state : 0

Enter the no. of final states : 1

Enter the final states : 2

Enter the no. of input symbols : 2

Enter the input symbols : a b

Enter the transitions : (-1 to stop)


move(0,a) : 0
move(0,a) : 1
move(0,a) : -1
move(0,b) : -1
move(0,e) : -1
move(1,a) : -1
move(1,b) : 2
move(1,b) : -1
move(1,e) : -1
move(2,a) : -1
move(2,b) : -1
move(2,e) : -1
DFA Transition Table
--------------------
States String Inputs
a b
-------- ----------
->A 0 B C
B 01 B D
C C C
*D 2 C C

RESULT: The given NFA was converted to a DFA using C++ successfully.
FIRST AND FOLLOW
EX. NO. 4
AIM: To write a program to perform first and follow using C language.
ALGORITHM:
For computing the first:
1. If X is a terminal then FIRST(X) = {X}
Example: F -> I | id
We can write it as FIRST(F) -> { ( , id )
2. If X is a non-terminal like E -> T then to get FIRSTI substitute T with other productions
until you get a terminal as the first symbol
3. If X -> ε then add ε to FIRST(X).
For computing the follow:
1. Always check the right side of the productions for a non-terminal, whose FOLLOW set is
being found. (never see the left side).
2. (a) If that non-terminal (S,A,B…) is followed by any terminal (a,b…,*,+,(,)…) , then add
that terminal into FOLLOW set.
(b) If that non-terminal is followed by any other non-terminal then add FIRST of other
nonterminal into FOLLOW set.
PROGRAM:
#include<bits/stdc++.h>
#define max 20
using namespace std;
char prod[max][10], ter[10], nt[10], first[10][10],follow[10][10];
int eps[10], count=0;
int findpos(char ch)
{
int n;
for(n=0;nt[n]!=’\0’;n++)
if(nt[n]==ch) break;
if(nt[n]==’\0’) return 1;
return n;
}
int IsCap(char c)
{
return (c >= ‘A’ && c <= ‘Z’)? 1 : 0;
}
void add(char *arr,char c)
{
15nti ,flag=0;
for(i = 0; arr[i]!=’\0’; i++)
if(arr[i] == c)
{
flag=1; break;
}
if(flag!=1)
arr[strlen(arr)] = c;
}
void addarr(char *s1,char *s2)
{
16nti ,j,flag=99;
for(i=0;s2[i]!=’\0’;i++)
{
flag=0;
for(j=0;;j++)
{
if(s2[i]==s1[j])
{
flag=1; break;
}
if(j==strlen(s1) && flag!=1)
{
s1[strlen(s1)] = s2[i]; break;
}
}
}
}
void addprod(char *s)
{
16nti ;
prod[count][0] = s[0];
for(i=3;s[i]!=’\0’;i++)
{
if(!IsCap(s[i]))
add(ter,s[i]);
prod[count][i-2] = s[i];
}
prod[count][i-2] = ‘\0’;
add(nt,s[0]);
count++;
}
void findfirst()
{
16nti ,j,n,k,e,n1;
for(i=0;i<count;i++)
{
for(j=0;j<count;j++)
{
n = findpos(prod[j][0]);
if(prod[j][1] == (char)238) eps[n] = 1;
else
{
for(k=1,e=1;prod[j][k]!=’\0’ && e==1;k++)
{
if(!IsCap(prod[j][k]))
{
e=0;
add(first[n],prod[j][k]);
}
else
{
n1 = findpos(prod[j][k]);
addarr(first[n],first[n1]);
if(eps[n1] == 0) e=0;
}
}
if(e==1) eps[n]=1;
}
}
}
}
void findfollow()
{
17nti ,j,k,n,e,n1;
n = findpos(prod[0][0]);
add(follow[n],’#’);
for(i=0;i<count;i++)
{
for(j=0;j<count;j++)
{
for(k = strlen(prod[j])-1; k>0; k--)
{
if(IsCap(prod[j][k]))
{
n=findpos(prod[j][k]);
if(prod[j][k+1] == ‘\0’) // A -> aB
{
n1 = findpos(prod[j][0]);
addarr(follow[n],follow[n1]);
}
if(IsCap(prod[j][k+1])) // A -> aBb
{
n1 = findpos(prod[j][k+1]);
addarr(follow[n],first[n1]);
if(eps[n1]==1)
{
n1=findpos(prod[j][0]);
addarr(follow[n],follow[n1]);
}
}
else if(prod[j][k+1] != ‘\0’)
add(follow[n],prod[j][k+1]);
}
}
}
}
}
int main()
{
char s[max],i;
cout<<”\nEnter the productions (type ‘end’ at the last of the
production)\n”;
cin>>s;
while(strcmp(“end”,s))
{
addprod(s);
cin>>s;
}
findfirst();
findfollow();
for(i=0; i<strlen(nt); i++)
{
cout<<”\nFIRST[“<<nt[i]<<”]: “<<first[i];
if(eps[i]==1)
cout<<(char)238<<”\t”;
else
cout<<”\t”;
cout<<”FOLLOW[“<<nt[i]<<”]: “<<follow[i];
}
return 0;
}

OUTPUT:

Enter the productions (type ‘end’ at the last of the production)


E->TD
D->+TD
D->ε
T->FG
G->*FG
G->ε
F->I
F->i
end

FIRST[E]: ( i FOLLOW[E]: $ )
FIRST[D]: + ε FOLLOW[D]: $ )
FIRST[T]: ( i FOLLOW[T]: + $ )
FIRST[G]: * ε FOLLOW[G]: + $ )
FIRST[F]: ( i FOLLOW[F]: * + $ )

RESULT: The FIRST and FOLLOW sets of the non-terminals of a grammar were found
successfully using C++.
ELIMINATION OF LEFT RECURSION
EX. NO. 5
AIM: To implement a C++ program to eliminate left recursion from a context free grammar.
ALGORITHM:
1. Start the program.
2. Initialize the arrays for taking input from the user.
3. Prompt the user to input the no. of non-terminals having left recursion and no. of
productions for these non-terminals.
4. Prompt the user to input the right production for non-terminals.
5. Eliminate left recursion using the following rules:-
A->Aα1| Aα2 | . . . . . |Aαm
A->β1| β2| . . . . .| βn
Then replace it by
A’-> βi A’ i=1,2,3,…..m
A’-> αj A’ j=1,2,3,…..n
A’-> Ɛ
6. After eliminating the left recursion by applying these rules, display the productions
without left recursion.
7. Stop.
PROGRAM:
#include<bits/stdc++.h>
using namespace std;
int main()
{
char input[100],*l,*r,*temp,tempprod[20],productions[25][50];
19nti =0,j=0,flag=0;
cout<<”Enter the productions: “;
cin>>input;
l = strtok(input,”->”);
r = strtok(NULL,”->”);
temp = strtok(r,”|”);
while(temp)
{
if(temp[0] == l[0])
{
flag = 1;
19nti 19(productions[i++],”%s’->%s%s’\0”,l,temp+1,l);
}
else
19nti 19(productions[i++],”%s->%s%s’\0”,l,temp,l);
temp = strtok(NULL,”|”);
}
19nti 19(productions[i++],”%s’->\u238\0”,l);
if(flag == 0)
cout<<”The given productions don’t have Left Recursion”;
else
for(j=0;j<i;j++)
cout<<”\n”<<productions[j];
return 0;
}
OUTPUT:
Enter the productions: A->A+b|A*c|(d)|a

A->(d)A’|aA’
A’->+bA’|*cA’|ε

RESULT: Left Recursion was eliminated from the given grammar successfully using C++.
LEFT FACTORING
EX. NO. 6
AIM: To Write a C Program to eliminate Left Factoring in the given grammar.
ALGORITHM:
1. Start
2. Get productions from the user
3. Check for common left factors in the production
4. Group all like productions
5. Simplify original production
6. Create the new production
7. Display all productions
8. Stop
PROGRAM:
#include<bits/stdc++.h>
using namespace std;
int main()
{
char a[10],a1[10],a2[10],a3[10],a4[10],a5[10];
21nti ,j=0,k,l;
cout<<”Enter any productions A->”);
cin>>a;
for(i=0;a[i]!=’|’;i++,j++)
a1[j]=a[i];
a1[j]=’\0’;
for(j=++i,i=0;a[j]!=’\0’;j++,i++)
a2[i]=a[j];
a2[i]=’\0’;
k=0;l=0;
for(i=0;i<strlen(a1)||i<strlen(a2);i++)
{
if(a1[i]==a2[i])
a3[k++]=a1[i];
else
{
a4[l]=a1[i];
a5[l]=a2[i];
l++;
}
}
a3[k]=’X’; a3[++k]=’\0’;
a4[l]=’|’; a5[l]=’\0’;
a4[++l]=’\0’;
strcat(a4,a5);
cout<<”\n A->”<<a3;
cout<<”\n X->”<<a4;
return 0;
}
OUTPUT:
Enter any productions A->bcd|bcf
A->bcX
X->d|f

RESULT: Left factoring was performed on the given grammar successfully using C++.
PREDICTIVE PARSER
EX. NO. 7
AIM: To construct a predictive parser in C++.
ALGORITHM:
1. Start the program.
2. Initialize the required variables.
3. Get the number of coordinates and productions from the user.
4. Perform the following
for (each production A → α in G) {
for (each terminal a in FIRST(α))
add A → α to M[A, a];
if (ε is in FIRST(α))
for (each symbol b in FOLLOW(A))
add A → α to M[A, b];
5. Print the resulting stack.
6. Print if the grammar is accepted or not.
7. Exit the program.
PROGRAM:
#include<bits/stdc++.h>
using namespace std;
int main()
{
char fin[10][20], st[10][20], ft[20][20], fol[20][20];
int a, i, t, b, n, j, s = 0, p;
cout<<"Enter the number of productions: ";
cin>>n;
cout<<"Enter the productions of the grammar:\n");
for(i = 0; i < n; i++)
cin>>st[i];
cout<<"\nEnter the FIRST and FOLLOW of each non-terminal:");
for(i = 0; i < n; i++)
{
cout<<"\nFIRST["<<st[i][0]<<"] : ";
cin>>ft[i];
cout<<"FOLLOW["<<st[i][0]<<"] : ";
cin>>fol[i];
}
cout<<"\nThe contents of the predictive parser table are:\n"
for(i = 0; i < n; i++)
{
j = 3;
while(st[i][j] != '\0')
{
if(st[i][j-1] == '|'|| j == 3)
{
for(p = 0; p <= 2; p++)
fin[s][p] = st[i][p];
t = j;
for(p=3; st[i][j]!='|' && st[i][j]!='\0'; p++, j++)
fin[s][p] = st[i][j];
fin[s][p] = '\0';
if(st[i][t] == 'e')
{
a = b = 0;
while(st[a++][0] != st[i][0]);
while(fol[a][b] != '\0')
{
cout<<"M["<<st[i][0]<<","<<fol[a][b]
<<"] = "<<fin[s]<<"\n";
b++;
}
}
else if(!(st[i][t] > 64 && st[i][t] < 91))
cout<<"M["<<st[i][0]<<","<<st[i][t]
<<"] = "<<fin[s]<<"\n";
else
{
a = b = 0;
while(st[a++][0] != st[i][3]);
while(ft[a][b] != '\0')
{
cout<<"M["<<st[i][0]<<","<<ft[a][b]
<<"] = "<<fin[s]<<"\n";
b++;
}
}
s++;
}
if(st[i][j] == '|')
j++;
}
}
return 0;
}

OUTPUT:
Enter the number of productions: 5
Enter the productions of the grammar:
E->TD
D->+TD|e
T->FG
G->*FG|e
F->(E)|i

Enter the FIRST and FOLLOW of each non-terminal:

FIRST[E]=(i
FOLLOW[E]=$)

FIRST[D]=+e
FOLLOW[D]=$)

FIRST[T]=(i
FOLLOW[T]=+$)
FIRST[G]=*e
FOLLOW[G]=+$)

FIRST[F]=(i
FOLLOW[F]=*+$)

The contents of the predictive parser table are:

M[E,(] = E->TD
M[E,i] = E->TD
M[D,+] = D->+TD
M[D,$] = D->e
M[D,)] = D->e
M[T,(] = T->FG
M[T,i] = T->FG
M[G,*] = G->*FG
M[G,+] = G->e
M[G,$] = G->e
M[G,)] = G->e
M[F,(] = F->(E)
M[F,i] = F->i

RESULT: The C++ program to implement the predictive parser was compiled, executed and
verified successfully.
LEADING AND TRAILING
EX. NO. 8
AIM: To implement a C++ program to find the LEADING and TRAILING sets of variables
of a given CFG.
ALGORITHM:
1. For Leading, check for the first non-terminal.
2. If found, print it.
3. Look for next production for the same non-terminal.
4. If not found, recursively call the procedure for the single non-terminal present before the
comma or End Of Production String.
5. Include it's results in the result of this non-terminal.
6. For trailing, we compute same as leading but we start from the end of the production to
the beginning.
7. Stop
PROGRAM:
#include<bits/stdc++.h>
using namespace std;
int nt,t,top=0;
char s[50],NT[10],T[10],st[50],l[10][10],tr[50][50];
int searchnt(char a)
{
int count=-1,i;
for(i=0;i<nt;i++)
{
if(NT[i]==a)
return i;
}
return count;
}
int searchter(char a)
{
int count=-1,i;
for(i=0;i<t;i++)
{
if(T[i]==a)
return i;
}
return count;
}
void push(char a)
{
s[top]=a;
top++;
}
char pop()
{
top--;
return s[top];
}
void installl(int a,int b)
{
if(l[a][b]=='f')
{
l[a][b]='t';
push(T[b]);
push(NT[a]);
}
}
void installt(int a,int b)
{
if(tr[a][b]=='f')
{
tr[a][b]='t';
push(T[b]);
push(NT[a]);
}
}
int main()
{
int i,s,k,j,n;
char pr[30][30],b,c;
cout<<"Enter the number of productions:";
cin>>n;
cout<<"Enter the productions:\n";
for(i=0;i<n;i++)
cin>>pr[i];
nt=0;
t=0;
for(i=0;i<n;i++)
if((searchnt(pr[i][0]))==-1)
NT[nt++]=pr[i][0];
for(i=0;i<n;i++)
for(j=3;j<strlen(pr[i]);j++)
if(searchnt(pr[i][j])==-1)
if(searchter(pr[i][j])==-1)
T[t++]=pr[i][j];
for(i=0;i<nt;i++)
for(j=0;j<t;j++)
l[i][j]='f';
for(i=0;i<nt;i++)
for(j=0;j<t;j++)
tr[i][j]='f';
for(i=0;i<nt;i++)
for(j=0;j<n;j++)
if(NT[(searchnt(pr[j][0]))]==NT[i])
{
if(searchter(pr[j][3])!=-1)
installl(searchnt(pr[j][0]),searchter(pr[j][3]));
else
for(k=3;k<strlen(pr[j]);k++)
if(searchnt(pr[j][k])==-1)
{
installl(searchnt(pr[j][0]),searchter(pr[j][k]));
break;
}
}
while(top!=0)
{
b=pop();
c=pop();
for(s=0;s<n;s++)
if(pr[s][3]==b)
installl(searchnt(pr[s][0]),searchter(c));
}
cout<<”\nLEAD sets of non-terminals:\n”;
for(i=0;i<nt;i++)
{
cout<<"LEAD["<<NT[i]<<"]"<<": {";
for(j=0;j<t;j++)
if(l[i][j]=='t')
cout<<T[j]<<",";
cout<<"\b}\n";
}
top=0;
for(i=0;i<nt;i++)
for(j=0;j<n;j++)
if(NT[searchnt(pr[j][0])]==NT[i])
{
if(searchter(pr[j][strlen(pr[j])-1])!=-1)
installt(searchnt(pr[j][0]),searchter(pr[j][strlen(pr[j])-1]));
else
for(k=(strlen(pr[j])-1);k>=3;k--)
if(searchnt(pr[j][k])==-1)
{
installt(searchnt(pr[j][0]),searchter(pr[j][k]));
break;
}

}
while(top!=0)
{
b=pop();
c=pop();
for(s=0;s<n;s++)
{
if(pr[s][3]==b)
installt(searchnt(pr[s][0]),searchter(c));
}
}
cout<<”\nTRAIL sets of non-terminals:\n”;
for(i=0;i<nt;i++)
{
cout<<"TRAIL["<<NT[i]<<"]"<<": {";
for(j=0;j<t;j++)
if(tr[i][j]=='t')
cout<<T[j]<<",";
cout<<"\b}\n";
}
return 0;
}
OUTPUT:
Enter the number of productions: 3
Enter the productions:
E->E+T|T
T->T*F|F
F->(E)|i

LEAD sets of non-terminals:


LEAD[E]: {+,*,(,i}
LEAD[T]: {*,(,i}
LEAD[F]: {(,i}

TRAIL sets of non-terminals:


TRAIL[E]: {+,*,),i}
TRAIL[T]: {*,),i}
TRAIL[F]: {),i}

RESULT: The C++ implementation to find the LEAD and TRAIL sets of variables of a CFG
was compiled, executed and verified successfully.
SHIFT REDUCE PARSER
EX. NO. 9
AIM: To implement Shift Reduce Parser in C++.
ALGORITHM:
1. Start the program.
2. Initialize the required variables.
3. Enter the input symbol.
4. Perform the following:
for top-of-stack symbol, s, and next input symbol, a
Shift x: (x is a STATE number)
Push a, then x on the top of the stack
Advance ip to point to the next input symbol.

Reduce y: (y is a PRODUCTION number)


Assume that the production is of the form A→ß
Pop 2 * |ß| symbols of the stack.

At this point the top of the stack should be a state number, say s’.
Push A, then goto of T[s’,A] (a state number) on the top of the stack.
Output the production A→ß.
5. Print if string is accepted or not.
6. Stop the program.

PROGRAM:
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<string.h>
char ip_sym[15],stack[15];
int ip_ptr=0,st_ptr=0,len,i;
char temp[2],temp2[2];
char act[15];
void check();
int main()
{
printf("\n\t\t SHIFT REDUCE PARSER\n");
printf("\n GRAMMAR\n");
printf("\n E->E+E\n E->E/E");
printf("\n E->E*E\n E->a/b");
printf("\n Enter the input symbol:\t");
gets(ip_sym);
printf("\n\t Stack implementation table");
printf("\n Stack\t\t Input symbol\t\t Action");
printf("\n______\t\t ____________\t\t ______\n");
printf("\n $\t\t%s$\t\t\t--",ip_sym);
strcpy(act,"shift ");
temp[0]=ip_sym[ip_ptr];
temp[1]='\0';
strcat(act,temp);
len=strlen(ip_sym);
for(i=0;i<=len-1;i++)
{
stack[st_ptr]=ip_sym[ip_ptr];
stack[st_ptr+1]='\0';
ip_sym[ip_ptr]=' ';
ip_ptr++;
printf("\n $%s\t\t%s$\t\t\t%s",stack,ip_sym,act);
strcpy(act,"shift ");
temp[0]=ip_sym[ip_ptr];
temp[1]='\0';
strcat(act,temp);
check();
st_ptr++;
}
st_ptr++;
check();
}
void check()
{
int flag=0;
temp2[0]=stack[st_ptr];
temp2[1]='\0';
if((!strcmpi(temp2,"a"))||(!strcmpi(temp2,"b")))
{
stack[st_ptr]='E';
if(!strcmpi(temp2,"a"))
printf("\n $%s\t\t%s$\t\t\tE->a",stack, ip_sym);
else
printf("\n $%s\t\t%s$\t\t\tE->b",stack,ip_sym);
flag=1;
}
if((!strcmpi(temp2,"+"))||(strcmpi(temp2,"*"))||(!strcmpi(temp2,"/")
))
{
flag=1;
}
if((!strcmpi(stack,"E+E"))||(!strcmpi(stack,"E\E"))||(!strcmpi(stack
,"E*E")))
{
strcpy(stack,"E");
st_ptr=0;
if(!strcmpi(stack,"E+E"))
printf("\n $%s\t\t%s$\t\t\tE->E+E",stack,ip_sym);
else
if(!strcmpi(stack,"E\E"))
printf("\n $%s\t\t %s$\t\t\tE->E\E",stack,ip_sym);
else
printf("\n $%s\t\t%s$\t\t\tE->E*E",stack,ip_sym);
flag=1;
}
if(!strcmpi(stack,"E")&&ip_ptr==len)
{
printf("\n $%s\t\t%s$\t\t\tACCEPT",stack,ip_sym);
getch();
exit(0);
}
if(flag==0)
{
printf("\n%s\t\t\t%s\t\t reject",stack,ip_sym);
exit(0);
}
return;
}
OUTPUT:
SHIFT REDUCE PARSER
GRAMMAR

E->E+E
E->E/E
E->E*E
E->a|b

Enter the input symbol: a+a/b

Stack implementation table

Stack Input symbol Action


______ ____________ ______

$ a+a/b$ --
$a +a/b$ shift a
$E +a/b$ E->a
$E+ a/b$ shift +
$E+a /b$ shift a
$E+E /b$ E->a
$E /b$ E->E*E
$E/ b$ shift /
$E/b $ shift b
$E/E $ E->E/E
$E $ ACCEPT

RESULT: The C++ implementation of Shift Reduce Parser was compiled, executed and
verified successfully.
LR(0) PARSER
EX. NO. 10
AIM: To implement LR(0) Parser in C++.
ALGORITHM:
1. Start.
2. Create structure for production with LHS and RHS.
3. Open file and read input from file.
4. Build state 0 from extra grammar Law S' -> S $ that is all start symbol of grammar and one
Dot ( . ) before S symbol.
5. If Dot symbol is before a non-terminal, add grammar laws that this non-terminal is in Left
Hand Side of that Law and set Dot in before of first part of Right Hand Side.
6. If state exists (a state with this Laws and same Dot position), use that instead.
7. Now find set of terminals and non-terminals in which Dot exist in before.
8. If step 7 Set is non-empty go to 9, else go to 10.
9. For each terminal/non-terminal in set step 7 create new state by using all grammar law that
Dot position is before of that terminal/non-terminal in reference state by increasing Dot point
to next part in Right Hand Side of that laws.
10. Go to step 5.
11. End of state building.
12. Display the output.
13. End.

PROGRAM:
#include<stdio.h>
#include<string.h>
int i,j,k,m,n=0,o,p,ns=0,tn=0,rr=0,ch=0;
char read[15][10], gl[15], gr[15][10], temp, templ[15], tempr[15][10];
char *ptr, temp2[5], dfa[15][15];
struct states
{
char lhs[15],rhs[15][10];
int n;
}I[15];
int compstruct(struct states s1,struct states s2)
{
int t;
if(s1.n!=s2.n)
return 0;
if( strcmp(s1.lhs,s2.lhs)!=0 )
return 0;
for(t=0;t<s1.n;t++)
if( strcmp(s1.rhs[t],s2.rhs[t])!=0 )
return 0;
return 1;
}
void moreprod()
{
int r,s,t,l1=0,rr1=0;
char *ptr1,read1[15][10];
for(r=0;r<I[ns].n;r++)
{
ptr1=strchr(I[ns].rhs[l1],'.');
t=ptr1-I[ns].rhs[l1];
if( t+1==strlen(I[ns].rhs[l1]) )
{
l1++;
continue;
}
temp=I[ns].rhs[l1][t+1];
l1++;
for(s=0;s<rr1;s++)
if( temp==read1[s][0] )
break;
if(s==rr1)
{
read1[rr1][0]=temp;
rr1++;
}
else
continue;
for(s=0;s<n;s++)
{
if(gl[s]==temp)
{
I[ns].rhs[I[ns].n][0]='.';
I[ns].rhs[I[ns].n][1]=NULL;
strcat(I[ns].rhs[I[ns].n],gr[s]);
I[ns].lhs[I[ns].n]=gl[s];
I[ns].lhs[I[ns].n+1]=NULL;
I[ns].n++;
}}}}
void canonical(int l)
{
int t1;
char read1[15][10],rr1=0,*ptr1;
for(i=0;i<I[l].n;i++)
{
temp2[0]='.';
ptr1=strchr(I[l].rhs[i],'.');
t1=ptr1-I[l].rhs[i];
if( t1+1==strlen(I[l].rhs[i]) )
continue;
temp2[1]=I[l].rhs[i][t1+1];
temp2[2]=NULL;
for(j=0;j<rr1;j++)
if( strcmp(temp2,read1[j])==0 )
break;
if(j==rr1)
{
strcpy(read1[rr1],temp2);
read1[rr1][2]=NULL;
rr1++;
}
else
continue;
for(j=0;j<I[0].n;j++)
{
ptr=strstr(I[l].rhs[j],temp2);
if( ptr )
{
templ[tn]=I[l].lhs[j];
templ[tn+1]=NULL;
strcpy(tempr[tn],I[l].rhs[j]);
tn++;
}}
for(j=0;j<tn;j++)
{
ptr=strchr(tempr[j],'.');
p=ptr-tempr[j];
tempr[j][p]=tempr[j][p+1];
tempr[j][p+1]='.';
I[ns].lhs[I[ns].n]=templ[j];
I[ns].lhs[I[ns].n+1]=NULL;
strcpy(I[ns].rhs[I[ns].n],tempr[j]);
I[ns].n++;
}
moreprod();
for(j=0;j<ns;j++)
{
//if ( memcmp(&I[ns],&I[j],sizeof(struct
states))==1 )
if( compstruct(I[ns],I[j])==1 )
{
I[ns].lhs[0]=NULL;
for(k=0;k<I[ns].n;k++)
I[ns].rhs[k][0]=NULL;
I[ns].n=0;
dfa[l][j]=temp2[1];
break;
}}
if(j<ns)
{
tn=0;
for(j=0;j<15;j++)
{
templ[j]=NULL;
tempr[j][0]=NULL;
}
continue;
}
dfa[l][j]=temp2[1];
printf("\n\nI%d :",ns);
for(j=0;j<I[ns].n;j++)
printf("\n\t%c -> %s",I[ns].lhs[j],I[ns].rhs[j]);
getch();
ns++;
tn=0;
for(j=0;j<15;j++)
{
templ[j]=NULL;
tempr[j][0]=NULL;
}}}
void main()
{
FILE *f;
int l;
clrscr();
for(i=0;i<15;i++)
{
I[i].n=0;
I[i].lhs[0]=NULL;
I[i].rhs[0][0]=NULL;
dfa[i][0]=NULL;
}
f=fopen("tab6.txt","r");
while(!feof(f))
{
fscanf(f,"%c",&gl[n]);
fscanf(f,"%s\n",gr[n]);
n++;
}
printf("THE GRAMMAR IS AS FOLLOWS\n");
for(i=0;i<n;i++)
printf("%c -> %s\n",gl[i],gr[i]);
I[0].lhs[0]='Z';
strcpy(I[0].rhs[0],".S");
I[0].n++;
l=0;
for(i=0;i<n;i++)
{
temp=I[0].rhs[l][1];
l++;
for(j=0;j<rr;j++)
if( temp==read[j][0] )
break;
if(j==rr)
{
read[rr][0]=temp;
rr++;
}
else
continue;
for(j=0;j<n;j++)
{
if(gl[j]==temp)
{
I[0].rhs[I[0].n][0]='.';
strcat(I[0].rhs[I[0].n],gr[j]);
I[0].lhs[I[0].n]=gl[j];
I[0].n++;
}
}
}
ns++;
printf("\nI%d :\n",ns-1);
for(i=0;i<I[0].n;i++)
printf("\t%c -> %s\n",I[0].lhs[i],I[0].rhs[i]);
for(l=0;l<ns;l++)
canonical(l);
printf("\n\n\n\t\tPRESS ANY KEY TO EXIT");
}
OUTPUT:
GRAMMAR

E->E+E
E->E/E
E->E*E
E->a|b

Enter the input symbol: a+a/b

Stack implementation table

Stack Input symbol Action


______ ____________ ______

$ a+a/b$ --
$a +a/b$ shift a
$E +a/b$ E->a
$E+ a/b$ shift +
$E+a /b$ shift a
$E+E /b$ E->a
$E /b$ E->E*E
$E/ b$ shift /
$E/b $ shift b
$E/E $ E->E/E
$E $ ACCEPT

RESULT: The C++ implementation of LR(0) Parser was compiled, executed and verified
successfully.

You might also like