-1

This program is to find the epsilon closure of all states of an NFA. I have used the stack to get this done.The program gives the right output when I compiled it using gcc and ran it Windows 10(Command Prompt). But when I compiled with the same compiler and ran it in Linux it results in segmentation fault. I have used any dynamic memory allocation for that matter.

I tried to debug using gdb but not able to find the problem. Detected a segmentation fault after a printf("\n") when displaying the transitions matrix. It would be very helpful for someone could find the fault. Thanks in advance.

The input is read from a file : nfa.txt.

//states
q0 q1 q2
//input_symbols 
0 1
//start_state       
q0
//final_state       
q2      
//transitions of the form : intial_state  input  final_state
q0 0 q0     
q0 e q1
q1 1 q1     
q1 e q2
q2 2 q2

The output is as follows:

232 is to represent null transition(Φ) and -1 for ε.

States:
q0
q1
q2
Transitions read
232  0    1    2    -1
0    0    232  232   1
1    232  1    232   2
2    232  232  2     232

e-closure(0) : 0 1 2
e-closure(1) : 1 2
e-closure(2) : 2

Please bear with me because it's a fairly long program.

#include <stdio.h>     
#include <string.h>     //REMEMBER ME WHILE I'M GONE 
#include <errno.h>
#include <stdlib.h>

FILE *file;
int  numberOfStates = 0;
int  flag = 0;
int  states[20];

int  j = 0;
int  i = 0;
int  k = 0;

char a[20];

int  transitions[4][5];
int  visited[10];

int  MAXSIZE = 8;       
int  stack[8];     
int  top = -1;            

int isempty()
{
   if(top == -1)
      return 1;
   else
      return 0;
}

int isfull()
{
   if(top == MAXSIZE)
      return 1;
   else
      return 0;
}

int pop() 
{
   int data;

   if(!isempty()) {
      data = stack[top];
      top = top - 1;   
      return data;
   }
   else
         printf("Could not retrieve data, Stack is empty.\n");
 }


int push(int data) {

   if(!isfull()) {
      top = top + 1;   
      stack[top] = data;
   }
   else 
      printf("Could not insert data, Stack is full.\n");
}

int IsVisited(int edge)
{
    for(int i = 0; i < 10; i++)
        if(visited[edge] == 1)
            return 1;

    return 0;
}

void epsilon_closure(int state)
{
    int  e_closure[10];


    for(int i = 0; i < 10; i++ )
    {   e_closure[i] = -1;
        visited[i] = 0;
    }

    push(state);
    visited[state] = 1;

    while(top != -1)
    {
        int u = pop();

        j = 1;
        while(j < 5)
        {
            //if there is an epsilon transition from the state 'u' to 'v'
            if(transitions[j][0] == u && transitions[j][4] != 232) //ASCII of Φ = 232
            {
                if(! IsVisited(transitions[j][4]))
                {
                    visited[transitions[j][4]] = 1;
                    push(transitions[j][4]);
                }

            }
            j++;
        }
    }

    j = 0;
    for(int edge = 0; edge < 10; edge++)
    {
        if(visited[edge] == 1)
            e_closure[j++] = edge;
    }
    printf("e-closure(%d) : ",state);
    for (i = 0; e_closure[i] != -1; ++i)
        printf("%d ", e_closure[i]);
    printf("\n");
} 

int main()
{
    file = fopen("nfa.txt","r");

    if (file == NULL) {
        perror("fopen");
        return -1;
    }


    //Reading the states 
    while(!feof(file))
    {
        fscanf(file,"%s",a);
        if(strcmp("//states",a) == 0)
            flag = 1;
        else if(strcmp("//input_symbols",a) == 0)
            break;
        if (flag == 1 && a[0] != '/')
        {
            states[i++] = a[1] - '0';

        }
        numberOfStates = i; 
    }

    //Display the states of the e-NFA
    printf("\nStates : \n");
    for(i = 0; i < numberOfStates; i++ )
    {   
        printf("q%d\n",states[i]);
    }

    i = 1;
    flag = 0;
    //Reading the transition table

    for(int i = 0; i < 4; i++){
        for(int j = 0; j < 5; j++)
        {
            transitions[i][j] = 232;
        }

    }   
    while(!feof(file))
    {
        fgets(a,100,file);
        if(a[0] == '/')
        {   
            flag = 1;
        }
        if(flag == 1 && a[0] != '/')
        {   
            j = 0;
            //found a way to store the transition table in a matrix
            if(a[3] == 'e')
                transitions[(a[1] - '0') + 1][4] = a[6] - '0';

            else    
                transitions[(a[1] - '0') + 1][(a[3] - '0') + 1] = a[6] - '0';
            if(a[3] != 'e')
                transitions[0][a[3] - '0' + 1] = a[3] - '0';        //input
            else
                transitions[0][4] = -1;     // epsilon input
            transitions[(a[1] - '0') + 1][0] = a[1] - '0'; //initial state

        }
    }
    printf("\nTransitions read\n");
    for(int i = 0; i < 4; i++){
        for(int j = 0; j < 5; j++)
        {
            printf("%d\t",transitions[i][j]);
        }
        printf("\n"); //detected segmentation fault here
    }   

    //Calling e-closure for all the states  
    for(k = 0; k < numberOfStates; k++)
    {
        epsilon_closure(states[k]);
    }

    return 0;
}
Akhil V
  • 53
  • 10
  • 4
    Debug it. And make sure your indices are not going out of the bounds of the arrays. This seem to be the only possible cause for segfault here. – Eugene Sh. Jul 04 '18 at 17:29
  • 3
    Ah... and this: `while(!feof(file))`. [Why is “while ( !feof (file) )” always wrong?](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) – Eugene Sh. Jul 04 '18 at 17:31
  • 4
    "*Please bear with me because it's a fairly long program.*" No. Please post a [mcve] instead. – melpomene Jul 04 '18 at 17:33
  • 2
    Your mixture of global `i` and several loop-local `i` isn't exactly helping bring clarity to this, btw. Likewise for `j`. – WhozCraig Jul 04 '18 at 17:35
  • Compile with `-fsanitize=undefined -Wall -Werror -pedantic-errors` flags – n. m. could be an AI Jul 04 '18 at 17:54
  • 1
    when compiling, always enable the warnings, then fix those warnings. (for `gcc`, at a minimum use: `-Wall -Wextra -Wconversion -pedantic -std=gnu11` ) – user3629249 Jul 04 '18 at 22:01
  • 1
    regarding: `fscanf(file,"%s",a);` 1) use this function call in the `while()` statement and forget about `feof()` as it does not do what you seem to think it does. 2) when calling any of the `scanf()` family of functions a) always check the returned value (not the parameter values) to assure the operation was successful. b) when using the format specifiers: `%s` and `%[...]` always include a MAX CHARACTERS modifier that is one less than the length of the input buffer to avoid buffer overflows and the resulting undefined behavior – user3629249 Jul 04 '18 at 22:08
  • Okay...I will look it up. Thank you – Akhil V Jul 05 '18 at 10:05

1 Answers1

3

There is a bug here:

int push(int data) {

   if(!isfull()) {
      top = top + 1;   
      stack[top] = data;  
   }
   else 
      printf("Could not insert data, Stack is full.\n");  
}

If top == MAXSIZE-1, isfull() will return false, then you increment top to MAXSIZE and assign stack[MAXSIZE] what is out of bounds and invokes UB. Not having checked the complete source code, I could imagine that incrementing top after assigning would be correct or you have to change isfull() to return true if top >= MAXSIZE-1

Ingo Leonhardt
  • 9,435
  • 2
  • 24
  • 33
  • 2
    Worth noting, this function also declares a `int` return type, but makes no attempts whatsoever to fulfill that. A similar problem happens in one of the control paths of `pop`, which is considerably more disastrous, as its return result is actually used by the caller. – WhozCraig Jul 04 '18 at 17:45
  • Thanks for pointing it out....The program now works for the input as expected.But push or pop wasn't the problem. Appreciate your help. – Akhil V Jul 05 '18 at 10:01