/**
 * This function optimizes a pattern of the form "eat".
 */
void optimize_token_pattern(int i,Fst2Tag* tag,Alphabet* alph,
               struct locate_parameters* p,Abstract_allocator prv_alloc) {
/* Whatever happens, this pattern will be turned into a token list */
tag[i]->type=TOKEN_LIST_TAG;
unichar* opt_token=tag[i]->pattern->inflected;
/* First, we check if this token pattern can recognize some tag tokens */
struct list_int* list=p->tag_token_list;
while (list!=NULL) {
   struct dela_entry* entry=tokenize_tag_token(p->tokens->value[list->n],1);
   if ((!is_bit_mask_set(tag[i]->control,RESPECT_CASE_TAG_BIT_MASK) && is_equal_or_uppercase(opt_token,entry->inflected,alph)) ||
       !u_strcmp(opt_token,entry->inflected)) {
      tag[i]->matching_tokens=sorted_insert(list->n,tag[i]->matching_tokens,prv_alloc);
   }
   free_dela_entry(entry);
   list=list->next;
}
/* Then, we look for normal tokens */
if (is_bit_mask_set(tag[i]->control,RESPECT_CASE_TAG_BIT_MASK)) {
   /* If no case variants are allowed, then we just have to insert the number
    * of the token, but only if this token in the text ones. */
   int token_number;
   if (-1!=(token_number=get_value_index(opt_token,p->tokens,DONT_INSERT))) {
      tag[i]->matching_tokens=sorted_insert(token_number,tag[i]->matching_tokens,prv_alloc);
   }
   return;
}
/* Here, we have to get all the case variants of the token. */
tag[i]->matching_tokens=destructive_sorted_merge(get_token_list_for_sequence(opt_token,alph,p->tokens,prv_alloc),tag[i]->matching_tokens,prv_alloc);
}
Example #2
0
/**
 * This function takes a condition, i.e. a list of graph numbers. Then, it
 * tests if all the corresponding graphs match <E>. In that case, it sets
 * '*matches_E' to E_IS_MATCHED.
 */
struct list_int* resolve_simple_condition(struct list_int* c,Fst2State* states,
                                    int* initial_states,int *modification,
                                    int *matches_E) {
struct list_int* tmp;
*matches_E=E_IS_MATCHED;
if (c==NULL) return NULL;
/* First, we try to solve the rest of the condition */
tmp=resolve_simple_condition(c->next,states,initial_states,modification,matches_E);
if ((*matches_E)==E_IS_NOT_MATCHED) {
   /* If at least one element of the rest of the condition does not
    * matches <E>, we can delete the current element (the rest has
    * already been freed). */
   free(c);
   (*modification)++;
   return NULL;
}
if ((*matches_E)==E_IS_MATCHED) {
   /* If all the elements of the rest of the condition match <E> */
   c->next=tmp;
   if (is_bit_mask_set(states[initial_states[c->n]]->control,UNCONDITIONAL_E_MATCH)) {
      /* If the current one also matches <E>, then we can return */
      return c;
   }
   if (is_bit_mask_set(states[initial_states[c->n]]->control,CONDITIONAL_E_MATCH) && 
       !is_bit_mask_set(states[initial_states[c->n]]->control,DOES_NOT_MATCH_E)) {
      /* If we don't know if the current element matches <E> or not */
      *matches_E=DOES_NOT_KNOW_IF_E_IS_MATCHED;
      return c;
   }
   /* If the current element does not match <E>, we can free the rest of the condition */
   free_list_int(c);
   *matches_E=E_IS_NOT_MATCHED;
   (*modification)++;
   return NULL;
}
/* If we don't know if the rest of the condition match <E> */
c->next=tmp;
if (is_bit_mask_set(states[initial_states[c->n]]->control,UNCONDITIONAL_E_MATCH)) {
   /* If the current element matches <E>, we still cannot decide */
   *matches_E=DOES_NOT_KNOW_IF_E_IS_MATCHED;
   return c;
}
if (is_bit_mask_set(states[initial_states[c->n]]->control,DOES_NOT_MATCH_E)) {
   /* If the current element does not matches <E>, the condition is not verified */
   free_list_int(c);
   *matches_E=E_IS_NOT_MATCHED;
   (*modification)++;
   return NULL;
}
/* If we still don't know, we do nothing */
*matches_E=DOES_NOT_KNOW_IF_E_IS_MATCHED;
return c;
}
Example #3
0
/**
 * Explores the transitions that outgo from the given state.
 * Returns 1 if a recursion is found; 0 otherwise.
 */
int explore_state(int state_number,struct list_int* l,Fst2* fst2,int* graphs_matching_E,U_FILE*ferr) {
Fst2State s=fst2->states[state_number];
int ret=0;
if (s==NULL) return 0;
if (is_bit_mask_set(s->control,TMP_LOOP_MARK|VISITED_MARK)) {
   /* If this state has already been processed */
   return 0;
}
set_bit_mask(&(s->control),TMP_LOOP_MARK|VISITED_MARK);
Transition* list=s->transitions;
while (list!=NULL) {
   if (list->tag_number<0) {
      /* If we have a subgraph call */
      if (look_for_recursion(-(list->tag_number),l,fst2,graphs_matching_E,ferr)) {
         /* If there is a recursion */
         return 1;
      }
      if (graphs_matching_E[-list->tag_number] && explore_state(list->state_number,l,fst2,graphs_matching_E,ferr)) {
         /* If the graph matches <E> */
         return 1;
      }
   } else if (fst2->tags[list->tag_number]->control==1) {
      /* If we have a transition that can match <E> */
      if (explore_state(list->state_number,l,fst2,graphs_matching_E,ferr)) {
         return 1;
      }
   }
   list=list->next;
}
unset_bit_mask(&(s->control),TMP_LOOP_MARK);
return ret;
}
Example #4
0
/**
 * Returns 1 if the given state has already been visited; 0 otherwise.
 */
int look_for_E_loop_in_state(int state_number,Fst2* fst2,int* graphs_matching_E) {
Transition* l;
Fst2State e=fst2->states[state_number];
if (is_bit_mask_set(e->control,TMP_LOOP_MARK)) {
   /* If we have already visited this state */
   unset_bit_mask(&(e->control),TMP_LOOP_MARK);
   return 1;
}
set_bit_mask(&(e->control),TMP_LOOP_MARK);
l=e->transitions;
while (l!=NULL) {
   if (l->tag_number<0) {
      /* If we have a graph call */
      if (graphs_matching_E[-l->tag_number]) {
         /* And if we can cross it because it matches <E> */
         if (look_for_E_loop_in_state(l->state_number,fst2,graphs_matching_E)) {
            /* And if we have reached the current state via an <E> loop */
            unset_bit_mask(&(e->control),TMP_LOOP_MARK);
            return 1;
         }
      }
   }
   else if (fst2->tags[l->tag_number]->control==1) {
      /* If we have a tag that can match <E> */
      if (look_for_E_loop_in_state(l->state_number,fst2,graphs_matching_E)) {
         /* And if we have reached the current state via an <E> loop */
         unset_bit_mask(&(e->control),TMP_LOOP_MARK);
         return 1;
      }
   }
  l=l->next;
}
unset_bit_mask(&(e->control),TMP_LOOP_MARK);
return 0;
}
Example #5
0
/**
 * This function looks for each graph if it can resolve a condition.
 * 
 * It returns a non zero value if some conditions have been resolved, 
 * even just one; 0 otherwise.
 */
int resolve_conditions(ConditionList* conditions,int n_graphs,
                       Fst2State* states,int* initial_states,U_FILE*ferr) {
int modification=0;
for (int i=1;i<n_graphs+1;i++) {
   if (!is_bit_mask_set(states[initial_states[i]]->control,
                        UNCONDITIONAL_E_MATCH|DOES_NOT_MATCH_E)) {
      /* If we don't already know the status of the current graph */
      if (!is_bit_mask_set(states[initial_states[i]]->control,CONDITIONAL_E_MATCH)) {
         /* If there is no conditionnal match, then we say that it does
          * not match <E> */
         set_bit_mask(&(states[initial_states[i]]->control),DOES_NOT_MATCH_E);
         modification++;
      } else {
         /* Otherwise, we try to solve the conditions of the graph */
         modification=modification+resolve_conditions_for_one_graph(i,conditions,states,initial_states,ferr);
      }
   }
}
return modification;
}
Example #6
0
/**
 * Cleans the control bytes of the fst2's states. If 'graphs_matching_E'
 * is not null, graphs_matching_E[i] is set to 1 if the graph #i matches <E>;
 * 0 otherwise.
 */
void clean_controls(Fst2* fst2,int* graphs_matching_E) {
int i;
if (graphs_matching_E!=NULL) {
   for (i=1;i<fst2->number_of_graphs+1;i++) {
      if (is_bit_mask_set(fst2->states[fst2->initial_states[i]]->control,UNCONDITIONAL_E_MATCH))
         graphs_matching_E[i]=1;
      else graphs_matching_E[i]=0;
   }
}
int ALL_MASKS=CONDITIONAL_E_MATCH|UNCONDITIONAL_E_MATCH|DOES_NOT_MATCH_E|TMP_LOOP_MARK|VISITED_MARK;
for (i=0;i<fst2->number_of_states;i++) {
   unset_bit_mask(&(fst2->states[i]->control),(unsigned char)ALL_MASKS);
}
}
/**
 * This function optimizes the given transition.
 */
static void optimize_transition(Variables* v,OutputVariables* output,Fst2* fst2,Transition* transition,
						OptimizedFst2State state,Fst2Tag* tags,Abstract_allocator prv_alloc) {
if (transition->tag_number<0) {
   /* If the transition is a graph call */
   add_graph_call(transition,&(state->graph_calls),prv_alloc);
   add_graph_call(transition,&(state->unoptimized_graph_calls),prv_alloc);
   return;
}
Fst2Tag tag=tags[transition->tag_number];
if (tag==NULL) {
   fatal_error("NULL transition tag in optimize_transition\n");
}
int negation=is_bit_mask_set(tag->control,NEGATION_TAG_BIT_MASK);
/* First, we look if there is a compound pattern associated to this tag */
if (tag->compound_pattern!=NO_COMPOUND_PATTERN) {
   add_pattern(tag->compound_pattern,transition,&(state->compound_patterns),negation,prv_alloc);
}
/* Then, we look the possible kind of transitions */
switch (tag->type) {
   case TOKEN_LIST_TAG: add_token_list(tag->matching_tokens,transition,&(state->token_list),&(state->number_of_tokens),prv_alloc);
                        return;
   case PATTERN_NUMBER_TAG: add_pattern(tag->pattern_number,transition,&(state->patterns),negation,prv_alloc);
                            return;
   case META_TAG: {
	   add_meta(tag->meta,transition,&(state->metas),negation,prv_alloc);
	   add_meta(tag->meta,transition,&(state->unoptimized_metas),negation,prv_alloc);
       return;
   }
   case BEGIN_VAR_TAG: {
	   add_input_variable(v,tag->variable,transition,&(state->input_variable_starts),prv_alloc);
	   add_input_variable(v,tag->variable,transition,&(state->unoptimized_input_variable_starts),prv_alloc);
       return;
   }
   case END_VAR_TAG: {
	   add_input_variable(v,tag->variable,transition,&(state->input_variable_ends),prv_alloc);
	   add_input_variable(v,tag->variable,transition,&(state->unoptimized_input_variable_ends),prv_alloc);
       return;
   }
   case BEGIN_OUTPUT_VAR_TAG: {
	   add_output_variable(output,tag->variable,transition,&(state->output_variable_starts),prv_alloc);
	   add_output_variable(output,tag->variable,transition,&(state->unoptimized_output_variable_starts),prv_alloc);
       return;
   }
   case END_OUTPUT_VAR_TAG: {
	   add_output_variable(output,tag->variable,transition,&(state->output_variable_ends),prv_alloc);
	   add_output_variable(output,tag->variable,transition,&(state->unoptimized_output_variable_ends),prv_alloc);
       return;
   }
   case BEGIN_POSITIVE_CONTEXT_TAG: add_positive_context(fst2,state,transition,prv_alloc); return;
   case BEGIN_NEGATIVE_CONTEXT_TAG: add_negative_context(fst2,state,transition,prv_alloc); return;
   case END_CONTEXT_TAG: add_end_context(state,transition,prv_alloc); return;
   case LEFT_CONTEXT_TAG: {
	   add_meta(META_LEFT_CONTEXT,transition,&(state->metas),0,prv_alloc);
	   add_meta(META_LEFT_CONTEXT,transition,&(state->unoptimized_metas),0,prv_alloc);
	   return;
   }
   case BEGIN_MORPHO_TAG: {
	   struct opt_meta* new_meta=add_meta(META_BEGIN_MORPHO,transition,&(state->metas),0,prv_alloc);
	   get_reachable_closing_morphological_mode(fst2,transition->state_number,&(new_meta->morphological_mode_ends),prv_alloc);
	   add_meta(META_BEGIN_MORPHO,transition,&(state->unoptimized_metas),0,prv_alloc);
	   return;
   }
   case END_MORPHO_TAG: {
	   add_meta(META_END_MORPHO,transition,&(state->metas),0,prv_alloc);
	   add_meta(META_END_MORPHO,transition,&(state->unoptimized_metas),0,prv_alloc);
	   return;
   }
   case TEXT_START_TAG: {
	   add_meta(META_TEXT_START,transition,&(state->metas),0,prv_alloc);
	   add_meta(META_TEXT_START,transition,&(state->unoptimized_metas),0,prv_alloc);
	   return;
   }
   case TEXT_END_TAG: {
	   add_meta(META_TEXT_END,transition,&(state->metas),0,prv_alloc);
	   add_meta(META_TEXT_END,transition,&(state->unoptimized_metas),0,prv_alloc);
	   return;
   }
   default: fatal_error("Unexpected transition tag type in optimize_transition\n");
}
}
Example #8
0
/**
 * This function analyses the inputs of all the tags of the given .fst2 in
 * order to determine their kind. 'tokens' contains all the text tokens.
 * After the execution of the function, 'number_of_patterns' will contain
 * the number of patterns found in the grammar, and 'is_DIC'/'is_CDIC'/'is_SDIC'/'is_TDIC'
 * will contain 1 if the tag 'DIC'/'CDIC'/'SDIC'/'TDIC' has been found. See
 * the comment below about the special case for '<!DIC>'.
 */
void process_tags(int *number_of_patterns,
                  struct string_hash* semantic_codes,
                  int *is_DIC,int *is_CDIC,
                  int *is_SDIC,struct locate_parameters* parameters,
                  Abstract_allocator prv_alloc) {
(*number_of_patterns)=0;
(*is_DIC)=0;
(*is_CDIC)=0;
(*is_SDIC)=0;
Fst2* fst2=parameters->fst2;
struct string_hash* tokens=parameters->tokens;
Fst2Tag* tag=fst2->tags;
/* We get the number of the SPACE token */
unichar t[2];
t[0]=' ';
t[1]='\0';
parameters->SPACE=get_value_index(t,tokens,DONT_INSERT);
/* Then, we test all the tags */
for (int i=0;i<fst2->number_of_tags;i++) {
   if (tag[i]->type!=UNDEFINED_TAG) {
      /* We don't need to process again things like variables and contexts
       * that have already been processed at the time of loading the fst2 */
      continue;
   }
   int length=u_strlen(tag[i]->input);
   if (!u_strcmp(tag[i]->input,"#")) {
      /* If we have a #, we must check if it is the meta one that
       * forbids space or the "#" token */
      if (is_bit_mask_set(tag[i]->control,RESPECT_CASE_TAG_BIT_MASK)) {
         /* If the case respect bit is set to 1, then we have the "#" token */
         tag[i]->type=PATTERN_TAG;
         tag[i]->pattern=build_token_pattern(tag[i]->input,prv_alloc);
      }
      else {
         /* If we have the meta # */
         tag[i]->type=META_TAG;
         tag[i]->meta=META_SHARP;
      }
   }
   else if (!u_strcmp(tag[i]->input,"<E>")) {
      /* If we have a transition tagged by the empty word epsilon */
      tag[i]->type=META_TAG;
      tag[i]->meta=META_EPSILON;
   }
   else {
      int token_number=get_value_index(tag[i]->input,tokens,DONT_INSERT);
      if (token_number!=-1) {
         /* If the input is an existing token */
         if (token_number==parameters->SPACE) {
            /* If it is a space */
            tag[i]->type=META_TAG;
            tag[i]->meta=META_SPACE;
         } else {
            /* If it is a normal token */
            tag[i]->type=PATTERN_TAG;
            tag[i]->pattern=build_token_pattern(tag[i]->input,prv_alloc);
         }
      }
      else {
         /* This input is not an existing token. Two cases can happen:
          * 1) metas like <!MOT> or patterns like <V:K>
          * 2) a word that is not in the text tokens */
         if (tag[i]->input[0]!='<' || tag[i]->input[length-1]!='>') {
            /* If we are in case 2, it may not be an error. For instance,
             * if the tag contains "foo" and if it is a tag that allows
             * case variations, we could match "FOO" if this token is in the
             * text. */
            tag[i]->type=PATTERN_TAG;
            tag[i]->pattern=build_token_pattern(tag[i]->input,prv_alloc);
         } else {
            /* If we have something of the form <...>, we must test first if it is
             * or not a negative tag like <!XXX> */
            int negative_tag=(tag[i]->input[1]=='!')?1:0;
            if (negative_tag) {
               set_bit_mask(&(tag[i]->control),NEGATION_TAG_BIT_MASK);
            }
            /* Then, we must test if we have or not a meta. To do that, we
             * extract the content without < > and ! if any.*/
            unichar* content=u_strdup(&(tag[i]->input[1+negative_tag]),length-2-negative_tag,prv_alloc);
            /* And we test all the possible metas */
            if (!u_strcmp(content,"MOT")) {
               tag[i]->type=META_TAG;
               tag[i]->meta=META_MOT;
            }
            else if (!u_strcmp(content,"DIC")) {
               tag[i]->type=META_TAG;
               tag[i]->meta=META_DIC;
               if (!negative_tag) {
                  /* We mark that the DIC tag has been found, but only
                   * if it is not the negative one (<!DIC>). We do this
                   * because things matched by <DIC> will be taken from
                   * the 'dlf' and 'dlc' files, whereas things matched by <!DIC>
                   * will be taken from the 'err' file. Such a trick is necessary
                   * if we don't want 'priori' to be taken as an unknown word since
                   * it is  part of the compound word 'a priori' */
                  (*is_DIC)=1;
               }
            }
            else if (!u_strcmp(content,"CDIC")) {
               tag[i]->type=META_TAG;
               tag[i]->meta=META_CDIC;
               (*is_CDIC)=1;
            }
            else if (!u_strcmp(content,"SDIC")) {
               tag[i]->type=META_TAG;
               tag[i]->meta=META_SDIC;
               (*is_SDIC)=1;
            }
            else if (!u_strcmp(content,"TDIC")) {
               tag[i]->type=META_TAG;
               tag[i]->meta=META_TDIC;
            }
            else if (!u_strcmp(content,"MAJ")) {
               tag[i]->type=META_TAG;
               tag[i]->meta=META_MAJ;
            }
            else if (!u_strcmp(content,"MIN")) {
               tag[i]->type=META_TAG;
               tag[i]->meta=META_MIN;
            }
            else if (!u_strcmp(content,"PRE")) {
               tag[i]->type=META_TAG;
               tag[i]->meta=META_PRE;
            }
            else if (!u_strcmp(content,"NB")) {
               tag[i]->type=META_TAG;
               tag[i]->meta=META_NB;
               if (negative_tag) {
                  error("Negative mark will be ignored in <!NB>\n");
               }
            }
            else if (!u_strcmp(content,"TOKEN")) {
               tag[i]->type=META_TAG;
               tag[i]->meta=META_TOKEN;
            }
            else {
               /* If we arrive here, we have not a meta but a pattern like
                * <be>, <be.V>, <V:K>, ... */
               tag[i]->type=PATTERN_TAG;
               tag[i]->pattern=build_pattern(content,semantic_codes,parameters->tilde_negation_operator,prv_alloc);
               if (tag[i]->pattern->type==CODE_PATTERN ||
                   tag[i]->pattern->type==LEMMA_AND_CODE_PATTERN ||
                   tag[i]->pattern->type==FULL_PATTERN || 
                   tag[i]->pattern->type==INFLECTED_AND_LEMMA_PATTERN) {
                  /* If the pattern we obtain contains grammatical/semantic
                   * codes, then we put it in the pattern tree and we note its number. */
                  tag[i]->pattern_number=add_pattern(number_of_patterns,tag[i]->pattern,parameters->pattern_tree_root,prv_alloc);
                  if (tag[i]->pattern->type==CODE_PATTERN) {
                     /* If we have a code pattern, then the tag will just need to contain
                      * the pattern number, BUT, WE DO NOT FREE THE PATTERN,
                      * since this pattern still could be used in morphological mode */
                     tag[i]->type=PATTERN_NUMBER_TAG;
                  }
               }
            }
            /* We don't forget to free the content */
            free_cb(content,prv_alloc);
         }
      }
   }
}
}
Example #9
0
/**
 * Returns 1 if the given .fst2 is OK to be used by the Locate program; 0 otherwise. 
 * Conditions are:
 * 
 * 1) no left recursion
 * 2) no loop that can recognize the empty word (<E> with an output or subgraph
 *    that can match the empty word).
 */
int OK_for_Locate_write_error(const char* name,char no_empty_graph_warning,U_FILE* ferr) {
ConditionList* conditions;
ConditionList* conditions_for_state;
int i,j;
int ERROR=0;
struct FST2_free_info fst2_free;
Fst2* fst2=load_abstract_fst2(name,1,&fst2_free);
if (fst2==NULL) {
	fatal_error("Cannot load graph %s\n",name);
}
u_printf("Recursion detection started\n");
int* graphs_matching_E=(int*)malloc(sizeof(int)*(fst2->number_of_graphs+1));
conditions=(ConditionList*)malloc(sizeof(ConditionList)*(fst2->number_of_graphs+1));
if (graphs_matching_E==NULL || conditions==NULL) {
   fatal_alloc_error("OK_for_Locate");
}
for (i=0;i<fst2->number_of_graphs+1;i++) {
   graphs_matching_E[i]=0;
   conditions[i]=NULL;
}
/* First, we look for tags that match the empty word <E> */
for (i=0;i<fst2->number_of_tags;i++) {
   check_epsilon_tag(fst2->tags[i]);
}
/* Then, we look for graphs that match <E> with or without conditions */
for (i=1;i<=fst2->number_of_graphs;i++) {
   conditions_for_state=(ConditionList*)malloc(sizeof(ConditionList)*fst2->number_of_states_per_graphs[i]);
   if (conditions_for_state==NULL) {
      fatal_alloc_error("OK_for_Locate");
   }
   for (j=0;j<fst2->number_of_states_per_graphs[i];j++) {
      conditions_for_state[j]=NULL;
   }
   graphs_matching_E[i]=graph_matches_E(fst2->initial_states[i],fst2->initial_states[i],
  								      fst2->states,fst2->tags,i,fst2->graph_names,
  								      conditions_for_state,&conditions[i]);
   /* If any, we remove the temp conditions */                        
   if (conditions[i]!=NULL) free_ConditionList(conditions[i]);
   /* And we way that the conditions for the current graph are its initial
    * state's ones. */
   conditions[i]=conditions_for_state[0];
   /* Then we perform cleaning */
   conditions_for_state[0]=NULL;
   for (j=1;j<fst2->number_of_states_per_graphs[i];j++) {
      free_ConditionList(conditions_for_state[j]);
   }
   free(conditions_for_state); 
}
/* Then, we use all our condition lists to determine which graphs match <E>.
 * We iterate until we find a fixed point. If some conditions remain non null
 * after this loop, it means that there are <E> dependencies between graphs
 * and this case will be dealt with later. */
u_printf("Resolving <E> conditions\n");
while (resolve_conditions(conditions,fst2->number_of_graphs,
							fst2->states,fst2->initial_states,ferr)) {}
if (is_bit_mask_set(fst2->states[fst2->initial_states[1]]->control,UNCONDITIONAL_E_MATCH)) {
   /* If the main graph matches <E> */
   if (!no_empty_graph_warning) {
       error("ERROR: the main graph %S recognizes <E>\n",fst2->graph_names[1]);
       if (ferr != NULL)
         u_fprintf(ferr,"ERROR: the main graph %S recognizes <E>\n",fst2->graph_names[1]);
   }
   ERROR=1;
}
if (!ERROR) {
   for (i=1;i<fst2->number_of_graphs+1;i++) {
      if (is_bit_mask_set(fst2->states[fst2->initial_states[i]]->control,UNCONDITIONAL_E_MATCH)) {
         /* If the graph matches <E> */
         if (!no_empty_graph_warning) {
             error("WARNING: the graph %S recognizes <E>\n",fst2->graph_names[i]);
             if (ferr != NULL)
                u_fprintf(ferr,"WARNING: the graph %S recognizes <E>\n",fst2->graph_names[i]);
         }
      }
   }
}
clean_controls(fst2,graphs_matching_E);
if (!ERROR) {
   u_printf("Looking for <E> loops\n");
   for (i=1;!ERROR && i<fst2->number_of_graphs+1;i++) {
      ERROR=look_for_E_loops(i,fst2,graphs_matching_E,ferr);
   }
}
clean_controls(fst2,NULL);
if (!ERROR) {
   u_printf("Looking for infinite recursions\n");
   for (i=1;!ERROR && i<fst2->number_of_graphs+1;i++) {
      ERROR=look_for_recursion(i,NULL,fst2,graphs_matching_E,ferr);
   }
}
for (i=1;i<fst2->number_of_graphs+1;i++) {
   free_ConditionList(conditions[i]);
}
free_abstract_Fst2(fst2,&fst2_free);
u_printf("Recursion detection completed\n");
free(conditions);
free(graphs_matching_E);
if (ERROR) return LEFT_RECURSION;
return NO_LEFT_RECURSION;
}
Example #10
0
/**
 * Returns 1 if we can match <E> from the current state, with or without
 * conditions; 0 otherwise.
 */
int graph_matches_E(int initial_state,int current_state,const Fst2State* states,Fst2Tag* tags,
                      int current_graph,unichar** graph_names,
                      ConditionList conditions_for_states[],
                      ConditionList *graph_conditions) {
Transition* l;
Fst2State s;
int ret_value=0;
int ret;
*graph_conditions=NULL;
s=states[current_state];
if (is_final_state(s)) {
   /* If we are arrived in a final state, then the graph matches <E> */
   set_bit_mask(&(s->control),UNCONDITIONAL_E_MATCH);
   return 1;
}
if (is_bit_mask_set(s->control,TMP_LOOP_MARK)) {
   /* If we have a loop, we do nothing, because they will be
    * dealt with later. */
   return 0;
}
if (is_bit_mask_set(s->control,VISITED_MARK)) {
   /* If we are in state that has already been visited */
   if (is_bit_mask_set(s->control,UNCONDITIONAL_E_MATCH)) {
      /* If this state can match <E> without conditions, then we have finished */
      return 1;
   }
   if (is_bit_mask_set(s->control,CONDITIONAL_E_MATCH)) {
      /* If this state can match <E> with conditions, then we have finished, but
       * we copy the necessary conditions in 'graph_conditions'. */
      *graph_conditions=clone_ConditionList(conditions_for_states[current_state-initial_state]);
      return 1;
   }
   /* If the state has been visited and if it does not match <E>, then we return OK */
   return 0;
}
set_bit_mask(&(s->control),VISITED_MARK);
set_bit_mask(&(s->control),TMP_LOOP_MARK);
l=s->transitions;
/* We look all the outgoing transitions */
while (l!=NULL) {
   if (l->tag_number<0) {
      /* If we have a subgraph, we test if it matches <E> */
      *graph_conditions=NULL;
      ret=graph_matches_E(initial_state,l->state_number,states,tags,current_graph,graph_names,conditions_for_states,graph_conditions);
      if (ret==1) {
         /* If the subgraph matches <E>, we say that the current state matches
          * <E>, modulo the conditions to be verified */
         set_bit_mask(&(s->control),CONDITIONAL_E_MATCH);
         /* We insert the new condition in first position... */
         insert_graph_in_conditions(-(l->tag_number),graph_conditions);
         /* ...and we merge the new conditions with the existing ones for this state */
         merge_condition_lists(&conditions_for_states[current_state-initial_state],*graph_conditions);
         *graph_conditions=NULL;
      }
      ret_value=ret_value|ret;
   }
   else if (tags[l->tag_number]->control&1) {
      /* If we have an <E> transition, we explore the rest of the graph from it */
      *graph_conditions=NULL;
      ret=graph_matches_E(initial_state,l->state_number,states,tags,current_graph,graph_names,conditions_for_states,graph_conditions);
      if (ret==1) {
         /* If we can match <E> from the <E>-transition's destination state, then
          * we can match it from the current state. */
         if (*graph_conditions==NULL) {
            /* If there is no condition */
            set_bit_mask(&(s->control),UNCONDITIONAL_E_MATCH);
         }
         else {
            /* Otherwise, we add the condition to the existing ones */
            set_bit_mask(&(s->control),CONDITIONAL_E_MATCH);
            merge_condition_lists(&conditions_for_states[current_state-initial_state],*graph_conditions);
            *graph_conditions=NULL;
         }
      }
      ret_value=ret_value|ret;
   }
   l=l->next;
}
unset_bit_mask(&(s->control),TMP_LOOP_MARK);
*graph_conditions=clone_ConditionList(conditions_for_states[current_state-initial_state]);
return ret_value;
}