# Computing first and following sets (compiler design)

I have made this program to find out the first and following sets of the productions:

E->TA
A->+TA
A->0
T->FB
B->*FB
B->0
F->(E)
F->#


Here epsilon(NULL) is taken as 0:

     #include<stdio.h>
#include<ctype.h>
char a[8][8];

struct firTab
{
int n;
char firT[5];
};
struct folTab
{
int n;
char folT[5];
};
struct folTab follow[5];
struct firTab first[5];
int col;
void findFirst(char,char);
void findFollow(char,char);
void folTabOperation(char,char);
void firTabOperation(char,char);
void main()
{
int i,j,c=0,cnt=0;
char ip;
char b[8];
printf("\nFIRST AND FOLLOW SET \n\nenter 8 productions in format A->B+T\n");
for(i=0;i<8;i++)
{
scanf("%s",&a[i]);
}
for(i=0;i<8;i++)
{   c=0;
for(j=0;j<i+1;j++)
{
if(a[i][0] == b[j])
{
c=1;
break;
}
}
if(c !=1)
{
b[cnt] = a[i][0];
cnt++;
}

}
printf("\n");

for(i=0;i<cnt;i++)
{   col=1;
first[i].firT[0] = b[i];
first[i].n=0;
findFirst(b[i],i);
}
for(i=0;i<cnt;i++)
{
col=1;
follow[i].folT[0] = b[i];
follow[i].n=0;
findFollow(b[i],i);
}

printf("\n");
for(i=0;i<cnt;i++)
{
for(j=0;j<=first[i].n;j++)
{
if(j==0)
{
printf("First(%c) : {",first[i].firT[j]);
}
else
{
printf(" %c",first[i].firT[j]);
}
}
printf(" } ");
printf("\n");
}
printf("\n");
for(i=0;i<cnt;i++)
{
for(j=0;j<=follow[i].n;j++)
{
if(j==0)
{
printf("Follow(%c) : {",follow[i].folT[j]);
}
else
{
printf(" %c",follow[i].folT[j]);
}
}
printf(" } ");

printf("\n");
}

}
void findFirst(char ip,char pos)
{
int i;
for(i=0;i<8;i++)
{
if(ip == a[i][0])
{
if(isupper(a[i][3]))
{
findFirst(a[i][3],pos);
}
else
{

first[pos].firT[col]=a[i][3];
first[pos].n++;
col++;
}
}
}
}
void findFollow(char ip,char row)
{   int i,j;
if(row==0 && col==1)
{
follow[row].folT[col]= '\$';
col++;
follow[row].n++;
}
for(i=0;i<8;i++)
{
for(j=3;j<7;j++)
{
if(a[i][j] == ip)
{
if(a[i][j+1] == '\0')
{
if(a[i][j] != a[i][0])
{
folTabOperation(a[i][0],row);
}
}
else if(isupper(a[i][j+1]))
{   if(a[i][j+1] != a[i][0])
{
firTabOperation(a[i][j+1],row);

}
}
else
{
follow[row].folT[col] = a[i][j+1];
col++;
follow[row].n++;

}
}
}
}
}
void folTabOperation(char ip,char row)
{   int i,j;
for(i=0;i<5;i++)
{
if(ip == follow[i].folT[0])
{
for(j=1;j<=follow[i].n;j++)
{
follow[row].folT[col] = follow[i].folT[j];
col++;
follow[row].n++;
}
}
}
}
void firTabOperation(char ip,char row)
{
int i,j;
for(i=0;i<5;i++)
{
if(ip == first[i].firT[0])
{
for(j=1;j<=first[i].n;j++)
{
if(first[i].firT[j] != '0')
{
follow[row].folT[col] = first[i].firT[j];
follow[row].n++;
col++;
}
else
{
folTabOperation(ip,row);
}
}
}
}

}

/*
input productions

E->TA
A->+TA
A->0
T->FB
B->*FB
B->0
F->(E)
F->#
*/


To start at the top, your two structures firTab and folTab could probably be combined. And given a name than means something.

Your embedded constants 8 and 5 throughout should be replaced by #defined constants to make changing them easier.

You would also do well to restructure main to extract parts that are are logically complete and separate into functions. And place main last to avoid the need for prototypes. Every other function can be static.

On compiling the code, every array subscript gives a warning: array subscript is of type 'char'. char subscripts are generally best avoided because char can be signed or unsigned according to the implementation.

On the details of the code, I can't claim to have followed it through. But looking at the first 30 lines of main...

Your first action is to obtain the 8 rules you expect. The code would be better is it did not assume a fixed number (8) of rules or a fixed number (5) of first/follow.

The first line of main defines some variables, but they would be better defined at the point of first use (where possible) or one per line. c and cnt are not sufficiently meaningful.

You then define array b[8], again with an embedded constant and an assumption of the number of input lines. b is left uninitialized and hence will contain junk (whatever is at that stack location).

You then read the 8 input lines into a[][] without any checks that they fit in the array entries. Then follows a loop that reads through these eight lines and puts the first character of each line into array b without duplication. There are numerous issues with these lines, the main one being that it is such a convoluted way of doing this. Here are some more:

• array a is badly named
• array b is badly named and is used before being initialized. The loop only works by chance.
• flag c is badly named. It is a boolean indicating that b already holds a particular letter.
• variables i and j should be declared as part of their loops:

 for (int i = 0; i < 8; i++)

• you should add some spaces to make expressions more readable, for example after if and for, after ;, around = and + etc

• your layout is inconsistent (eg placement of c=0; compared to other opening braces)

This whole loop should have been combined with the input loop so that each time you read a new line into a, you checked its first character to see whether it was in b and if not added it. If we rename b as letters and make it a nul terminated string, you can check this easily with

    if (!strchr(letters, line[0])) {
// append new letter
}


where line is the new input line.

I've only covered 50 lines of the code, but I think there is enough there for you to think about. It looks as if you have disappeared, so I'm not sure it is worth digging any further. If you reappear, I might :-)