plan9front/sys/src/libregexp/regexec.c

202 lines
3.8 KiB
C
Raw Normal View History

#include <u.h>
#include <libc.h>
2016-04-26 20:23:44 -07:00
#include <regexp.h>
#include "regimpl.h"
2016-04-26 20:23:44 -07:00
typedef struct RethreadQ RethreadQ;
struct RethreadQ
{
Rethread *head;
Rethread **tail;
};
2016-04-26 20:23:44 -07:00
int
regexec(Reprog *prog, char *str, Resub *sem, int msize)
{
2016-04-26 20:23:44 -07:00
RethreadQ lists[2], *clist, *nlist, *tmp;
Rethread *t, *next, *pooltop, *avail;
2016-04-26 20:23:44 -07:00
Reinst *curinst;
Rune r;
char *sp, *ep, endc;
int i, match, first, gen, matchpri, pri;
2016-04-26 20:23:44 -07:00
if(msize > NSUBEXPM)
msize = NSUBEXPM;
2016-04-26 20:23:44 -07:00
if(prog->startinst->gen != 0) {
for(curinst = prog->startinst; curinst < prog->startinst + prog->len; curinst++)
curinst->gen = 0;
}
2016-04-26 20:23:44 -07:00
clist = lists;
clist->head = nil;
clist->tail = &clist->head;
nlist = lists + 1;
nlist->head = nil;
nlist->tail = &nlist->head;
pooltop = prog->threads + prog->nthr;
avail = nil;
2016-04-26 20:23:44 -07:00
pri = matchpri = gen = match = 0;
sp = str;
ep = nil;
endc = '\0';
if(sem != nil && msize > 0) {
if(sem->sp != nil)
sp = sem->sp;
if(sem->ep != nil && *sem->ep != '\0') {
ep = sem->ep;
endc = *sem->ep;
*sem->ep = '\0';
}
}
r = Runemax + 1;
for(; r != L'\0'; sp += i) {
gen++;
i = chartorune(&r, sp);
first = 1;
t = clist->head;
if(t == nil)
goto Start;
curinst = t->pc;
Again:
if(curinst->gen == gen)
goto Done;
curinst->gen = gen;
switch(curinst->op) {
case ORUNE:
if(r != curinst->r)
goto Done;
case OANY: /* fallthrough */
Any:
next = t->next;
2016-04-26 20:23:44 -07:00
t->pc = curinst + 1;
t->next = nil;
*nlist->tail = t;
nlist->tail = &t->next;
if(next == nil)
2016-04-26 20:23:44 -07:00
break;
t = next;
2016-04-26 20:23:44 -07:00
curinst = t->pc;
goto Again;
case OCLASS:
Class:
if(r < curinst->r)
goto Done;
if(r > curinst->r1) {
curinst++;
goto Class;
}
next = t->next;
2016-04-26 20:23:44 -07:00
t->pc = curinst->a;
t->next = nil;
*nlist->tail = t;
nlist->tail = &t->next;
if(next == nil)
break;
t = next;
2016-04-26 20:23:44 -07:00
curinst = t->pc;
goto Again;
case ONOTNL:
if(r != L'\n') {
curinst++;
goto Again;
}
goto Done;
case OBOL:
if(sp == str || sp[-1] == '\n') {
curinst++;
goto Again;
}
2016-04-26 20:23:44 -07:00
goto Done;
case OEOL:
if(r == L'\0' && ep == nil) {
curinst++;
goto Again;
}
if(r == L'\n')
goto Any;
goto Done;
case OJMP:
curinst = curinst->a;
goto Again;
case OSPLIT:
if(avail == nil)
next = --pooltop;
else {
next = avail;
avail = avail->next;
}
next->pc = curinst->b;
2016-04-26 20:23:44 -07:00
if(msize > 0)
memcpy(next->sem, t->sem, sizeof(Resub)*msize);
next->pri = t->pri;
next->next = t->next;
t->next = next;
2016-04-26 20:23:44 -07:00
curinst = curinst->a;
goto Again;
case OSAVE:
if(curinst->sub < msize)
t->sem[curinst->sub].sp = sp;
curinst++;
goto Again;
case OUNSAVE:
if(curinst->sub == 0) {
/* "Highest" priority is the left-most longest. */
if (t->pri > matchpri)
goto Done;
match = 1;
matchpri = t->pri;
if(sem != nil && msize > 0) {
memcpy(sem, t->sem, sizeof(Resub)*msize);
sem->ep = sp;
}
goto Done;
}
if(curinst->sub < msize)
t->sem[curinst->sub].ep = sp;
curinst++;
goto Again;
Done:
next = t->next;
t->next = avail;
avail = t;
if(next == nil)
2016-04-26 20:23:44 -07:00
break;
t = next;
2016-04-26 20:23:44 -07:00
curinst = t->pc;
goto Again;
}
2016-04-26 20:23:44 -07:00
Start:
/* Start again once if we haven't found anything. */
if(first == 1 && match == 0) {
first = 0;
if(avail == nil)
t = --pooltop;
else {
t = avail;
avail = avail->next;
}
2016-04-26 20:23:44 -07:00
if(msize > 0)
memset(t->sem, 0, sizeof(Resub)*msize);
/* "Lower" priority thread */
t->pri = matchpri = pri++;
t->next = nil;
curinst = prog->startinst;
goto Again;
}
/* If we have a match and no extant threads, we are done. */
if(match == 1 && nlist->head == nil)
break;
2016-04-26 20:23:44 -07:00
tmp = clist;
clist = nlist;
nlist = tmp;
nlist->head = nil;
nlist->tail = &nlist->head;
}
2016-04-26 20:23:44 -07:00
if(ep != nil)
*ep = endc;
return match;
}