|
|
researchv10 Norman
#include "regprog.h"
/*
* Machine state
*/
#define LISTINCREMENT 8
typedef struct List{
Inst *inst; /* Instruction of the thread */
Subexp se; /* matched subexpressions in this thread */
}List;
static List *tl, *nl; /* This list, next list */
static List *tle, *nle; /* ends of this and next list */
static List *list[2];
static List *liste[2];
static int listsize = LISTINCREMENT;
static Subexp sempty; /* empty set of matches */
static int match; /* true if match is found */
/*
* Note optimization in addinst:
* *lp must be pending when addinst called; if *l has been looked
* at already, the optimization is a bug.
*/
static List *
newthread(lp, ip, sep)
List *lp; /* list to add to */
Inst *ip; /* instruction to add */
register Subexp *sep; /* pointers to subexpressions */
{
register List *p;
for(p=lp; p->inst != NULL; p++){
if(p->inst==ip){
if((sep)->m[0].sp < p->se.m[0].sp)
p->se = *sep;
return NULL;
}
}
p->inst = ip;
p->se = *sep;
(++p)->inst = NULL;
return p;
}
static void
newmatch(mp, ms, sp)
regsubexp *mp;
int ms;
register Subexp *sp;
{
register int i;
if (mp==NULL || ms <=0)
return;
if(mp[0].sp==0 || sp->m[0].sp<mp[0].sp ||
(sp->m[0].sp==mp[0].sp && sp->m[0].ep>mp[0].ep)) {
for (i=0; i < ms; i++)
mp[i] = sp->m[i];
}
}
extern int
regexec(progp, starts, mp, ms)
Prog *progp; /* program to run */
char *starts; /* string to run machine on */
regsubexp *mp; /* subexpression elements */
int ms; /* number of elements pointed to by mp */
{
register flag=0;
register Inst *inst;
register List *tlp;
register char *s;
int startchar=progp->startinst->type<OPERATOR? progp->startinst->type : 0;
int i, checkstart;
restart:
match = 0;
checkstart = startchar;
sempty.m[0].sp = NULL;
if (mp!=NULL && ms >0)
mp[0].sp = mp[0].ep = NULL;
if (list[0] == NULL) {
list[0] = (List *)malloc(2*listsize*sizeof(List));
list[1] = list[0] + listsize;
liste[0] = list[0] + listsize - 1;
liste[1] = list[1] + listsize - 1;
if (list[0] == NULL)
regerror("list overflow");
}
list[0][0].inst = list[1][0].inst = NULL;
/* Execute machine once for each character, including terminal NUL */
s=starts;
do{
/* fast check for first char */
if(checkstart && *s!=startchar)
continue;
tl=list[flag];
tle=liste[flag];
nl=list[flag^=1];
nle=liste[flag];
nl->inst=0;
/* Add first instruction to this list */
sempty.m[0].sp = s;
(void)newthread(tl, progp->startinst, &sempty);
/* Execute machine until this list is empty */
for(tlp=tl; inst=tlp->inst; tlp++){ /* assignment = */
Switchstmt:
switch(inst->type){
default: /* regular character */
if(inst->type == *s){
Addinst:
if(newthread(nl, inst->next, &tlp->se)==nle)
goto realloc;
}
break;
case LBRA:
tlp->se.m[inst->subid].sp = s;
inst=inst->next;
goto Switchstmt;
case RBRA:
tlp->se.m[inst->subid].ep = s;
inst=inst->next;
goto Switchstmt;
case ANY:
goto Addinst;
case BOL:
if(s == starts){
inst=inst->next;
goto Switchstmt;
}
break;
case EOL:
if(*s=='\0'){
inst=inst->next;
goto Switchstmt;
}
break;
case CCLASS:
if(((char *)inst->right)[*s/8]&(1<<(*s&07)))
goto Addinst;
break;
case OR:
/* evaluate right choice later */
if (newthread(tlp, inst->right, &tlp->se) == tle)
goto realloc;
/* efficiency: advance and re-evaluate */
inst=inst->left;
goto Switchstmt;
case END: /* Match! */
match = 1;
tlp->se.m[0].ep = s;
if (mp != NULL && ms > 0) newmatch(mp, ms, &tlp->se);
break;
}
}
checkstart = startchar && nl->inst==NULL;
}while(*s++);
return match;
realloc:
free(list[0]);
list[0] = NULL;
listsize += LISTINCREMENT;
goto restart;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.