/**
 * Looks for a loop. To do that, we only follow transitions that can match E.
 * Every time we follow such a transition, we add it to the 'transitions' list.
 * This list is used to print the E loop if we find any. The function returns
 * 1 if a loop is found; 0 otherwise.
 */
static int find_an_E_loop(int* mark,int current_state,int graph,GrfCheckInfo* chk,
		struct list_pointer* transitions) {
if (mark[current_state]==1) {
	/* The state has been visited, nothing to do */
	return 0;
}
if (mark[current_state]==2) {
	/* The state is being visited, we have a loop */
	error("E loop in graph %S, made of the following tags:\n",chk->fst2->graph_names[graph]);
	print_reversed_list(transitions,chk->fst2,current_state,0);
	return 1;
}
/* We start visiting the state */
mark[current_state]=2;
SingleGraphState s=chk->condition_graphs[graph]->states[current_state];
Transition* t=s->outgoing_transitions;
while (t!=NULL) {
	if (transition_can_match_E(t->tag_number,chk)) {
		struct list_pointer* new_head=new_list_pointer(t,transitions);
		int res=find_an_E_loop(mark,t->state_number,graph,chk,new_head);
		new_head->next=NULL;
		free_list_pointer(new_head);
		if (res==1) {
			return 1;
		}
	}
	t=t->next;
}
/* The state has been fully visited */
mark[current_state]=1;
return 0;
}
Exemple #2
0
/**
 * Prints the graph call sequence that leads to the graph #n.
 */
void print_reversed_list(const struct list_int* l,int n,unichar**  graph_names,U_FILE* ferr) {
if (l->n==n) {
   error("ERROR: %S",graph_names[l->n]);
   if (ferr != NULL)
       u_fprintf(ferr,"ERROR: %S",graph_names[l->n]);
   return;
}
print_reversed_list(l->next,n,graph_names,ferr);
error(" calls %S that",graph_names[l->n]);
if (ferr != NULL)
  u_fprintf(ferr," calls %S that",graph_names[l->n]);
}
Exemple #3
0
/**
 * Returns 1 and prints an error message if a recursion is found in graph #n;
 * returns 0 otherwise.
 */
int look_for_recursion(int n,struct list_int* l,Fst2* fst2,int* graphs_matching_E,U_FILE*ferr) {
if (is_in_list(n,l)) {
   /* If we find a graph that has already been visited */
   print_reversed_list(l,n,fst2->graph_names,ferr);
   error(" recalls the graph %S\n",fst2->graph_names[n]);
   if (ferr != NULL)
      u_fprintf(ferr," recalls the graph %S\n",fst2->graph_names[n]);
   return 1;
}
l=new_list_int(n,l);
int ret=explore_state(fst2->initial_states[n],l,fst2,graphs_matching_E,ferr);
delete_head(&l);
return ret;
}
static int find_a_left_recursion(int* mark_graph,int* mark_state,int current_state,int graph,
									GrfCheckInfo* chk,struct list_pointer* transitions) {
if (mark_state[current_state]==1) {
	/* The state has been visited, nothing to do */
	return 0;
}
if (mark_state[current_state]==2) {
	/* The state is being visited, we have a loop, but it should have been detected before */
	error("E loop in graph %S, made of the following tags:\n",chk->fst2->graph_names[graph]);
	print_reversed_list(transitions,chk->fst2,current_state,0);
	return 1;
}
/* We start visiting the state */
mark_state[current_state]=2;
SingleGraphState s=chk->condition_graphs[graph]->states[current_state];
Transition* t=s->outgoing_transitions;
while (t!=NULL) {
	if (t->tag_number<0) {
		/* As we look for left recursions, we always test recursively
		 * graph calls, regardless the fact that they may match E
		 */
		struct list_pointer* new_head=new_list_pointer(t,transitions);
		int res=is_left_recursion(chk,-(t->tag_number),mark_graph,new_head);
		new_head->next=NULL;
		free_list_pointer(new_head);
		if (res==1) {
			return 1;
		}
	}
	if (transition_can_match_E(t->tag_number,chk)) {
		struct list_pointer* new_head=new_list_pointer(t,transitions);
		int res=find_a_left_recursion(mark_graph,mark_state,t->state_number,graph,chk,new_head);
		new_head->next=NULL;
		free_list_pointer(new_head);
		if (res==1) {
			return 1;
		}
	}
	t=t->next;
}
/* The state has been fully visited */
mark_state[current_state]=1;
return 0;
}
/**
 * By convention, if stop is >=0 it represents a state number, and if <0, it represents
 * a graph call. We use it as a stop condition.
 */
static void print_reversed_list(struct list_pointer* list,Fst2* fst2,int stop,int depth) {
if (list==NULL) {
	return;
}
Transition* t=(Transition*)list->pointer;
if (depth!=0) {
	if ((stop>=0 && t->state_number==stop) || (stop<0 && t->tag_number==stop)) {
		return;
	}
}
print_reversed_list(list->next,fst2,stop,depth+1);
if (t->tag_number<0) {
	error("   :%S",fst2->graph_names[-t->tag_number]);
} else {
	error("   %S",fst2->tags[t->tag_number]->input);
	if (fst2->tags[t->tag_number]->output!=NULL && fst2->tags[t->tag_number]->output[0]!='\0') {
		error("/%S",fst2->tags[t->tag_number]->output);
	}
}
error("\n");
}
/**
 * Returns 0 if no left recursion is found. Otherwise, prints a message that
 * describes the loop and returns 1.
 */
static int is_left_recursion(GrfCheckInfo* chk,int graph,int* mark_graph,struct list_pointer* transitions) {
if (mark_graph[graph]==1) {
	/* The graph has already been tested for left recursions */
	return 0;
}
if (mark_graph[graph]==2) {
	/* We found a left recursion */
	error("Left recursion found in graph %S, made of the following tags:\n",chk->fst2->graph_names[graph]);
	print_reversed_list(transitions,chk->fst2,-graph,0);
	return 1;
}

mark_graph[graph]=2;
SingleGraph g=chk->condition_graphs[graph];
/* 0 means that the state has not been visited at all
 * 1 means that the state has already been fully visited
 * 2 means that the state is being visited now, so finding such
 *   a state means that there is an E loop
 */
int* mark_state=(int*)calloc(g->number_of_states,sizeof(int));
int recursion=0;
int initial_state=get_initial_state(g);
if (initial_state==-2) {
	fatal_error("Internal error: several initial states in graph %S\n",chk->fst2->graph_names[graph]);
}
if (initial_state==-1) {
	/* If the graph could not be loaded, we just ignore */
	mark_graph[graph]=1;
	free(mark_state);
	return 0;
}
if (find_a_left_recursion(mark_graph,mark_state,initial_state,graph,chk,transitions)) {
	recursion=1;
}
free(mark_state);
mark_graph[graph]=1;
return recursion;
}