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

Compiler Design

The document outlines the Compiler Design Lab work by Alby Thekkedan, a Computer Science and Engineering student. It includes various programming experiments related to finite automata, such as finding epsilon closures, converting NFA to DFA, and implementing lexical analyzers. Each experiment consists of an aim, algorithm, and code implementation, demonstrating practical applications of compiler design concepts.

Uploaded by

foralbygames
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)
19 views

Compiler Design

The document outlines the Compiler Design Lab work by Alby Thekkedan, a Computer Science and Engineering student. It includes various programming experiments related to finite automata, such as finding epsilon closures, converting NFA to DFA, and implementing lexical analyzers. Each experiment consists of an aim, algorithm, and code implementation, demonstrating practical applications of compiler design concepts.

Uploaded by

foralbygames
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/ 83

GOVT.

MODEL ENGINEERING COLLEGE


THRIKKAKKARA, ERNAKULAM

CSL411 – COMPILER DESIGN LAB


.......................................................................................................................................................

NAME: ALBY THEKKEDAN

BRANCH: COMPUTER SCIENCE AND ENGINEERING

SEMESTER : 7 ROLL NO : 20CSB08

Certified that this is the bonafide work done by

ALBY THEKKEDAN
. .....................................................................................................................................

Staff- in Charge Head of the Department

Register No............................................................ Date:.............................................

Year and month.............................................................. Thrikkakkara

Internal Examiner External Examiner


2
INDEX
PAGE.
SL.NO. DATE PROGRAM REMARKS
NO.
1 Implement a C program to find ԑ closure of all
22/08/23
states of any given NFA with ԑ transition 5
Implement a C program to convert NFA 9
2 22/08/23 with ԑ transition to NFA without ԑ transition

3
Implement a C program to convert NFA to 17
22/08/23 DFA

4
Implement a C program to minimize any given 27
22/09/23 DFA
Implement a lexical analyzer for given
5
22/09/23 language using C and the lexical analyzer
39
should ignore redundant spaces, tabs and
newlines

6 Implement a lex program to recognize all strings


26/09/23
which does not contain first four characters of 43
your name as a substring

Implement a YACC program to recognize a valid


7 26/09/23
variable which starts with a letter followed by any 45
number of digits or letters

8
Implementation of calculator using lex and yacc 47
10/10/23
9
Convert BNF rules into YACC form and write 51
10/10/23 code to generate abstract syntax tree

10 Implement a YACC program to check the syntax 61


17/10/23
of FOR statement in C

Develop an operator precedence parser for a given 65


11 17/10/23 language

12 Implement a C program to find First and Follow 69


17/10/23 of any given grammar

13
Construct a recursive descent parser for an 77
14/11/23 expression

14
Construct a shift reduce parser for a given 81
14/11/23 language

3
PROGRAM: /*Program to find ԑ closure of NFA*/
#include<stdio.h>
#include<string.h>
char result[20][20],copy[3],states[20][20];
void add_state(char a[3],int i){
strcpy(result[i],a);
}
void display(int n){
int k=0;
printf("\n\n\n Epsilon closure of %s = { ",copy);
while(k < n){
printf(" %s",result[k]);
k++;
}
printf(" } \n\n\n");
}
int main(){
FILE *INPUT;
INPUT=fopen("input.txt","r");
char state[3];
int end,i=0,n,k=0;
char state1[3],input[3],state2[3];
printf("\n Enter the no of states: ");
scanf("%d",&n);
printf("\n Enter the states n");
for(k=0;k<3;k++){
scanf("%s",states[k]);
}
for( k=0;k<n;k++){
i=0;
strcpy(state,states[k]);
strcpy(copy,state);
add_state(state,i++);
while(1){
end = fscanf(INPUT,"%s%s%s",state1,input,state2);
if (end == EOF ){
break;
}
if( strcmp(state,state1) == 0 ){
if( strcmp(input,"e") == 0 ) {
add_state(state2,i++);
strcpy(state, state2);
}

4
EXPERIMENT - 1

Program to find ԑ - Closure of all states of any given NFA with ԑ


transitions

AIM: To implement a program to find the ԑ closure of all states of any given NFA with
ԑ transitions.

ALGORITHM:

Step 0: Start
Step 1: Declare arrays result, copy and states to store immediate and final
results.
Step 2: Declare the variables to hold state information and take input n which is
number of states from user.
Step 3: Open the file using fopen function and store its pointer in INPUT.
Step 4: Give state names for the inputted number of states.
Step 5: For each state in the states array,
5.1:- Initialise I to 0 and copy current state to state variable.
5.2:- Call add-state function to add current state to result array at index i.
5.3:- Enter a loop that reads transitions from input file until EOF is reached.
5.3.1:- if current state matches ‘state1’ and input symbol is epsilon(“ԑ”),
call add_state function to add ‘state2’ to ‘result’ array at index I and
update ‘state’ with value of ‘state2’.
5.4:- Increment i for next iteration.
5.5:- Call the display function to print epsilon closure of current state.
5.6:- Rewind input file to its beginning using rewind function.
Step 6: Close the input file using fclose function.
Step 7: Stop

5
}
}
display(i);
rewind(INPUT);
}
return 0;
}

OUTPUT:

6
RESULT: Program to find the epsilon closure of all states of an epsilon
NFA was successfully implemented

7
PROGRAM: /*Program to convert ԑ-NFA to NFA*/
#include<stdio.h>
#include<stdlib.h>
struct node
{
int st;
struct node *link;
};
void findclosure(int,int);
void insert_trantbl(int ,char, int);
int findalpha(char);
void findfinalstate(void);
void unionclosure(int);
void print_e_closure(int);
static int set[20],nostate,noalpha,s,notransition,nofinal,start,finalstate[20],r,buffer[20];
static char c;
char alphabet[20];
static int e_closure[20][20]={0};
struct node * transition[20][20]={NULL};
void main()
{
int i,j,k,m,t,n;
struct node *temp;
printf("enter the number of alphabets?\n");
scanf("%d",&noalpha);
getchar();
printf("NOTE:- [ use letter e as epsilon]\n");
printf("NOTE:- [e must be last character ,if it is present]\n");
printf("\nEnter alphabets?\n");
for(i=0;i<noalpha;i++)
{
alphabet[i]=getchar();
getchar();
}
printf("Enter the number of states?\n");
scanf("%d",&nostate);
printf("Enter the start state?\n");
scanf("%d",&start);
printf("Enter the number of final states?\n");
scanf("%d",&nofinal);
printf("Enter the final states?\n");
for(i=0;i<nofinal;i++)
scanf("%d",&finalstate[i]);
printf("Enter no of transition?\n");
scanf("%d",&notransition);
printf("NOTE:- [Transition is in the form--> qno alphabet qno]\n");
printf("NOTE:- [States number must be greater than zero]\n");
printf("\nEnter transition?\n");

8
EXPERIMENT - 2

Program to convert NFA with ԑ transition to NFA without ԑ transitions

AIM: To implement a program to convert NFA with ԑ transition to NFA without ԑ


transitions.

ALGORITHM:

Step 0: Start the program.


Step 1: Read the number of alphabets, states, final states and transitions and take
input for the same from user.
Step 2: Initialise ԑ-closure matrix to store ԑ-closure for each state and a buffer array
to track visited states during ԑ-closure calculation.
Step 3: Compute ԑ-closure for each state.
3.1:- For each state i, initialise i to 0 and clear the buffer array.
3.2:- Call findclosure( i,i) to compute ԑ-closure of state I and store it in ԑ-
closure[][].
Step 4: Print equivalent NFA without epsilon.
4.1:- Print start state’s ԑ-closure.
4.2:- Print alphabet symbols.
4.3:- For each state i, print ԑ-closure of state i.
Step 5: Generate transitions for equivalent NFA.
5.1:- For each state i inside which for each alphabet j, initialise an empty set
to track reachable states from ԑ-closure of state i.
5.2:- For each state k in ԑ-closure of i, traverse transitions for state ‘k’ on
alphabet symbol and add reachable states to set.
5.3:- Print transitions from ԑ-closure of state I to set of reachable states on
alphabet symbol.
Step 6: Identify final states for equivalent NFA.
6.1:- For each final state index i in finalState[], for each state ‘j’, for each
state ‘k’ in ԑ-closure of state ‘j’; if k matches current final state index ‘i’, print ԑ-
closure of state j.
Step 7: Stop the program.

9
for(i=0;i<notransition;i++)
{
scanf("%d %c%d",&r,&c,&s);
insert_trantbl(r,c,s);
}
printf("\n");
for(i=1;i<=nostate;i++)
{
c=0;
for(j=0;j<20;j++)
{
buffer[j]=0;
e_closure[i][j]=0;
}
findclosure(i,i);
}
printf("Equivalent NFA without epsilon\n");
printf("-----------------------------------\n");
printf("start state:");
print_e_closure(start);
printf("\nAlphabets:");
for(i=0;i<noalpha;i++)
printf("%c ",alphabet[i]);
printf("\nStates :" );
for(i=1;i<=nostate;i++)
print_e_closure(i);
printf("\nTransitions are...:\n");
for(i=1;i<=nostate;i++)
{
for(j=0;j<noalpha-1;j++)
{
for(m=1;m<=nostate;m++)
set[m]=0;
for(k=0;e_closure[i][k]!=0;k++)
{
t=e_closure[i][k];
temp=transition[t][j];
while(temp!=NULL)
{
unionclosure(temp->st);
temp=temp->link;
}
}
printf("\n");
print_e_closure(i);
printf("%c\t",alphabet[j] );
printf("{");
for(n=1;n<=nostate;n++)
{
if(set[n]!=0)

10
11
printf("q%d,",n);
}
printf("}");
}
}
printf("\nFinal states:");
findfinalstate();
}
void findclosure(int x,int sta)
{
struct node *temp;
int i;
if(buffer[x])
return;
e_closure[sta][c++]=x;
buffer[x]=1;
if(alphabet[noalpha-1]=='e' && transition[x][noalpha-1]!=NULL)
{
temp=transition[x][noalpha-1];
while(temp!=NULL)
{
findclosure(temp->st,sta);
temp=temp->link;
}
}
}
void insert_trantbl(int r,char c,int s)
{
int j;
struct node *temp;
j=findalpha(c);
if(j==999)
{
printf("error\n");
exit(0);
}
temp=(struct node *) malloc(sizeof(struct node));
temp->st=s;
temp->link=transition[r][j];
transition[r][j]=temp;
}
int findalpha(char c)
{
int i;
for(i=0;i<noalpha;i++)
if(alphabet[i]==c)
return i;

return(999);}

12
13
void unionclosure(int i)
{
int j=0,k;
while(e_closure[i][j]!=0)
{
k=e_closure[i][j];
set[k]=1;
j++;
}
}
void findfinalstate()
{
int i,j,k,t;
for(i=0;i<nofinal;i++)
{
for(j=1;j<=nostate;j++)
{
for(k=0;e_closure[j][k]!=0;k++)
{
if(e_closure[j][k]==finalstate[i])
{

print_e_closure(j);
}
}
}
}
}
void print_e_closure(int i)
{
int j=0;
printf("{");
if(e_closure[i][j]!=0)
printf("q%d,",e_closure[i][0]);
printf("}\t");
}
OUTPUT:

14
RESULT: Program to convert ԑ-NFA to NFA was successfully
implemented.

15
PROGRAM: /*Program to convert NFA to DFA*/
#include<stdio.h>
#include<stdlib.h>
struct node
{
int st;
struct node *link;
};
struct node1
{
int nst[20];
};
void insert(int ,char, int);
int findalpha(char);
void findfinalstate(void);
int insertdfastate(struct node1);
int compare(struct node1,struct node1);
void printnewstate(struct node1);
static int set[20],nostate,noalpha,s,notransition,nofinal,start,finalstate[20],r,buffer[20];
static char c;
int complete=-1;
char alphabet[20];
static int eclosure[20][20]={0};
struct node1 hash[20];
struct node * transition[20][20]={NULL};
void main()
{
int i,j,k,m,t,n,l;
struct node *temp;
struct node1 newstate={0},tmpstate={0};
printf("Enter the number of alphabets?\n");
printf("NOTE:- [ use letter e as epsilon]\n");
printf("NOTE:- [e must be last character ,if it is present]\n");
printf("\nEnter No of alphabets and alphabets?\n");
scanf("%d",&noalpha);
getchar();
for(i=0;i<noalpha;i++)
{
alphabet[i]=getchar();
getchar();
}
printf("Enter the number of states?\n");
scanf("%d",&nostate);
printf("Enter the start state?\n");
scanf("%d",&start);
printf("Enter the number of final states?\n");
scanf("%d",&nofinal);
printf("Enter the final states?\n");
for(i=0;i<nofinal;i++)

16
EXPERIMENT - 3

Program to convert NFA to DFA

AIM: To implement a program to convert NFA to DFA.

ALGORITHM:

Step 0: Start the program.


Step 1: Read the number of alphabets, states, final states and transitions and get
the input for same from user.
Step 2: Initialise the transition table to store NFA transitions, ԑ-closure matrix to
store ԑ-closure sets for each state, DFA state hash table. Initialise ‘complete’ to -1
and ‘i’ to -1.
Step 3: Perform initialisation for subset construction.
3.1:- Create an empty DFA state ‘newstate’ with start state.
3.2:- Call ‘insertdfastate()’ to insert newstate into DFA state hash table.
Step 4: In the loop of subset construction, increment i while i is not equal to
complete and get next DFA state ‘newstate’ from hash table.
Step 5: For each alphabet symbol k:-
5.1:- Create an empty set to track NFA states in DFA state.
5.2:- For each NFA state j, if newstate contains NFA state ‘j’, traverse
transitions for NFA state j using current alphabet symbol ‘k’ and add reachable
states to set using ԑ-closure.
5.3:- if set is not empty, create a new DFA state using states in ‘set[]’. Call
insertdfastate() to insert tmpstate into DFA state hash table.
5.3.1:- Print transitions from newstate to tmpstate on alphabet symbol
‘alphabet[k]’.
Step 6: identify DFA accepting states.
6.1:- In each DFA state in hash table, for each NFA final state, if DFA state
contains an NFA final state, mark it as DFA accepting state.
Step 7: Print the resultant DFA details.
Step 8: Stop the program.

17
scanf("%d",&finalstate[i]);
printf("Enter no of transition?\n");
scanf("%d",&notransition);
printf("NOTE:- [Transition is in the form–> qno alphabet qno]\n");
printf("NOTE:- [States number must be greater than zero]\n");
printf("\nEnter transition?\n");
for(i=0;i<notransition;i++)
{
scanf("%d %c %d",&r,&c,&s);
insert(r,c,s);
}
for(i=0;i<20;i++)
{
for(j=0;j<20;j++)
hash[i].nst[j]=0;
}
complete=-1;
i=-1;
printf("\nEquivalent DFA.....\n");
printf("Trnsitions of DFA\n");
newstate.nst[start]=start;
insertdfastate(newstate);
while(i!=complete)
{
i++;
newstate=hash[i];
for(k=0;k<noalpha;k++)
{
c=0;
for(j=1;j<=nostate;j++)
set[j]=0;
for(j=1;j<=nostate;j++)
{
l=newstate.nst[j];
if(l!=0)
{
temp=transition[l][k];
while(temp!=NULL)
{
if(set[temp->st]==0)
{
c++;
set[temp->st]=temp->st;
}
temp=temp->link;
}
}
}
printf("\n");
if(c!=0)

18
19
{
for(m=1;m<=nostate;m++)
tmpstate.nst[m]=set[m];
insertdfastate(tmpstate);
printnewstate(newstate);
printf("%c\t",alphabet[k]);
printnewstate(tmpstate);
printf("\n");
}
else
{
printnewstate(newstate);
printf("%c\t", alphabet[k]);
printf("NULL\n");
}
}
}
printf("\nStates of DFA:\n");
for(i=0;i<=complete;i++)
printnewstate(hash[i]);
printf("\n Alphabets:\n");
for(i=0;i<noalpha;i++)
printf("%c\t",alphabet[i]);
printf("\n Start State:\n");
printf("q%d",start);
printf("\nFinal states:\n");
findfinalstate();
}
int insertdfastate(struct node1 newstate)
{
int i;
for(i=0;i<=complete;i++)
{
if(compare(hash[i],newstate))
return 0;
}
complete++;
hash[complete]=newstate;
return 1;
}
int compare(struct node1 a,struct node1 b)
{
int i;
for(i=1;i<=nostate;i++)
{
if(a.nst[i]!=b.nst[i])
return 0;
}
return 1;

20
21
}
void insert(int r,char c,int s)
{
int j;
struct node *temp;
j=findalpha(c);
if(j==999)
{
printf("error\n");
exit(0);
}
temp=(struct node *) malloc(sizeof(struct node));
temp->st=s;
temp->link=transition[r][j];
transition[r][j]=temp;
}
int findalpha(char c)
{
int i;
for(i=0;i<noalpha;i++)
if(alphabet[i]==c)
return i;
return(999);
}
void findfinalstate()
{
int i,j,k,t;
for(i=0;i<=complete;i++)
{
for(j=1;j<=nostate;j++)
{
for(k=0;k<nofinal;k++)
{
if(hash[i].nst[j]==finalstate[k])
{
printnewstate(hash[i]);
printf("\t");
j=nostate;
break;
}
}
}
}
}
void printnewstate(struct node1 state)
{
int j;
printf("{");
for(j=1;j<=nostate;j++)
{

22
23
if(state.nst[j]!=0)
printf("q%d,",state.nst[j]);
}
printf("}\t");
}
OUTPUT:

24
RESULT: Program to convert NFA to DFA was successfully implemented.

25
PROGRAM: /*Program to minimize any DFA*/
#include <stdio.h>
#include <stdlib.h>
static int nostate, noalpha, s, notransition, nofinal, start, finalstate[20], r;
char alphabet[20];
int transition_map[30][30], table[30][30], nonfinalstate[20], partition[20][20];
int findalpha(char a)
{
int i;
for (i = 0; i < noalpha; i++)
if (alphabet[i] == a)
return i;
return (-1);
}
int main()
{
int i, j, p[20], q[20], k;
char a;
for (i = 0; i < 30; i++)
{
for (j = 0; j < 30; j++)
transition_map[i][j] = -1;
}
printf("Enter the number of alphabets: ");
scanf("%d", &noalpha);
getchar();
printf("Enter the alphabets: ");
for (i = 0; i < noalpha; i++)
{
alphabet[i] = getchar();
getchar();
}
printf("Enter the number of states: ");
scanf("%d", &nostate);
printf("Enter the start state: ");
scanf("%d", &start);
printf("Enter the number of final states: ");
scanf("%d", &nofinal);
printf("Enter the final state(s): ");
for (i = 0; i < nofinal; i++)
scanf("%d", &finalstate[i]);
printf("Enter no of transition: ");
scanf("%d", &notransition);
printf("Enter Transition in the form –> state alphabet next_state\n");
for (i = 0; i < notransition; i++)
{
scanf("%d %c %d", &r, &a, &s);
j = findalpha(a);
if (j == -1)

26
EXPERIMENT - 4

Program to minimize any given DFA

AIM: To implement a program to minimize any given DFA.

ALGORITHM:

Step 0: Start the program.


Step 1: Initialise the DFA table including number of states, symbols and final states.
Step 2: Create an array to represent state names and initialise it.
Step 3: Initialise variables for the number of optimised DFA states and new final
states.
Step 4: Print the original DFA table for reference.
Step 5: Initialise equivalence classes of states based on final and non-final states.
Step 6: Enter the main loop for state minimisation.
6.1:- Print the current equivalence classes.
6.2:- Generate the optimised DFA table based on current equivalence
classes.
6.3:- Check if any state can be further divided into new equivalence classes.
6.4:- If there are new equivalence classes, update state names table and go
back to step 6.1.
6.5:- If no new equivalence classes are found, exit the loop.
Step 7: Calculate new final states for minimised DFA.
Step 8: Print the minimised final DFA.
Step 9: Stop the program.

27
{
printf("\nerror\n");
exit(1);
}
transition_map[r][j] = s;
}
for (i = 0; i < nostate; i++)
{
for (j = 0; j < i; j++)
{
table[i][j] = 0;
}
}
int f = 0;
k = 0;
for (i = 0; i < nostate; i++)
{
f = 0;
for (j = 0; j < nofinal; j++)
{
if (i == finalstate[j])
{
f = 1;
break;
}
}
if (f == 0)
{
nonfinalstate[k++] = i;
}
}
for (i = 0; i < nofinal; i++)
{
for (j = 0; j < (nostate - nofinal); j++)
if (nonfinalstate[j] > finalstate[i])
table[nonfinalstate[j]][finalstate[i]] = 1;
else
table[finalstate[i]][nonfinalstate[j]] = 1;
}
int change = 1;
while (change == 1)
{
change = 0;
for (i = 0; i < nostate; i++)
{
for (j = 0; j < i; j++)
{
if (table[i][j] != 1)
{
for (k = 0; k < noalpha; k++)

28
29
p[k] = transition_map[i][k];
for (k = 0; k < noalpha; k++)
q[k] = transition_map[j][k];
for (k = 0; k < noalpha; k++)
{
if (p[k] > q[k])
{
if (table[p[k]][q[k]] == 1)
{
change = 1;
table[i][j] = 1;
break;
}
}
else if (p[k] < q[k])
{
if (table[q[k]][p[k]] == 1)
{
change = 1;
table[i][j] = 1;
break;
}
}
}
}
}
}
}
k = 0;
for (i = 0; i < nostate; i++)
{
k = 0;
partition[i][k++] = i;
for (j = 0; j < i; j++)
if (table[i][j] == 0)
{
partition[i][k++] = j;
}
partition[i][k] = -1;
}
int newstate[20] = {0}, m;
printf("\nStates in minimized DFA");
printf("\n----------------------------\n");
for (i = nostate - 1; i >= 0; i--)
{
k = 0;
if (newstate[i] == 0)
{
printf("{");

30
31
while (partition[i][k] != -1)
{
if (newstate[partition[i][k]] == 0)
{
newstate[partition[i][k]] = 1;
printf("q%d ", partition[i][k]);
}
k++;
}
printf("}\n");
}
}
return 0;
}
OUTPUT:

32
RESULT: Program to minimise DFA was successfully implemented.

33
34
Introduction to Lex

Lex is a tool or a computer program that generates Lexical Analyzers (converts the
stream of characters into tokens). The Lex tool itself is a compiler. The Lex
compiler takes the input and transforms that input into input patterns. It is
commonly used with YACC(Yet Another Compiler Compiler).

The function of Lex is as follows:


1)Lexical Analyzer Creation: The process begins by creating a program called lex.1
using Lex's language. This program defines the rules and patterns for recognizing
tokens in the source code.
2)Lex Compiler Execution: The lex.1 program is then executed using the Lex
compiler. This step generates a C program named lex.yy.c
3)C Compiler Execution: The C compiler is then used to compile the generated
lex.yy.c program. The result is an object program referred to as a.out
4)Lexical Analysis: The a.out object program is essentially a lexical analyzer. When
this program is run, it takes an input stream of source code and transforms it into a
sequence of tokens based on the rules defined in the original lex.1 program

Any lex file consists of the following three parts-


1)Definitions: This section of lex files contains declarations of constant, variable,
and regular definitions.
2)Rules: This section of the lex files defines the rules in the form of the regular
expressions and corresponding actions that the lexer should take to identify tokens
in the input stream. Each rule consists of a regular expression followed by a code
block that specifies the action to take when the regular expression matches. The
rule is in the form of- p1 {action1} p2 {action2} ... pn {action}. Where Pi is the ith
Regular expression and action is the action that must be taken when the regular
expression matches.
3)User Subroutines: This section contains the user-defined functions that can be
used by the action code block in the rules section of the lex file.

The formal lex file has the following format-

{ definitions }
%%
{ rules }
%%
{ user subroutines }

35
36
Introduction to YACC

Each translation rule input to YACC has a string specification that resembles a
production of a grammar-it has a nonterminal on the LHS and a few alternatives on
the RHS. For simplicity, we will refer to a string specification as a production. YACC
generates an LALR(1) parser for language L from the productions, which is a
bottom-up parser. The parser would operate as follows: For a shift action, it would
invoke the scanner to obtain the next token and continue the parse by using that
token. While performing a reduced action in accordance with production, it would
perform the semantic action associated with that production.

A parser generator is a program that takes as input a specification of a syntax and


produces as output a procedure for recognizing that language. Historically, they
are also called compiler compilers. YACC (yet another compiler-compiler) is an
LALR(1) (LookAhead, Left-to-right, Rightmost derivation producer with 1 lookahead
token) parser generator. YACC was originally designed for being complemented by
Lex.

Input File: YACC input file is divided into three parts:-


Definitions: these include the header files and any token information used in the
syntax. These are located at the top of the input file. Here, the tokens are defined
using a modulus sign. In the YACC, numbers are automatically assigned for tokens.
Rules: The rules are defined between %% and %%. These rules define the actions
for when the token is scanned and are executed when a token matches the
grammar.
Auxiliary Routines: Auxiliary routines contain the function required in the rules
section. This Auxiliary section includes the main() function, where the yyparse()
function is always called. This yyparse() function plays the role of reading the
token, performing actions and then returning to the main() after the execution or
in the case of an error. 0 is returned after successful parsing and 1 is returned after
an unsuccessful parsing.

37
PROGRAM: /*Program to implement lexical analyser*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int kwd(char buffer[]);
int main()
{
char ch, buffer[15], buf[15], operators[] = "+-*/%=,;()";
FILE *fp;
int i, j = 0;
int ido = 0;
fp = fopen("inputfile.txt", "r");
if (fp == NULL)
{
printf("error while opening the file\n");
exit(0);
}
while ((ch = fgetc(fp)) != EOF)
{
for (i = 0; i < 10; i++)
{
if (ch == operators[i] && kwd(buffer) == 0)
printf("id ");
}
for (i = 0; i < 10; ++i)
{
if (ch == operators[i])
if (operators[i] == '+')
printf("op-plus ");
else if (operators[i] == '-')
printf("op-sub ");
else if (operators[i] == '*')
printf("op-mul ");
else if (operators[i] == '/')
printf("op-div ");
else if (operators[i] == '%')
printf("op-mod ");
else if (operators[i] == '=')
printf("op-equ ");
else if (operators[i] == ';')
printf(";");
else if (operators[i] == ',')
printf(",");
else if (operators[i] == '(')
printf(".");
}
if (isalnum(ch))
{

38
EXPERIMENT - 5

Lexical Analyser using C to remove redundant spaces, tabs and


newlines

AIM: To implement a lexical analyser for given language using C and lexical
analyser should ignore redundant spaces, tabs and newlines.

ALGORITHM:

Step 0: Start the program


Step 1: Include the necessary C libraries.
Step 2: Define token type for lexical analyser including keywords, identifiers and
operators, etc for input language.
Step 3: Create a state machine to recognize different lexical elements. Define
states for each type of token & transitions between states based on input
characters.
Step 4: Initialise variables to store the current state, lexeme, etc being processed.
Step 5: Read the input source code.
Step 6: Implement a loop to iterate through each character in source code.
Step 7: Build the lexeme by appending characters to it.
Step 8: Check for spaces, tabs, etc and ignore them.
Step 9: When a token is recognised, determine its type based on the final state in
state machine.
Step 10: Output the recognised tokens along with their lexeme.
Step 11: Stop the program.

39
buffer[j++] = ch;
}
else if ((ch == ' ' || ch == '\n') && (j != 0))
{
buffer[j] = '\0';
j = 0;
if (kwd(buffer) == 1)
printf("kwd ");
}
}
fclose(fp);
return 0;
}
int kwd(char buffer[])
{
char keywords[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"};
int i, flag = 0;
// returns 1 if the buffer is a keyword
for (i = 0; i < 32; ++i)
{
if (strcmp(keywords[i], buffer) == 0)
{
flag = 1;
break;
}
}
return flag;
}
OUTPUT:
Inputfile.txt

40
RESULT: Program to implement lexical analyser using C by ignoring redundant
spaces, tabs and newline was successfully implemented.

41
PROGRAM: /* Lexical Program to recognize all strings which does not first four characters of
your name as substring*/

%{
#include<stdio.h>
#include<math.h>
FILE *file;
%}

%%
[a-zA-Z]*"alby"[a-zA-Z]* {}
[a-zA-Z]* {printf("%s\n",yytext);}
%%
int main()
{
file = fopen("input.txt", "r");
if (!file)
{
printf("could not open the file");
exit(0);
}
yyin = file;
yylex();
printf("\n");
return (0);
}
int yywrap()
{
return (1);
}

OUTPUT:

42
EXPERIMENT - 6

Lexical Program to recognize all strings which does not first four
characters of your name as substring

AIM: To implement a lexical program to recognize all strings which does not first
four characters of your name as substring.

ALGORITHM:

Step 0: Start the program.


Step 1: Include the necessary C libraries.
Step 2: Define the first four characters of the name that needs to be excluded from
the strings.
Step 3: Define the lexical rules to recognise strings that do not contain specified
substring.
Step 4: Check if the particular yytext contains first four letters as substring by
specifying the corresponding rule and it would print the words that do not contain
the substring
Step 5: Define the main function to invoke the lex scanner.
Step 6: Stop the program.

RESULT: Lexical program to recognize all strings which does not first four
characters of your name as substring was successfully implemented.

43
PROGRAM: /*Yacc program to recognize valid variable*/
Yacc program:
%{
#include<stdio.h>
#include<stdlib.h>
%}
%token LET DIG
%%
variable:var
;
var:var DIG
|var LET
|LET
;
%%
int main() {
printf("Enter the variable:\n");
yyparse();
printf("Valid variable\n");
return 0;
}
int yyerror()
{
printf("Invalid variable \n");
exit(0);
}
Lex Program:
%{
#include "y.tab.h"
%}
%%
[a-zA-Z] {return LET;}
[0-9] {return DIG;}
. {return yytext[0];}
\n {return 0;}
%%
int yywrap() {
return 1;
}
OUTPUT:

44
EXPERIMENT - 7

YACC Program to recognize a valid variable which starts with a letter


followed by any number of letters or digits

AIM: To implement a YACC Program to recognize a valid variable which starts with
a letter followed by any number of letters or digits.

ALGORITHM:

Step 0: Start the program


Step 1: Specify the tokens needed to represent the components of a valid variable.
Step 2: Create grammar rules that define the structure of a valid variable. It should
satisfy the condition that a variable starts with a letter followed by letters or digits.
Step 3: Write your rules corresponding to grammar rules, capturing syntax of a
valid variable.
Step 4: Specify actions to be taken when a valid variable is recognized or not.
Step 5: Print the output.
Step 6: Stop the program.

RESULT: YACC Program to recognize a valid variable which starts with a letter
followed by any number of letters or digits was successfully implemented.

45
PROGRAM: /*Calculator using lex and yacc*/
Yacc Program
%{
#include<stdio.h>
int flag=0;
%}
%token NUMBER
%left '+' '-'
%left '*' '/' '%'
%left '(' ')'
%%
ArithmeticExpression: E{
printf("\nResult=%d\n",$$);
return 0;
};
E:E'+'E {$$=$1+$3;}
|E'-'E {$$=$1-$3;}
|E'*'E {$$=$1*$3;}
|E'/'E {$$=$1/$3;}
|E'%'E {$$=$1%$3;}
|'('E')' {$$=$2;}
| NUMBER {$$=$1;}
;
%%
void main()
{
printf("\nEnter Any Arithmetic Expression which can have operations Addition, Subtraction,
Multiplication, Divison, Modulus and Round brackets:\n");
yyparse();
if(flag==0)
printf("\nEntered arithmetic expression is Valid\n\n");
}
void yyerror()
{
printf("\nEntered arithmetic expression is Invalid\n\n");
flag=1;
}
Lex Program
%{
#include<stdio.h>
#include "y.tab.h"
extern int yylval;
%}
%%
[0-9]+ {
yylval=atoi(yytext);
return NUMBER;
}
[\t] ;

46
EXPERIMENT - 8

Implementation of calculator using Lex and Yacc

AIM: To implement a calculator using lex and yacc.

ALGORITHM:

Step 0: Start the program.


Step 1: Define tokens such as numbers, operators and parenthesis.
Step 2: Use lex to define regular expressions matching the pattern of tokens.
Step 3: Define the grammar rules f calculator considering precedence &
associativity of operators.
Step 4: Write yacc rules & define action for each rule.
Step 5: In yacc actions, builds an AST that represents structure of input expression.
Step 6: Extend yacc actions to perform actual calculations using AST.
Step 7: Print output/result of calculation.
Step 8: Stop the program.

47
[\n] return 0;
. return yytext[0];
%%
int yywrap()
{
return 1;
}

OUTPUT:

48
RESULT: Implementation of calculator using lex and yacc was successfully done.

49
PROGRAM: /*Yacc program to convert BNF to abstract syntax tree*/
Yacc Program
%{
#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;
int Index=0,tIndex=0,StNo,Ind,tInd;
extern int LineNo;
%}
%union
{
char var[10];
}
%token <var> NUM VAR RELOP
%token MAIN IF ELSE WHILE TYPE
%type <var> EXPR ASSIGNMENT CONDITION IFST ELSEST WHILELOOP
%left '-' '+'
%left '*' '/'
%%
PROGRAM : MAIN BLOCK
;
BLOCK: '{' CODE '}'
;
CODE: BLOCK
| STATEMENT CODE
| STATEMENT
;
STATEMENT: DESCT ';'
| ASSIGNMENT ';'
| CONDST
| WHILEST
;
DESCT: TYPE VARLIST
;
VARLIST: VAR ',' VARLIST
| VAR
;
ASSIGNMENT: VAR '=' EXPR{

50
EXPERIMENT - 9

Yacc program to change BNF into Abstract Syntax Tree

AIM: To convert BNF rules into YACC form and write code to generate abstract
syntax tree.

ALGORITHM:

Step 0: Start the program


Step 1: Identify types of nodes in abstract syntax tree.
Step 2: Define C structures in YACC file to represent the different types of nodes.
Step 3: For each production rule in grammar, modify yacc action to create and link
nodes of AST.
Step 4: In yacc actions, instantiate the structure for the corresponding AST.
Step 5: Establish the parent-child relationships between nodes by updating points
to AST nodes.
Step 6: Return root of AST.
Step 7: Print the root node value.
Step 8: Stop the program.

51
strcpy(QUAD[Index].op,"=");
strcpy(QUAD[Index].arg1,$3);
strcpy(QUAD[Index].arg2,"");
strcpy(QUAD[Index].result,$1);
strcpy($$,QUAD[Index++].result);
}
;
EXPR: EXPR '+' EXPR {AddQuadruple("+",$1,$3,$$);}
| EXPR '-' EXPR {AddQuadruple("-",$1,$3,$$);}
| EXPR '*' EXPR {AddQuadruple("*",$1,$3,$$);}
| EXPR '/' EXPR {AddQuadruple("/",$1,$3,$$);}
| '-' EXPR {AddQuadruple("UMIN",$2,"",$$);}
| '(' EXPR ')' {strcpy($$,$2);}
| VAR
| NUM
;
CONDST: IFST{
Ind=pop();
sprintf(QUAD[Ind].result,"%d",Index);
Ind=pop();
sprintf(QUAD[Ind].result,"%d",Index);
}
| IFST ELSEST
;
IFST: IF '(' CONDITION ')' {
strcpy(QUAD[Index].op,"==");
strcpy(QUAD[Index].arg1,$3);
strcpy(QUAD[Index].arg2,"FALSE");
strcpy(QUAD[Index].result,"-1");
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++;
};
ELSEST: ELSE{
tInd=pop();
Ind=pop();
push(tInd);
sprintf(QUAD[Ind].result,"%d",Index);
}
BLOCK{
Ind=pop();
sprintf(QUAD[Ind].result,"%d",Index);
};

52
53
CONDITION: VAR RELOP VAR {AddQuadruple($2,$1,$3,$$);
StNo=Index-1;
}
| VAR
| NUM
;
WHILEST: WHILELOOP{
Ind=pop();
sprintf(QUAD[Ind].result,"%d",StNo);
Ind=pop();
sprintf(QUAD[Ind].result,"%d",Index);
}
;
WHILELOOP: WHILE '(' CONDITION ')' {
strcpy(QUAD[Index].op,"==");
strcpy(QUAD[Index].arg1,$3);
strcpy(QUAD[Index].arg2,"FALSE");
strcpy(QUAD[Index].result,"-1");
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++;
}
;
%%
extern FILE *yyin;
int main(int argc,char *argv[])
{
FILE *fp;
int i;
if(argc>1)
{
fp=fopen(argv[1],"r");
if(!fp)
{
printf("\n File not found");
exit(0);
}
yyin=fp;
}
yyparse();
printf("\n\n\t\t -----------------------------------""\n\t\t Pos Operator Arg1 Arg2 Result" "\n\t\t ----
-------------------------------");
for(i=0;i<Index;i++)

54
55
{
printf("\n\t\t %d\t %s\t %s\t %s\t%s",i,QUAD[i].op,QUAD[i].arg1,QUAD[i].arg2,QUAD[i].result);
}
printf("\n\t\t -----------------------------------");
printf("\n\n");
return 0;
}
void push(int data)
{
stk.top++;
if(stk.top==100)
{
printf("\n Stack overflow\n");
exit(0);
}
stk.items[stk.top]=data;
}
int pop()
{
int data;
if(stk.top==-1)
{
printf("\n Stack underflow\n");
exit(0);
}
data=stk.items[stk.top--];
return data;
}
void AddQuadruple(char op[5],char arg1[10],char arg2[10],char result[10])
{
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()
{
printf("\n Error on line no:%d",LineNo);
}
Lex Program
%{
#include"y.tab.h"
#include<stdio.h>
#include<string.h>
int LineNo=1;
%}
identifier [a-zA-Z][_a-zA-Z0-9]*

56
57
number [0-9]+|([0-9]*\.[0-9]+)
%%
main\(\) return MAIN;
if return IF;
else return ELSE;
while return WHILE;
int |
char |
float return TYPE;
{identifier} {strcpy(yylval.var,yytext);
return VAR;}
{number} {strcpy(yylval.var,yytext);
return NUM;}
\< |
\> |
\>= |
\<= |
== {strcpy(yylval.var,yytext);
return RELOP;}
[ \t] ;
\n LineNo++;
. return yytext[0];
%%
int yywrap()
{
return 1;
}
OUTPUT:
Input.c

58
RESULT: Conversion of BNF rules into Yacc form to generate abstract syntax tree
was successfully implemented.

59
PROGRAM: /*Yacc program to check syntax of FOR statement*/
Yacc Program
%{
#include<stdio.h>
int valid=1;
%}
%token FOR LPAREN TYPE ID EQ NUMBER COMMA COMP RPAREN UPD
%%
FORSTMT:FOR LPAREN TYPE ID EQ NUMBER COMMA ID COMP NUMBER COMMA ID UPD
RPAREN
%%
int yyerror()
{
printf("Not Valid For Syntax");
valid=0;
return 0;
}
int main()
{
yyparse();
if(valid)
{
printf("Valid Syntax");
}
return 0;
}

60
EXPERIMENT - 10

Yacc program to check syntax of For statement in C

AIM: To convert BNF rules into YACC form and write code to generate abstract
syntax tree.

ALGORITHM:

Step 0: Start the program.


Step 1: Identify the structure of a for loop in C & define grammar rules.
Step 2: Write yacc rules based on the grammar.
Step 3: Define the tokens needed for the for loop in lex file including keywords,
identifiers, etc.
Step 4: In the yacc actions, perform checks to ensure that the for loop follows
correct syntax.
Step 5: Print the output.
Step 6: Stop the program.

61
Lex Program
%{
#include<stdio.h>
#include "y.tab.h"
%}
%%
for {return FOR;}
[(] {return LPAREN;}
int|double|float {return TYPE;}
[a-zA-Z_][a-zA-Z0-9_]* {return ID;}
[=] {return EQ;}
[0-9]+ {return NUMBER;}
[;] {return COMMA;}
[<>] {return COMP;}
[<>][=] {return COMP;}
[)] {return RPAREN;}
[+][+] {return UPD;}
[-][-] {return UPD;}
[ ] {}
[\n] {return 0;}
%%
int yywrap()
{
return 1;
}

OUTPUT:

62
RESULT: Yacc program to check the syntax of for statement in C was successfully
implemented.

63
PROGRAM: /*Operator precedence parser*/
#include<stdio.h>
#include<string.h>
void main(){
char stack[20],ip[20],opt[10][10][1],ter[10];
int i,j,k,n,top=0,col,row;
for(i=0;i<10;i++)
{
stack[i]=0;
ip[i]=0;
for(j=0;j<10;j++)
{
opt[i][j][1]=0;
}
}
printf("Enter the no.of terminals :\n");
scanf("%d",&n);
printf("\nEnter the terminals :\n");
scanf("%s",ter);
printf("\nEnter the table values :\n");
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
printf("Enter the value for %c %c:",ter[i],ter[j]);
scanf("%s",opt[i][j]);
}
}
printf("\n**** OPERATOR PRECEDENCE TABLE ****\n");
for(i=0;i<n;i++)
{
printf("\t%c",ter[i]);}
printf("\n");
for(i=0;i<n;i++){printf("\n%c",ter[i]);
for(j=0;j<n;j++){printf("\t%c",opt[i][j][0]);}}
stack[top]='$';
printf("\nEnter the input string:");
scanf("%s",ip);
i=0;
printf("\nSTACK\t\t\tINPUT STRING\t\t\tACTION\n");
printf("\n%s\t\t\t%s\t\t\t",stack,ip);
while(i<=strlen(ip))
{
for(k=0;k<n;k++)
{
if(stack[top]==ter[k])
col=k;
if(ip[i]==ter[k])

64
EXPERIMENT - 11

Operator Precedence Parser

AIM: To develop an operator precedence parser for a given language.

ALGORITHM:

Algo(Grammar G, input string w, Parsing Table T)


{
set p to point to the first symbol of w$;
repeat forever
if($ is on top of stack and p points to $)
Then return; //success
else
{
let a be the topmost terminal symbol on stack;
let b be the symbol pointed to by p;
1. if(a<b or a=.b) then {/*SHIFT*/
push b onto stack;
advance p to next input symbol;
}
2. else if(a>b) then /*REDUCE*/
repeat pop stack
until(top of stack terminal is related by < to terminal most recently
popped);
3. else error(); /*ERROR*/
}
}

65
row=k;}
if((stack[top]=='$')&&(ip[i]=='$')){
printf("String is accepted\n");
break;}
else if((opt[col][row][0]=='<') ||(opt[col][row][0]=='='))
{ stack[++top]=opt[col][row][0];
stack[++top]=ip[i];
printf("Shift %c",ip[i]);
i++;}
else{
if(opt[col][row][0]=='>')
{
while(stack[top]!='<'){--top;}
top=top-1;
printf("Reduce");
}
else
{
printf("\nString is not accepted");
break;}}
printf("\n");
for(k=0;k<=top;k++)
{
printf("%c",stack[k]);
}
printf("\t\t\t");
for(k=i;k<strlen(ip);k++){
printf("%c",ip[k]);
}
printf("\t\t\t");
}}
OUTPUT:

66
RESULT: Program to develop an operator precedence parser for a given language
was successfully implemented.

67
PROGRAM: /*First and follow of a grammar*/
#include <stdio.h>
#include <string.h>
int n;
char prods[50][50];
char firsts[26][50];
int is_first_done[26];
char follows[26][50];
int is_follow_done[26];
int isTerminal(char c)
{
if (c < 65 || c > 90)
return 1;
return 0;
}
void first(char nonterm)
{
int index = 0;
char curr_firsts[50];
for (int i = 0; i < n; i++)
{
if (prods[i][0] == nonterm)
{
int curr_prod_index = 2;
int flag = 0;
while (prods[i][curr_prod_index] != '\0' && flag == 0)
{
flag = 1;
if (isTerminal(prods[i][curr_prod_index]))
{
curr_firsts[index] = prods[i][2];
index++;
break;
}
if (!is_first_done[prods[i][curr_prod_index] - 65])
first(prods[i][curr_prod_index]);
int in = 0;
while (firsts[prods[i][curr_prod_index] - 65][in] != '\0')
{
curr_firsts[index] = firsts[prods[i][curr_prod_index] - 65][in];
if (firsts[prods[i][curr_prod_index] - 65][in] == 'e')
{
curr_prod_index++;
flag = 0;
}
index++;
in++;
}
}}

68
EXPERIMENT - 12

Simulation of First and Follow of a Grammar

AIM: To develop a program to simulate first and follow of any given grammar.

ALGORITHM:

First():-

if x is a terminal, then FIRST(x) = {‘x’}


if x→epsilon is a production rule, then add epsilon to FIRST(x)
if x→Y1Y2Y3…Yn is a production,
FIRST(x) = FIRST(Y1)
if FIRST(Y1) contains epsilon then FIRST(x) = {FIRST(Y1)-epsilon} U {FIRST(Y2)}
if FIRST(Yi) contains epsilon for all i=1 to n, then add epsilon to FIRST(x).

Follow():-

FOLLOW(S)={$} // where S is non-terminal


if a→pBq is a production, where p,B and q are any grammar symbols;
then everything in FIRST(q) except epsilon is in FOLLOW(B)
if A→pB is a production, then everything in FOLLOW(A) is in FOLLOW(B).
if A→pBq is a production and FIRST(q) contains epsilon,
then FOLLOW(B) contains {FIRST(q)-epsilon} U FOLLOW(A);

69
}
curr_firsts[index] = '\0';
index++;
strcpy(firsts[nonterm - 65], curr_firsts);
is_first_done[nonterm - 65] = 1;
}
void follow(char nonterm)
{
int index = 0;
char curr_follows[50];
if (nonterm == prods[0][0])
{
curr_follows[index] = '$';
index++;
}
for (int j = 0; j < n; j++)
{
int k = 2;
int include_lhs_flag;
while (prods[j][k] != '\0')
{
include_lhs_flag = 0;
if (prods[j][k] == nonterm)
{
if (prods[j][k + 1] != '\0')
{
if (isTerminal(prods[j][k + 1]))
{
curr_follows[index] = prods[j][k + 1];
index++;
break;
}
int in = 0;
while (firsts[prods[j][k + 1] - 65][in] != '\0')
{
if (firsts[prods[j][k + 1] - 65][in] == 'e')
{
include_lhs_flag = 1;
in++;
continue;
}
int temp_flag = 0;
for (int z = 0; z < index; z++)
if (firsts[prods[j][k + 1] - 65][in] == curr_follows[z])
{
temp_flag = 1;
in++;
break;
}
if (temp_flag)

70
71
continue;
curr_follows[index] = firsts[prods[j][k + 1] - 65][in];
index++;
in++;
}
}
if (prods[j][k + 1] == '\0' || include_lhs_flag == 1)
{
if (prods[j][0] != nonterm)
{
if (!is_follow_done[prods[j][0] - 65])
follow(prods[j][0]);
int x = 0;
while (follows[prods[j][0] - 65][x] != '\0')
{
int temp_flag = 0;
for (int z = 0; z < index; z++)
if (follows[prods[j][0] - 65][x] == curr_follows[z])
{
temp_flag = 1;
x++;
break;
}
if (temp_flag)
continue;
curr_follows[index] = follows[prods[j][0] - 65][x];
index++;
x++;
}
}
}
}
k++;
}
}
curr_follows[index] = '\0';
index++;
strcpy(follows[nonterm - 65], curr_follows);
is_follow_done[nonterm - 65] = 1;
}
int main()
{
printf("Enter the number of productions: ");
scanf("%d", &n);
printf("Enter the productions: \n");
for (int i = 0; i < n; i++)
scanf("%s", prods[i]);
for (int i = 0; i < 26; i++)
is_first_done[i] = 0;

72
73
for (int i = 0; i < n; i++)
if (is_first_done[prods[i][0] - 65] == 0)
first(prods[i][0]);
for (int i = 0; i < n; i++)
if (is_follow_done[prods[i][0] - 65] == 0)
follow(prods[i][0]);
printf("Firsts:\n");
for (int i = 0; i < 26; i++)
if (is_first_done[i])
printf("%c : %s\n", i + 65, firsts[i]);
printf("Follows:\n");
for (int i = 0; i < 26; i++)
if (is_follow_done[i])
printf("%c : %s\n", i + 65, follows[i]);
}
OUTPUT:

74
RESULT: Program to simulate first and follow of a grammar was successfully
implemented.

75
PROGRAM: /*Recursive descent parser*/
#include <stdio.h>
char inp[100];
int len = 0;
int curr = 0;
int E();
int Z();
int main()
{
printf("Enter input:\n");
scanf("%s", inp);
while (inp[len] != '\0')
len++;
int res = E();
if (res == 1 && curr == len)
printf("Input has been accepted.\n");
else
printf("Input has been rejected.\n");
}
int E()
{
int result;
if (inp[curr] == 'i')
{
curr++;
result = Z();
if (result == 1)
return 1;
else
return -1;
}
return -1;
}
int Z()
{
int result;
if (inp[curr] == '+' && inp[curr + 1] == 'i')
{
curr += 2;
result = Z();
if (result == 1)
return 1;
}
return 1;
}

76
EXPERIMENT - 13

Recursive Descent Parser

AIM: To construct a recursive descent parser for an expression.

ALGORITHM:

Step 0: Start the program


Step 1: Define the context free grammar for expressions, including terminals and
non-terminal symbols and production rules.
Step 2: For each non terminal symbol in grammar, create a corresponding function
that implements production rule.
Step 3: Implement a tokenizer or lexical analyser to break input expression into
tokens.
Step 4: Create a main parsing function that initialises the parsing process.
Step 5: For each non terminal in the grammar, create a parsing function. These
functions should examine current token and choose appropriate production rule to
apply, call parsing functions for non-terminals or terminals that appear in
production rule.
Step 6: In each parsing function, consume tokens as they are matched by
production rules.
Step 7: Stop the program.

77
OUTPUT:

78
RESULT: Program to construct recursive descent parser for a grammar was
successfully implemented.

79
PROGRAM: /*Shift reduce parser*/
#include <stdio.h>
#include <string.h>
char inp[100];
int len;
char stack[100];
int top = 0;
void print_details(int ind, char *action)
{
printf("$");
for (int i = 0; i <= top; i++)
printf("%c", stack[i]);
printf("\t\t");
for (int i = ind; i < len; i++)
printf("%c", inp[i]);
printf("$\t\t%s\n", action);
}
void check_for_reduce(int i)
{
int flag = 1;
while (flag)
{
flag = 0;
if (stack[top - 2] == 'S' && stack[top - 1] == '+' && stack[top] == 'S')
{
print_details(i + 1, "REDUCE");
stack[top - 2] = 'S';
top = top - 2;
flag = 1;
}
else if (stack[top - 2] == 'S' && stack[top - 1] == '-' && stack[top] == 'S')
{
print_details(i + 1, "REDUCE");
stack[top - 2] = 'S';
top = top - 2;
flag = 1;
}
else if (stack[top - 2] == '(' && stack[top - 1] == 'S' && stack[top] == ')')
{
print_details(i + 1, "REDUCE");
stack[top - 2] = 'S';
top = top - 2;
flag = 1;
}
else if (stack[top] == 'i')
{
print_details(i + 1, "REDUCE");
stack[top] = 'S';

80
EXPERIMENT - 14

Shift Reduce Parser

AIM: To construct a shift reduce parser for a given language.

ALGORITHM:

Step 0: Start the program


Step 1: Define context free grammar for given language, including terminals, non-
terminals and production rules.
Step 2: Construct a parsing table that maps parsing states and lookahead tokens to
parsing actions or error handling.
Step 3: Initialise a stack to represent parser’s state and an input buffer with
sequence of tokens to be parsed.
Step 4: Start with an initial parsing state.
4.1:- Read current token from input buffer.
4.2:- Lookup the current state at top of stack and current token in parsing
table. Determine parsing action based on table entry.
4.3:- Repeat steps 4.1 & 4.2 until one of condition is met. If stack contains
only start symbol and input buffer is empty, input is accepted.
Step 5: Display stack implementation table.
Step 6: Stop the program

81
flag = 1;
}
}
}
int main()
{
printf("Enter input:\n");
scanf("%s", inp);
len = strlen(inp);
printf("Stack\t\tInput\t\tAction\n");
for (int i = 0; i < len; i++)
{
print_details(i, "SHIFT");
stack[top] = inp[i];
check_for_reduce(i);
top++;
}
top--;
if (top == 0 && stack[0] == 'S')
printf("Accepted.\n");
else
printf("Rejected.\n");
}
OUTPUT:

82
RESULT: Program to construct shift reduce parser for a given language was
successfully implemented.

83

You might also like