static void apply_force_clear_stack(struct apply_handle *h) { /* Make sure stack is empty and marks reset */ if (!apply_stack_isempty(h)) { *(h->marks+(h->gstates+h->ptr)->state_no) = 0; while (!apply_stack_isempty(h)) { apply_stack_pop(h); *(h->marks+(h->gstates+h->ptr)->state_no) = 0; } h->iterator = 0; h->iterate_old = 0; apply_stack_clear(h); } }
char *apply_net(struct apply_handle *h) { char *fname, *fvalue; int eatupi, eatupo, symin, symout, f, fneg; int vcount, msource, mtarget; /* We perform a basic DFS on the graph, with two minor complications: */ /* 1. We keep a mark for each state which indicates whether it is seen */ /* on the current "run." If we reach a marked state, we terminate. */ /* As we pop a position, we also unmark the state we came from. */ /* If we're matching against a string, we terminate if the mark */ /* is set and ipos is the same as last time we saw the flag, i.e. */ /* we've traversed a loop without consuming an input symbol */ /* 2. If the graph has flags, we push the previous flag value when */ /* traversing a flag-modifying arc. This is because a flag may */ /* may have been set during the previous "run" and may not apply. */ /* Since we're doing a DFS, we can be sure to return to the previous */ /* global flag state by just remembering that last flag change. */ /* If called with NULL as the input word, this will be set */ if (h->iterate_old == 1) { goto resume; } h->ptr = 0; h->ipos = 0; h->opos = 0; apply_stack_clear(h); if (h->has_flags) { apply_clear_flags(h); } /* "The use of four-letter words like goto can occasionally be justified */ /* even in the best of company." Knuth (1974). */ goto L2; while(!apply_stack_isempty(h)) { apply_stack_pop(h); /* Last line */ if ((h->gstates+h->ptr)->state_no != (h->gstates+h->ptr+1)->state_no) { /* Restore mark */ *(h->marks+(h->gstates+h->ptr)->state_no) = 0; continue; } (h->ptr)++; /* Follow arc & push old position */ L1: for (f=0,h->curr_ptr = h->ptr; (h->gstates+h->curr_ptr)->state_no == (h->gstates+h->ptr)->state_no && (h->gstates+h->curr_ptr)-> in != -1; (h->curr_ptr)++) { f = 0; /* Select one random arc to follow out of all outgoing arcs */ if ((h->mode & RANDOM) == RANDOM) { vcount = 0; for (h->curr_ptr = h->ptr; (h->gstates+h->curr_ptr)->state_no == (h->gstates+h->ptr)->state_no && (h->gstates+h->curr_ptr)-> in != -1; (h->curr_ptr)++) { vcount++; } if (vcount > 0) { h->curr_ptr = h->ptr + (rand() % vcount) ; } else { h->curr_ptr = h->ptr; } } symin = (((h->mode)&DOWN) == DOWN) ? (h->gstates+h->curr_ptr)->in : (h->gstates+h->curr_ptr)->out; symout = (((h->mode)&DOWN) == DOWN) ? (h->gstates+h->curr_ptr)->out : (h->gstates+h->curr_ptr)->in; msource = *(h->marks+(h->gstates+h->ptr)->state_no); mtarget = *(h->marks+(h->gstates+(*(h->statemap+(h->gstates+h->curr_ptr)->target)))->state_no); if (((eatupi = apply_match_str(h, symin, h->ipos)) != -1) && -1-(h->ipos)-eatupi != mtarget) { eatupo = apply_append(h, h->curr_ptr, symout); if (g_obey_flags && h->has_flags && ((h->flag_lookup+symin)->type & (FLAG_UNIFY|FLAG_CLEAR|FLAG_POSITIVE|FLAG_NEGATIVE))) { fname = (h->flag_lookup+symin)->name; fvalue = h->oldflagvalue; fneg = h->oldflagneg; } else { fname = fvalue = NULL; fneg = 0; } apply_stack_push(h, h->curr_ptr, h->ipos, h->opos, msource, fname, fvalue, fneg); f = 1; h->ptr = *(h->statemap+(h->gstates+h->curr_ptr)->target); h->ipos = (h->ipos)+eatupi; h->opos = (h->opos)+eatupo; break; } } /* There were no more edges on this vertex? */ if (!f) { /* Unmark? */ *(h->marks+(h->gstates+h->ptr)->state_no) = 0; continue; } /* Print accumulated string */ L2: if ((h->gstates+h->ptr)->final_state == 1 && ((((h->mode) & ENUMERATE) == ENUMERATE) || (h->ipos == h->current_instring_length))) { /* Stick a 0 to endpos to avoid getting old accumulated gunk strings printed */ *(h->outstring+h->opos) = '\0'; if (((h->mode) & RANDOM) == RANDOM) { /* To end or not to end */ if (!(rand() % 2)) { apply_stack_clear(h); h->iterator = 0; h->iterate_old = 0; return(h->outstring); } } else { return(h->outstring); } } resume: /* Mark */ /* 0 = unseen, +ipos = seen at ipos, -ipos = seen second time at ipos */ if ((h->mode & RANDOM) != RANDOM) { if (*(h->marks+(h->gstates+h->ptr)->state_no) == h->ipos+1) { *(h->marks+(h->gstates+h->ptr)->state_no) = -(h->ipos+1); } else { *(h->marks+(h->gstates+h->ptr)->state_no) = h->ipos+1; } } goto L1; } /* Catch unprinted random which didn't stop at a final state */ if ((h->mode & RANDOM) == RANDOM) { apply_stack_clear(h); h->iterator = 0; h->iterate_old = 0; return(h->outstring); } apply_stack_clear(h); return NULL; }
char *apply_net(struct apply_handle *h) { /* We perform a basic DFS on the graph, with two minor complications: */ /* 1. We keep a mark for each state which indicates how many input symbols */ /* we had consumed the last time we entered that state on the current */ /* "run." If we reach a state seen twice without consuming input, we */ /* terminate that branch of the search. */ /* As we pop a position, we also unmark the state we came from. */ /* 2. If the graph has flags, we push the previous flag value when */ /* traversing a flag-modifying arc (P,U,N, or C). This is because a */ /* flag may have been set during the previous "run" and may not apply. */ /* Since we're doing a DFS, we can be sure to return to the previous */ /* global flag state by just remembering that last flag change. */ /* 3. The whole system needs to work as an iterator, meaning we need to */ /* store the global state of the search so we can resume it later to */ /* to yield more possible output words with the same input string. */ char *returnstring; if (h->iterate_old == 1) { /* If called with NULL as the input word, this will be set */ goto resume; } h->iptr = NULL; h->ptr = 0; h->ipos = 0; h->opos = 0; apply_set_iptr(h); apply_stack_clear(h); if (h->has_flags) { apply_clear_flags(h); } /* "The use of four-letter words like goto can occasionally be justified */ /* even in the best of company." Knuth (1974). */ goto L2; while(!apply_stack_isempty(h)) { apply_stack_pop(h); /* If last line was popped */ if (apply_at_last_arc(h)) { *(h->marks+(h->gstates+h->ptr)->state_no) = 0; /* Unmark */ continue; /* pop next */ } apply_skip_this_arc(h); /* skip old pushed arc */ L1: if (!apply_follow_next_arc(h)) { *(h->marks+(h->gstates+h->ptr)->state_no) = 0; /* Unmark */ continue; /* pop next */ } L2: /* Print accumulated string upon entry to state */ if ((h->gstates+h->ptr)->final_state == 1 && (h->ipos == h->current_instring_length || ((h->mode) & ENUMERATE) == ENUMERATE)) { if ((returnstring = (apply_return_string(h))) != NULL) { return(returnstring); } } resume: apply_mark_state(h); /* Mark upon arrival to new state */ goto L1; } if ((h->mode & RANDOM) == RANDOM) { apply_stack_clear(h); h->iterator = 0; h->iterate_old = 0; return(h->outstring); } apply_stack_clear(h); return NULL; }