int is_match_pike(struct Prog* prog,char* input, char** subp) { char* sp; struct Sub* sub; struct Inst* pc; int matched = 0; struct ThreadList *clist, *nlist, *tlist; int len = prog->len; clist = threadlist(len); nlist = threadlist(len); gen++; sub = newsub(); int i; for(i = 0; i < MAXSUB; i++) sub->sub[i] = NULL; addthread(clist, thread(prog->start, sub), input); for(sp = input; ; sp++) { if(clist->n == 0) break; gen++; for(i = 0; i < clist->n; i++) { pc = clist->t[i].pc; sub = clist->t[i].sub; switch(pc->opcode) { case Char: if(*sp != pc->c) { decref(sub); break; } //printf("%c", pc->c); case Any: if(*sp == '\0') { decref(sub); break; } addthread(nlist, thread(pc+1, sub), sp+1); break; case Match: matched = 1; int i; for(i = 0; i < MAXSUB; i++) subp[i] = sub->sub[i]; for(i = 0; i < clist->n; i++) decref(clist->t[i].sub); goto BreakFor; } } //printf("\n"); BreakFor: tlist = clist; clist = nlist; nlist = tlist; nlist->n = 0; if(sp == '\0') break; } if(matched) return sp - input; return 0; }
Sub* update(Sub *s, int i, const char *p) { Sub *s1; int j; if(s->ref > 1) { s1 = newsub(s->nsub); for(j=0; j<s->nsub; j++) s1->sub[j] = s->sub[j]; s->ref--; s = s1; } s->sub[i] = p; return s; }
static void test_add_thread(void) { char input[] = "ab"; struct Regexp* re = parse(input); struct Prog* prog = compile(re); struct Inst* pc = prog->start; struct Sub* s = newsub(); struct ThreadList* list = threadlist(2); gen++; addthread(list, thread(pc, s), input); gen++; addthread(list, thread(pc+1, s), input); assert('a' == list->t[0].pc->c); assert(Char == list->t[0].pc->opcode); assert('b' == list->t[1].pc->c); assert(Char == list->t[0].pc->opcode); }
int backtrack(Prog *prog, char *input, char **subp, int nsubp) { enum { MAX = 1000 }; Thread ready[MAX]; int i, nready; Inst *pc; char *sp; Sub *sub; /* queue initial thread */ sub = newsub(nsubp); for(i=0; i<nsubp; i++) sub->sub[i] = nil; ready[0] = thread(prog->start, input, sub); nready = 1; /* run threads in stack order */ while(nready > 0) { --nready; /* pop state for next thread to run */ pc = ready[nready].pc; sp = ready[nready].sp; sub = ready[nready].sub; assert(sub->ref > 0); for(;;) { switch(pc->opcode) { case Char: if(*sp != pc->c) goto Dead; pc++; sp++; continue; case Any: if(*sp == 0) goto Dead; pc++; sp++; continue; case Match: for(i=0; i<nsubp; i++) subp[i] = sub->sub[i]; decref(sub); return 1; case Jmp: pc = pc->x; continue; case Split: if(nready >= MAX) fatal("backtrack overflow"); ready[nready++] = thread(pc->y, sp, incref(sub)); pc = pc->x; /* continue current thread */ continue; case Save: sub = update(sub, pc->n, sp); pc++; continue; } } Dead: decref(sub); } return 0; }