xref: /plan9/sys/src/cmd/sam/regexp.c (revision 82726826a7b3d40fb66339b4b0e95b60314f98b9)
13e12c5d1SDavid du Colombier #include "sam.h"
23e12c5d1SDavid du Colombier 
33e12c5d1SDavid du Colombier Rangeset	sel;
43e12c5d1SDavid du Colombier String		lastregexp;
53e12c5d1SDavid du Colombier /*
63e12c5d1SDavid du Colombier  * Machine Information
73e12c5d1SDavid du Colombier  */
83e12c5d1SDavid du Colombier typedef struct Inst Inst;
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier struct Inst
113e12c5d1SDavid du Colombier {
12*82726826SDavid du Colombier 	long	type;	/* <= Runemax ==> literal, otherwise action */
133e12c5d1SDavid du Colombier 	union {
143e12c5d1SDavid du Colombier 		int rsid;
153e12c5d1SDavid du Colombier 		int rsubid;
163e12c5d1SDavid du Colombier 		int class;
173e12c5d1SDavid du Colombier 		struct Inst *rother;
183e12c5d1SDavid du Colombier 		struct Inst *rright;
193e12c5d1SDavid du Colombier 	} r;
203e12c5d1SDavid du Colombier 	union{
213e12c5d1SDavid du Colombier 		struct Inst *lleft;
223e12c5d1SDavid du Colombier 		struct Inst *lnext;
233e12c5d1SDavid du Colombier 	} l;
243e12c5d1SDavid du Colombier };
253e12c5d1SDavid du Colombier #define	sid	r.rsid
263e12c5d1SDavid du Colombier #define	subid	r.rsubid
273e12c5d1SDavid du Colombier #define	rclass	r.class
283e12c5d1SDavid du Colombier #define	other	r.rother
293e12c5d1SDavid du Colombier #define	right	r.rright
303e12c5d1SDavid du Colombier #define	left	l.lleft
313e12c5d1SDavid du Colombier #define	next	l.lnext
323e12c5d1SDavid du Colombier 
333e12c5d1SDavid du Colombier #define	NPROG	1024
343e12c5d1SDavid du Colombier Inst	program[NPROG];
353e12c5d1SDavid du Colombier Inst	*progp;
363e12c5d1SDavid du Colombier Inst	*startinst;	/* First inst. of program; might not be program[0] */
373e12c5d1SDavid du Colombier Inst	*bstartinst;	/* same for backwards machine */
383e12c5d1SDavid du Colombier 
393e12c5d1SDavid du Colombier typedef struct Ilist Ilist;
403e12c5d1SDavid du Colombier struct Ilist
413e12c5d1SDavid du Colombier {
423e12c5d1SDavid du Colombier 	Inst	*inst;		/* Instruction of the thread */
433e12c5d1SDavid du Colombier 	Rangeset se;
443e12c5d1SDavid du Colombier 	Posn	startp;		/* first char of match */
453e12c5d1SDavid du Colombier };
463e12c5d1SDavid du Colombier 
47e6dcbf51SDavid du Colombier #define	NLIST	127
483e12c5d1SDavid du Colombier 
493e12c5d1SDavid du Colombier Ilist	*tl, *nl;		/* This list, next list */
50e6dcbf51SDavid du Colombier Ilist	list[2][NLIST+1];	/* +1 for trailing null */
513e12c5d1SDavid du Colombier static	Rangeset sempty;
523e12c5d1SDavid du Colombier 
533e12c5d1SDavid du Colombier /*
543e12c5d1SDavid du Colombier  * Actions and Tokens
553e12c5d1SDavid du Colombier  *
563e12c5d1SDavid du Colombier  *	0x100xx are operators, value == precedence
573e12c5d1SDavid du Colombier  *	0x200xx are tokens, i.e. operands for operators
583e12c5d1SDavid du Colombier  */
59*82726826SDavid du Colombier enum {
60*82726826SDavid du Colombier 	OPERATOR = Runemask+1,	/* Bitmask of all operators */
61*82726826SDavid du Colombier 	START	= OPERATOR,	/* Start, used for marker on stack */
62*82726826SDavid du Colombier 	RBRA,			/* Right bracket, ) */
63*82726826SDavid du Colombier 	LBRA,			/* Left bracket, ( */
64*82726826SDavid du Colombier 	OR,			/* Alternation, | */
65*82726826SDavid du Colombier 	CAT,			/* Concatentation, implicit operator */
66*82726826SDavid du Colombier 	STAR,			/* Closure, * */
67*82726826SDavid du Colombier 	PLUS,			/* a+ == aa* */
68*82726826SDavid du Colombier 	QUEST,			/* a? == a|nothing, i.e. 0 or 1 a's */
693e12c5d1SDavid du Colombier 
70*82726826SDavid du Colombier 	ANY	= OPERATOR<<1,	/* Any character but newline, . */
71*82726826SDavid du Colombier 	NOP,			/* No operation, internal use only */
72*82726826SDavid du Colombier 	BOL,			/* Beginning of line, ^ */
73*82726826SDavid du Colombier 	EOL,			/* End of line, $ */
74*82726826SDavid du Colombier 	CCLASS,			/* Character class, [] */
75*82726826SDavid du Colombier 	NCCLASS,		/* Negated character class, [^] */
76*82726826SDavid du Colombier 	END,			/* Terminate: match found */
77*82726826SDavid du Colombier 
78*82726826SDavid du Colombier 	ISATOR	= OPERATOR,
79*82726826SDavid du Colombier 	ISAND	= OPERATOR<<1,
80*82726826SDavid du Colombier };
813e12c5d1SDavid du Colombier 
823e12c5d1SDavid du Colombier /*
833e12c5d1SDavid du Colombier  * Parser Information
843e12c5d1SDavid du Colombier  */
853e12c5d1SDavid du Colombier typedef struct Node Node;
863e12c5d1SDavid du Colombier struct Node
873e12c5d1SDavid du Colombier {
883e12c5d1SDavid du Colombier 	Inst	*first;
893e12c5d1SDavid du Colombier 	Inst	*last;
903e12c5d1SDavid du Colombier };
913e12c5d1SDavid du Colombier 
923e12c5d1SDavid du Colombier #define	NSTACK	20
933e12c5d1SDavid du Colombier Node	andstack[NSTACK];
943e12c5d1SDavid du Colombier Node	*andp;
953e12c5d1SDavid du Colombier int	atorstack[NSTACK];
963e12c5d1SDavid du Colombier int	*atorp;
973e12c5d1SDavid du Colombier int	lastwasand;	/* Last token was operand */
983e12c5d1SDavid du Colombier int	cursubid;
993e12c5d1SDavid du Colombier int	subidstack[NSTACK];
1003e12c5d1SDavid du Colombier int	*subidp;
1013e12c5d1SDavid du Colombier int	backwards;
1023e12c5d1SDavid du Colombier int	nbra;
1033e12c5d1SDavid du Colombier Rune	*exprp;		/* pointer to next character in source expression */
1043e12c5d1SDavid du Colombier #define	DCLASS	10	/* allocation increment */
1053e12c5d1SDavid du Colombier int	nclass;		/* number active */
1063e12c5d1SDavid du Colombier int	Nclass;		/* high water mark */
1073e12c5d1SDavid du Colombier Rune	**class;
1083e12c5d1SDavid du Colombier int	negateclass;
1093e12c5d1SDavid du Colombier 
110e6dcbf51SDavid du Colombier int	addinst(Ilist *l, Inst *inst, Rangeset *sep);
1113e12c5d1SDavid du Colombier void	newmatch(Rangeset*);
1123e12c5d1SDavid du Colombier void	bnewmatch(Rangeset*);
1133e12c5d1SDavid du Colombier void	pushand(Inst*, Inst*);
1143e12c5d1SDavid du Colombier void	pushator(int);
1153e12c5d1SDavid du Colombier Node	*popand(int);
1163e12c5d1SDavid du Colombier int	popator(void);
1173e12c5d1SDavid du Colombier void	startlex(Rune*);
1183e12c5d1SDavid du Colombier int	lex(void);
1193e12c5d1SDavid du Colombier void	operator(int);
1203e12c5d1SDavid du Colombier void	operand(int);
1213e12c5d1SDavid du Colombier void	evaluntil(int);
1223e12c5d1SDavid du Colombier void	optimize(Inst*);
1233e12c5d1SDavid du Colombier void	bldcclass(void);
1243e12c5d1SDavid du Colombier 
1253e12c5d1SDavid du Colombier void
regerror(Err e)1263e12c5d1SDavid du Colombier regerror(Err e)
1273e12c5d1SDavid du Colombier {
1283e12c5d1SDavid du Colombier 	Strzero(&lastregexp);
1293e12c5d1SDavid du Colombier 	error(e);
1303e12c5d1SDavid du Colombier }
1313e12c5d1SDavid du Colombier 
1323e12c5d1SDavid du Colombier void
regerror_c(Err e,int c)1333e12c5d1SDavid du Colombier regerror_c(Err e, int c)
1343e12c5d1SDavid du Colombier {
1353e12c5d1SDavid du Colombier 	Strzero(&lastregexp);
1363e12c5d1SDavid du Colombier 	error_c(e, c);
1373e12c5d1SDavid du Colombier }
1383e12c5d1SDavid du Colombier 
1393e12c5d1SDavid du Colombier Inst *
newinst(int t)1403e12c5d1SDavid du Colombier newinst(int t)
1413e12c5d1SDavid du Colombier {
1423e12c5d1SDavid du Colombier 	if(progp >= &program[NPROG])
1433e12c5d1SDavid du Colombier 		regerror(Etoolong);
1443e12c5d1SDavid du Colombier 	progp->type = t;
1453e12c5d1SDavid du Colombier 	progp->left = 0;
1463e12c5d1SDavid du Colombier 	progp->right = 0;
1473e12c5d1SDavid du Colombier 	return progp++;
1483e12c5d1SDavid du Colombier }
1493e12c5d1SDavid du Colombier 
1503e12c5d1SDavid du Colombier Inst *
realcompile(Rune * s)1513e12c5d1SDavid du Colombier realcompile(Rune *s)
1523e12c5d1SDavid du Colombier {
1533e12c5d1SDavid du Colombier 	int token;
1543e12c5d1SDavid du Colombier 
1553e12c5d1SDavid du Colombier 	startlex(s);
1563e12c5d1SDavid du Colombier 	atorp = atorstack;
1573e12c5d1SDavid du Colombier 	andp = andstack;
1583e12c5d1SDavid du Colombier 	subidp = subidstack;
1593e12c5d1SDavid du Colombier 	cursubid = 0;
1603e12c5d1SDavid du Colombier 	lastwasand = FALSE;
1613e12c5d1SDavid du Colombier 	/* Start with a low priority operator to prime parser */
1623e12c5d1SDavid du Colombier 	pushator(START-1);
1633e12c5d1SDavid du Colombier 	while((token=lex()) != END){
1643e12c5d1SDavid du Colombier 		if((token&ISATOR) == OPERATOR)
1653e12c5d1SDavid du Colombier 			operator(token);
1663e12c5d1SDavid du Colombier 		else
1673e12c5d1SDavid du Colombier 			operand(token);
1683e12c5d1SDavid du Colombier 	}
1693e12c5d1SDavid du Colombier 	/* Close with a low priority operator */
1703e12c5d1SDavid du Colombier 	evaluntil(START);
1713e12c5d1SDavid du Colombier 	/* Force END */
1723e12c5d1SDavid du Colombier 	operand(END);
1733e12c5d1SDavid du Colombier 	evaluntil(START);
1743e12c5d1SDavid du Colombier 	if(nbra)
1753e12c5d1SDavid du Colombier 		regerror(Eleftpar);
1763e12c5d1SDavid du Colombier 	--andp;	/* points to first and only operand */
1773e12c5d1SDavid du Colombier 	return andp->first;
1783e12c5d1SDavid du Colombier }
1793e12c5d1SDavid du Colombier 
1803e12c5d1SDavid du Colombier void
compile(String * s)1813e12c5d1SDavid du Colombier compile(String *s)
1823e12c5d1SDavid du Colombier {
1833e12c5d1SDavid du Colombier 	int i;
1843e12c5d1SDavid du Colombier 	Inst *oprogp;
1853e12c5d1SDavid du Colombier 
1863e12c5d1SDavid du Colombier 	if(Strcmp(s, &lastregexp)==0)
1873e12c5d1SDavid du Colombier 		return;
1883e12c5d1SDavid du Colombier 	for(i=0; i<nclass; i++)
1893e12c5d1SDavid du Colombier 		free(class[i]);
1903e12c5d1SDavid du Colombier 	nclass = 0;
1913e12c5d1SDavid du Colombier 	progp = program;
1923e12c5d1SDavid du Colombier 	backwards = FALSE;
1933e12c5d1SDavid du Colombier 	startinst = realcompile(s->s);
1943e12c5d1SDavid du Colombier 	optimize(program);
1953e12c5d1SDavid du Colombier 	oprogp = progp;
1963e12c5d1SDavid du Colombier 	backwards = TRUE;
1973e12c5d1SDavid du Colombier 	bstartinst = realcompile(s->s);
1983e12c5d1SDavid du Colombier 	optimize(oprogp);
1993e12c5d1SDavid du Colombier 	Strduplstr(&lastregexp, s);
2003e12c5d1SDavid du Colombier }
2013e12c5d1SDavid du Colombier 
2023e12c5d1SDavid du Colombier void
operand(int t)2033e12c5d1SDavid du Colombier operand(int t)
2043e12c5d1SDavid du Colombier {
2053e12c5d1SDavid du Colombier 	Inst *i;
2063e12c5d1SDavid du Colombier 	if(lastwasand)
2073e12c5d1SDavid du Colombier 		operator(CAT);	/* catenate is implicit */
2083e12c5d1SDavid du Colombier 	i = newinst(t);
2093e12c5d1SDavid du Colombier 	if(t == CCLASS){
2103e12c5d1SDavid du Colombier 		if(negateclass)
2113e12c5d1SDavid du Colombier 			i->type = NCCLASS;	/* UGH */
2123e12c5d1SDavid du Colombier 		i->rclass = nclass-1;		/* UGH */
2133e12c5d1SDavid du Colombier 	}
2143e12c5d1SDavid du Colombier 	pushand(i, i);
2153e12c5d1SDavid du Colombier 	lastwasand = TRUE;
2163e12c5d1SDavid du Colombier }
2173e12c5d1SDavid du Colombier 
2183e12c5d1SDavid du Colombier void
operator(int t)2193e12c5d1SDavid du Colombier operator(int t)
2203e12c5d1SDavid du Colombier {
2213e12c5d1SDavid du Colombier 	if(t==RBRA && --nbra<0)
2223e12c5d1SDavid du Colombier 		regerror(Erightpar);
2233e12c5d1SDavid du Colombier 	if(t==LBRA){
2243e12c5d1SDavid du Colombier /*
2253e12c5d1SDavid du Colombier  *		if(++cursubid >= NSUBEXP)
2263e12c5d1SDavid du Colombier  *			regerror(Esubexp);
2273e12c5d1SDavid du Colombier  */
2283e12c5d1SDavid du Colombier 		cursubid++;	/* silently ignored */
2293e12c5d1SDavid du Colombier 		nbra++;
2303e12c5d1SDavid du Colombier 		if(lastwasand)
2313e12c5d1SDavid du Colombier 			operator(CAT);
2323e12c5d1SDavid du Colombier 	}else
2333e12c5d1SDavid du Colombier 		evaluntil(t);
2343e12c5d1SDavid du Colombier 	if(t!=RBRA)
2353e12c5d1SDavid du Colombier 		pushator(t);
2363e12c5d1SDavid du Colombier 	lastwasand = FALSE;
2373e12c5d1SDavid du Colombier 	if(t==STAR || t==QUEST || t==PLUS || t==RBRA)
2383e12c5d1SDavid du Colombier 		lastwasand = TRUE;	/* these look like operands */
2393e12c5d1SDavid du Colombier }
2403e12c5d1SDavid du Colombier 
2413e12c5d1SDavid du Colombier void
cant(char * s)2423e12c5d1SDavid du Colombier cant(char *s)
2433e12c5d1SDavid du Colombier {
2443e12c5d1SDavid du Colombier 	char buf[100];
2453e12c5d1SDavid du Colombier 
2463e12c5d1SDavid du Colombier 	sprint(buf, "regexp: can't happen: %s", s);
2473e12c5d1SDavid du Colombier 	panic(buf);
2483e12c5d1SDavid du Colombier }
2493e12c5d1SDavid du Colombier 
2503e12c5d1SDavid du Colombier void
pushand(Inst * f,Inst * l)2513e12c5d1SDavid du Colombier pushand(Inst *f, Inst *l)
2523e12c5d1SDavid du Colombier {
2533e12c5d1SDavid du Colombier 	if(andp >= &andstack[NSTACK])
2543e12c5d1SDavid du Colombier 		cant("operand stack overflow");
2553e12c5d1SDavid du Colombier 	andp->first = f;
2563e12c5d1SDavid du Colombier 	andp->last = l;
2573e12c5d1SDavid du Colombier 	andp++;
2583e12c5d1SDavid du Colombier }
2593e12c5d1SDavid du Colombier 
2603e12c5d1SDavid du Colombier void
pushator(int t)2613e12c5d1SDavid du Colombier pushator(int t)
2623e12c5d1SDavid du Colombier {
2633e12c5d1SDavid du Colombier 	if(atorp >= &atorstack[NSTACK])
2643e12c5d1SDavid du Colombier 		cant("operator stack overflow");
2653e12c5d1SDavid du Colombier 	*atorp++=t;
2663e12c5d1SDavid du Colombier 	if(cursubid >= NSUBEXP)
2673e12c5d1SDavid du Colombier 		*subidp++= -1;
2683e12c5d1SDavid du Colombier 	else
2693e12c5d1SDavid du Colombier 		*subidp++=cursubid;
2703e12c5d1SDavid du Colombier }
2713e12c5d1SDavid du Colombier 
2723e12c5d1SDavid du Colombier Node *
popand(int op)2733e12c5d1SDavid du Colombier popand(int op)
2743e12c5d1SDavid du Colombier {
2753e12c5d1SDavid du Colombier 	if(andp <= &andstack[0])
2763e12c5d1SDavid du Colombier 		if(op)
2773e12c5d1SDavid du Colombier 			regerror_c(Emissop, op);
2783e12c5d1SDavid du Colombier 		else
2793e12c5d1SDavid du Colombier 			regerror(Ebadregexp);
2803e12c5d1SDavid du Colombier 	return --andp;
2813e12c5d1SDavid du Colombier }
2823e12c5d1SDavid du Colombier 
2833e12c5d1SDavid du Colombier int
popator(void)2843e12c5d1SDavid du Colombier popator(void)
2853e12c5d1SDavid du Colombier {
2863e12c5d1SDavid du Colombier 	if(atorp <= &atorstack[0])
2873e12c5d1SDavid du Colombier 		cant("operator stack underflow");
2883e12c5d1SDavid du Colombier 	--subidp;
2893e12c5d1SDavid du Colombier 	return *--atorp;
2903e12c5d1SDavid du Colombier }
2913e12c5d1SDavid du Colombier 
2923e12c5d1SDavid du Colombier void
evaluntil(int pri)2933e12c5d1SDavid du Colombier evaluntil(int pri)
2943e12c5d1SDavid du Colombier {
2953e12c5d1SDavid du Colombier 	Node *op1, *op2, *t;
2963e12c5d1SDavid du Colombier 	Inst *inst1, *inst2;
2973e12c5d1SDavid du Colombier 
2983e12c5d1SDavid du Colombier 	while(pri==RBRA || atorp[-1]>=pri){
2993e12c5d1SDavid du Colombier 		switch(popator()){
3003e12c5d1SDavid du Colombier 		case LBRA:
3013e12c5d1SDavid du Colombier 			op1 = popand('(');
3023e12c5d1SDavid du Colombier 			inst2 = newinst(RBRA);
3033e12c5d1SDavid du Colombier 			inst2->subid = *subidp;
3043e12c5d1SDavid du Colombier 			op1->last->next = inst2;
3053e12c5d1SDavid du Colombier 			inst1 = newinst(LBRA);
3063e12c5d1SDavid du Colombier 			inst1->subid = *subidp;
3073e12c5d1SDavid du Colombier 			inst1->next = op1->first;
3083e12c5d1SDavid du Colombier 			pushand(inst1, inst2);
3093e12c5d1SDavid du Colombier 			return;		/* must have been RBRA */
3103e12c5d1SDavid du Colombier 		default:
3113e12c5d1SDavid du Colombier 			panic("unknown regexp operator");
3123e12c5d1SDavid du Colombier 			break;
3133e12c5d1SDavid du Colombier 		case OR:
3143e12c5d1SDavid du Colombier 			op2 = popand('|');
3153e12c5d1SDavid du Colombier 			op1 = popand('|');
3163e12c5d1SDavid du Colombier 			inst2 = newinst(NOP);
3173e12c5d1SDavid du Colombier 			op2->last->next = inst2;
3183e12c5d1SDavid du Colombier 			op1->last->next = inst2;
3193e12c5d1SDavid du Colombier 			inst1 = newinst(OR);
3203e12c5d1SDavid du Colombier 			inst1->right = op1->first;
3213e12c5d1SDavid du Colombier 			inst1->left = op2->first;
3223e12c5d1SDavid du Colombier 			pushand(inst1, inst2);
3233e12c5d1SDavid du Colombier 			break;
3243e12c5d1SDavid du Colombier 		case CAT:
3253e12c5d1SDavid du Colombier 			op2 = popand(0);
3263e12c5d1SDavid du Colombier 			op1 = popand(0);
3273e12c5d1SDavid du Colombier 			if(backwards && op2->first->type!=END)
3283e12c5d1SDavid du Colombier 				t = op1, op1 = op2, op2 = t;
3293e12c5d1SDavid du Colombier 			op1->last->next = op2->first;
3303e12c5d1SDavid du Colombier 			pushand(op1->first, op2->last);
3313e12c5d1SDavid du Colombier 			break;
3323e12c5d1SDavid du Colombier 		case STAR:
3333e12c5d1SDavid du Colombier 			op2 = popand('*');
3343e12c5d1SDavid du Colombier 			inst1 = newinst(OR);
3353e12c5d1SDavid du Colombier 			op2->last->next = inst1;
3363e12c5d1SDavid du Colombier 			inst1->right = op2->first;
3373e12c5d1SDavid du Colombier 			pushand(inst1, inst1);
3383e12c5d1SDavid du Colombier 			break;
3393e12c5d1SDavid du Colombier 		case PLUS:
3403e12c5d1SDavid du Colombier 			op2 = popand('+');
3413e12c5d1SDavid du Colombier 			inst1 = newinst(OR);
3423e12c5d1SDavid du Colombier 			op2->last->next = inst1;
3433e12c5d1SDavid du Colombier 			inst1->right = op2->first;
3443e12c5d1SDavid du Colombier 			pushand(op2->first, inst1);
3453e12c5d1SDavid du Colombier 			break;
3463e12c5d1SDavid du Colombier 		case QUEST:
3473e12c5d1SDavid du Colombier 			op2 = popand('?');
3483e12c5d1SDavid du Colombier 			inst1 = newinst(OR);
3493e12c5d1SDavid du Colombier 			inst2 = newinst(NOP);
3503e12c5d1SDavid du Colombier 			inst1->left = inst2;
3513e12c5d1SDavid du Colombier 			inst1->right = op2->first;
3523e12c5d1SDavid du Colombier 			op2->last->next = inst2;
3533e12c5d1SDavid du Colombier 			pushand(inst1, inst2);
3543e12c5d1SDavid du Colombier 			break;
3553e12c5d1SDavid du Colombier 		}
3563e12c5d1SDavid du Colombier 	}
3573e12c5d1SDavid du Colombier }
3583e12c5d1SDavid du Colombier 
3593e12c5d1SDavid du Colombier 
3603e12c5d1SDavid du Colombier void
optimize(Inst * start)3613e12c5d1SDavid du Colombier optimize(Inst *start)
3623e12c5d1SDavid du Colombier {
3633e12c5d1SDavid du Colombier 	Inst *inst, *target;
3643e12c5d1SDavid du Colombier 
3653e12c5d1SDavid du Colombier 	for(inst=start; inst->type!=END; inst++){
3663e12c5d1SDavid du Colombier 		target = inst->next;
3673e12c5d1SDavid du Colombier 		while(target->type == NOP)
3683e12c5d1SDavid du Colombier 			target = target->next;
3693e12c5d1SDavid du Colombier 		inst->next = target;
3703e12c5d1SDavid du Colombier 	}
3713e12c5d1SDavid du Colombier }
3723e12c5d1SDavid du Colombier 
3733e12c5d1SDavid du Colombier #ifdef	DEBUG
3743e12c5d1SDavid du Colombier void
dumpstack(void)3753e12c5d1SDavid du Colombier dumpstack(void){
3763e12c5d1SDavid du Colombier 	Node *stk;
3773e12c5d1SDavid du Colombier 	int *ip;
3783e12c5d1SDavid du Colombier 
3793e12c5d1SDavid du Colombier 	dprint("operators\n");
3803e12c5d1SDavid du Colombier 	for(ip = atorstack; ip<atorp; ip++)
3813e12c5d1SDavid du Colombier 		dprint("0%o\n", *ip);
3823e12c5d1SDavid du Colombier 	dprint("operands\n");
3833e12c5d1SDavid du Colombier 	for(stk = andstack; stk<andp; stk++)
3843e12c5d1SDavid du Colombier 		dprint("0%o\t0%o\n", stk->first->type, stk->last->type);
3853e12c5d1SDavid du Colombier }
3863e12c5d1SDavid du Colombier void
dump(void)3873e12c5d1SDavid du Colombier dump(void){
3883e12c5d1SDavid du Colombier 	Inst *l;
3893e12c5d1SDavid du Colombier 
3903e12c5d1SDavid du Colombier 	l = program;
3913e12c5d1SDavid du Colombier 	do{
3923e12c5d1SDavid du Colombier 		dprint("%d:\t0%o\t%d\t%d\n", l-program, l->type,
3933e12c5d1SDavid du Colombier 			l->left-program, l->right-program);
3943e12c5d1SDavid du Colombier 	}while(l++->type);
3953e12c5d1SDavid du Colombier }
3963e12c5d1SDavid du Colombier #endif
3973e12c5d1SDavid du Colombier 
3983e12c5d1SDavid du Colombier void
startlex(Rune * s)3993e12c5d1SDavid du Colombier startlex(Rune *s)
4003e12c5d1SDavid du Colombier {
4013e12c5d1SDavid du Colombier 	exprp = s;
4023e12c5d1SDavid du Colombier 	nbra = 0;
4033e12c5d1SDavid du Colombier }
4043e12c5d1SDavid du Colombier 
4053e12c5d1SDavid du Colombier 
4063e12c5d1SDavid du Colombier int
lex(void)4073e12c5d1SDavid du Colombier lex(void){
4083e12c5d1SDavid du Colombier 	int c= *exprp++;
4093e12c5d1SDavid du Colombier 
4103e12c5d1SDavid du Colombier 	switch(c){
4113e12c5d1SDavid du Colombier 	case '\\':
4123e12c5d1SDavid du Colombier 		if(*exprp)
4133e12c5d1SDavid du Colombier 			if((c= *exprp++)=='n')
4143e12c5d1SDavid du Colombier 				c='\n';
4153e12c5d1SDavid du Colombier 		break;
4163e12c5d1SDavid du Colombier 	case 0:
4173e12c5d1SDavid du Colombier 		c = END;
4183e12c5d1SDavid du Colombier 		--exprp;	/* In case we come here again */
4193e12c5d1SDavid du Colombier 		break;
4203e12c5d1SDavid du Colombier 	case '*':
4213e12c5d1SDavid du Colombier 		c = STAR;
4223e12c5d1SDavid du Colombier 		break;
4233e12c5d1SDavid du Colombier 	case '?':
4243e12c5d1SDavid du Colombier 		c = QUEST;
4253e12c5d1SDavid du Colombier 		break;
4263e12c5d1SDavid du Colombier 	case '+':
4273e12c5d1SDavid du Colombier 		c = PLUS;
4283e12c5d1SDavid du Colombier 		break;
4293e12c5d1SDavid du Colombier 	case '|':
4303e12c5d1SDavid du Colombier 		c = OR;
4313e12c5d1SDavid du Colombier 		break;
4323e12c5d1SDavid du Colombier 	case '.':
4333e12c5d1SDavid du Colombier 		c = ANY;
4343e12c5d1SDavid du Colombier 		break;
4353e12c5d1SDavid du Colombier 	case '(':
4363e12c5d1SDavid du Colombier 		c = LBRA;
4373e12c5d1SDavid du Colombier 		break;
4383e12c5d1SDavid du Colombier 	case ')':
4393e12c5d1SDavid du Colombier 		c = RBRA;
4403e12c5d1SDavid du Colombier 		break;
4413e12c5d1SDavid du Colombier 	case '^':
4423e12c5d1SDavid du Colombier 		c = BOL;
4433e12c5d1SDavid du Colombier 		break;
4443e12c5d1SDavid du Colombier 	case '$':
4453e12c5d1SDavid du Colombier 		c = EOL;
4463e12c5d1SDavid du Colombier 		break;
4473e12c5d1SDavid du Colombier 	case '[':
4483e12c5d1SDavid du Colombier 		c = CCLASS;
4493e12c5d1SDavid du Colombier 		bldcclass();
4503e12c5d1SDavid du Colombier 		break;
4513e12c5d1SDavid du Colombier 	}
4523e12c5d1SDavid du Colombier 	return c;
4533e12c5d1SDavid du Colombier }
4543e12c5d1SDavid du Colombier 
4553e12c5d1SDavid du Colombier long
nextrec(void)4563e12c5d1SDavid du Colombier nextrec(void){
4573e12c5d1SDavid du Colombier 	if(exprp[0]==0 || (exprp[0]=='\\' && exprp[1]==0))
4583e12c5d1SDavid du Colombier 		regerror(Ebadclass);
4593e12c5d1SDavid du Colombier 	if(exprp[0] == '\\'){
4603e12c5d1SDavid du Colombier 		exprp++;
4613e12c5d1SDavid du Colombier 		if(*exprp=='n'){
4623e12c5d1SDavid du Colombier 			exprp++;
4633e12c5d1SDavid du Colombier 			return '\n';
4643e12c5d1SDavid du Colombier 		}
465*82726826SDavid du Colombier 		return *exprp++|(Runemax+1);
4663e12c5d1SDavid du Colombier 	}
4673e12c5d1SDavid du Colombier 	return *exprp++;
4683e12c5d1SDavid du Colombier }
4693e12c5d1SDavid du Colombier 
4703e12c5d1SDavid du Colombier void
bldcclass(void)4713e12c5d1SDavid du Colombier bldcclass(void)
4723e12c5d1SDavid du Colombier {
4733e12c5d1SDavid du Colombier 	long c1, c2, n, na;
4743e12c5d1SDavid du Colombier 	Rune *classp;
4753e12c5d1SDavid du Colombier 
4763e12c5d1SDavid du Colombier 	classp = emalloc(DCLASS*RUNESIZE);
4773e12c5d1SDavid du Colombier 	n = 0;
4783e12c5d1SDavid du Colombier 	na = DCLASS;
4793e12c5d1SDavid du Colombier 	/* we have already seen the '[' */
4803e12c5d1SDavid du Colombier 	if(*exprp == '^'){
4813e12c5d1SDavid du Colombier 		classp[n++] = '\n';	/* don't match newline in negate case */
4823e12c5d1SDavid du Colombier 		negateclass = TRUE;
4833e12c5d1SDavid du Colombier 		exprp++;
4843e12c5d1SDavid du Colombier 	}else
4853e12c5d1SDavid du Colombier 		negateclass = FALSE;
4863e12c5d1SDavid du Colombier 	while((c1 = nextrec()) != ']'){
4873e12c5d1SDavid du Colombier 		if(c1 == '-'){
4883e12c5d1SDavid du Colombier     Error:
4893e12c5d1SDavid du Colombier 			free(classp);
4903e12c5d1SDavid du Colombier 			regerror(Ebadclass);
4913e12c5d1SDavid du Colombier 		}
4923e12c5d1SDavid du Colombier 		if(n+4 >= na){		/* 3 runes plus NUL */
4933e12c5d1SDavid du Colombier 			na += DCLASS;
4943e12c5d1SDavid du Colombier 			classp = erealloc(classp, na*RUNESIZE);
4953e12c5d1SDavid du Colombier 		}
4963e12c5d1SDavid du Colombier 		if(*exprp == '-'){
4973e12c5d1SDavid du Colombier 			exprp++;	/* eat '-' */
4983e12c5d1SDavid du Colombier 			if((c2 = nextrec()) == ']')
4993e12c5d1SDavid du Colombier 				goto Error;
500*82726826SDavid du Colombier 			classp[n+0] = Runemax;
5013e12c5d1SDavid du Colombier 			classp[n+1] = c1;
5023e12c5d1SDavid du Colombier 			classp[n+2] = c2;
5033e12c5d1SDavid du Colombier 			n += 3;
5043e12c5d1SDavid du Colombier 		}else
5053e12c5d1SDavid du Colombier 			classp[n++] = c1;
5063e12c5d1SDavid du Colombier 	}
5073e12c5d1SDavid du Colombier 	classp[n] = 0;
5083e12c5d1SDavid du Colombier 	if(nclass == Nclass){
5093e12c5d1SDavid du Colombier 		Nclass += DCLASS;
5103e12c5d1SDavid du Colombier 		class = erealloc(class, Nclass*sizeof(Rune*));
5113e12c5d1SDavid du Colombier 	}
5123e12c5d1SDavid du Colombier 	class[nclass++] = classp;
5133e12c5d1SDavid du Colombier }
5143e12c5d1SDavid du Colombier 
5153e12c5d1SDavid du Colombier int
classmatch(int classno,int c,int negate)5163e12c5d1SDavid du Colombier classmatch(int classno, int c, int negate)
5173e12c5d1SDavid du Colombier {
5183e12c5d1SDavid du Colombier 	Rune *p;
5193e12c5d1SDavid du Colombier 
5203e12c5d1SDavid du Colombier 	p = class[classno];
5213e12c5d1SDavid du Colombier 	while(*p){
522*82726826SDavid du Colombier 		if(*p == Runemax){
5233e12c5d1SDavid du Colombier 			if(p[1]<=c && c<=p[2])
5243e12c5d1SDavid du Colombier 				return !negate;
5253e12c5d1SDavid du Colombier 			p += 3;
5263e12c5d1SDavid du Colombier 		}else if(*p++ == c)
5273e12c5d1SDavid du Colombier 			return !negate;
5283e12c5d1SDavid du Colombier 	}
5293e12c5d1SDavid du Colombier 	return negate;
5303e12c5d1SDavid du Colombier }
5313e12c5d1SDavid du Colombier 
5323e12c5d1SDavid du Colombier /*
5333e12c5d1SDavid du Colombier  * Note optimization in addinst:
5343e12c5d1SDavid du Colombier  * 	*l must be pending when addinst called; if *l has been looked
5353e12c5d1SDavid du Colombier  *		at already, the optimization is a bug.
5363e12c5d1SDavid du Colombier  */
537e6dcbf51SDavid du Colombier int
addinst(Ilist * l,Inst * inst,Rangeset * sep)5383e12c5d1SDavid du Colombier addinst(Ilist *l, Inst *inst, Rangeset *sep)
5393e12c5d1SDavid du Colombier {
5403e12c5d1SDavid du Colombier 	Ilist *p;
5413e12c5d1SDavid du Colombier 
5423e12c5d1SDavid du Colombier 	for(p = l; p->inst; p++){
5433e12c5d1SDavid du Colombier 		if(p->inst==inst){
5443e12c5d1SDavid du Colombier 			if((sep)->p[0].p1 < p->se.p[0].p1)
5453e12c5d1SDavid du Colombier 				p->se= *sep;	/* this would be bug */
546e6dcbf51SDavid du Colombier 			return 0;	/* It's already there */
5473e12c5d1SDavid du Colombier 		}
5483e12c5d1SDavid du Colombier 	}
5493e12c5d1SDavid du Colombier 	p->inst = inst;
5503e12c5d1SDavid du Colombier 	p->se= *sep;
5513e12c5d1SDavid du Colombier 	(p+1)->inst = 0;
552e6dcbf51SDavid du Colombier 	return 1;
5533e12c5d1SDavid du Colombier }
5543e12c5d1SDavid du Colombier 
5553e12c5d1SDavid du Colombier int
execute(File * f,Posn startp,Posn eof)5563e12c5d1SDavid du Colombier execute(File *f, Posn startp, Posn eof)
5573e12c5d1SDavid du Colombier {
5583e12c5d1SDavid du Colombier 	int flag = 0;
5593e12c5d1SDavid du Colombier 	Inst *inst;
5603e12c5d1SDavid du Colombier 	Ilist *tlp;
5613e12c5d1SDavid du Colombier 	Posn p = startp;
5623e12c5d1SDavid du Colombier 	int nnl = 0, ntl;
5633e12c5d1SDavid du Colombier 	int c;
5643e12c5d1SDavid du Colombier 	int wrapped = 0;
5653e12c5d1SDavid du Colombier 	int startchar = startinst->type<OPERATOR? startinst->type : 0;
5663e12c5d1SDavid du Colombier 
5673e12c5d1SDavid du Colombier 	list[0][0].inst = list[1][0].inst = 0;
5683e12c5d1SDavid du Colombier 	sel.p[0].p1 = -1;
5693e12c5d1SDavid du Colombier 	/* Execute machine once for each character */
5703e12c5d1SDavid du Colombier 	for(;;p++){
5713e12c5d1SDavid du Colombier 	doloop:
5727dd7cddfSDavid du Colombier 		c = filereadc(f, p);
5733e12c5d1SDavid du Colombier 		if(p>=eof || c<0){
5743e12c5d1SDavid du Colombier 			switch(wrapped++){
5753e12c5d1SDavid du Colombier 			case 0:		/* let loop run one more click */
5763e12c5d1SDavid du Colombier 			case 2:
5773e12c5d1SDavid du Colombier 				break;
5783e12c5d1SDavid du Colombier 			case 1:		/* expired; wrap to beginning */
5793e12c5d1SDavid du Colombier 				if(sel.p[0].p1>=0 || eof!=INFINITY)
5803e12c5d1SDavid du Colombier 					goto Return;
5813e12c5d1SDavid du Colombier 				list[0][0].inst = list[1][0].inst = 0;
5823e12c5d1SDavid du Colombier 				p = 0;
5833e12c5d1SDavid du Colombier 				goto doloop;
5843e12c5d1SDavid du Colombier 			default:
5853e12c5d1SDavid du Colombier 				goto Return;
5863e12c5d1SDavid du Colombier 			}
5873e12c5d1SDavid du Colombier 		}else if(((wrapped && p>=startp) || sel.p[0].p1>0) && nnl==0)
5883e12c5d1SDavid du Colombier 			break;
5893e12c5d1SDavid du Colombier 		/* fast check for first char */
5903e12c5d1SDavid du Colombier 		if(startchar && nnl==0 && c!=startchar)
5913e12c5d1SDavid du Colombier 			continue;
5923e12c5d1SDavid du Colombier 		tl = list[flag];
5933e12c5d1SDavid du Colombier 		nl = list[flag^=1];
5943e12c5d1SDavid du Colombier 		nl->inst = 0;
5953e12c5d1SDavid du Colombier 		ntl = nnl;
5963e12c5d1SDavid du Colombier 		nnl = 0;
5973e12c5d1SDavid du Colombier 		if(sel.p[0].p1<0 && (!wrapped || p<startp || startp==eof)){
5983e12c5d1SDavid du Colombier 			/* Add first instruction to this list */
599e6dcbf51SDavid du Colombier 			sempty.p[0].p1 = p;
600e6dcbf51SDavid du Colombier 			if(addinst(tl, startinst, &sempty))
6013e12c5d1SDavid du Colombier 			if(++ntl >= NLIST)
6023e12c5d1SDavid du Colombier 	Overflow:
6033e12c5d1SDavid du Colombier 				error(Eoverflow);
6043e12c5d1SDavid du Colombier 		}
6053e12c5d1SDavid du Colombier 		/* Execute machine until this list is empty */
6063e12c5d1SDavid du Colombier 		for(tlp = tl; inst = tlp->inst; tlp++){	/* assignment = */
6073e12c5d1SDavid du Colombier 	Switchstmt:
6083e12c5d1SDavid du Colombier 			switch(inst->type){
6093e12c5d1SDavid du Colombier 			default:	/* regular character */
6103e12c5d1SDavid du Colombier 				if(inst->type==c){
6113e12c5d1SDavid du Colombier 	Addinst:
612e6dcbf51SDavid du Colombier 					if(addinst(nl, inst->next, &tlp->se))
6133e12c5d1SDavid du Colombier 					if(++nnl >= NLIST)
6143e12c5d1SDavid du Colombier 						goto Overflow;
6153e12c5d1SDavid du Colombier 				}
6163e12c5d1SDavid du Colombier 				break;
6173e12c5d1SDavid du Colombier 			case LBRA:
6183e12c5d1SDavid du Colombier 				if(inst->subid>=0)
6193e12c5d1SDavid du Colombier 					tlp->se.p[inst->subid].p1 = p;
6203e12c5d1SDavid du Colombier 				inst = inst->next;
6213e12c5d1SDavid du Colombier 				goto Switchstmt;
6223e12c5d1SDavid du Colombier 			case RBRA:
6233e12c5d1SDavid du Colombier 				if(inst->subid>=0)
6243e12c5d1SDavid du Colombier 					tlp->se.p[inst->subid].p2 = p;
6253e12c5d1SDavid du Colombier 				inst = inst->next;
6263e12c5d1SDavid du Colombier 				goto Switchstmt;
6273e12c5d1SDavid du Colombier 			case ANY:
6283e12c5d1SDavid du Colombier 				if(c!='\n')
6293e12c5d1SDavid du Colombier 					goto Addinst;
6303e12c5d1SDavid du Colombier 				break;
6313e12c5d1SDavid du Colombier 			case BOL:
6327dd7cddfSDavid du Colombier 				if(p==0 || filereadc(f, p - 1)=='\n'){
6333e12c5d1SDavid du Colombier 	Step:
6343e12c5d1SDavid du Colombier 					inst = inst->next;
6353e12c5d1SDavid du Colombier 					goto Switchstmt;
6363e12c5d1SDavid du Colombier 				}
6373e12c5d1SDavid du Colombier 				break;
6383e12c5d1SDavid du Colombier 			case EOL:
6393e12c5d1SDavid du Colombier 				if(c == '\n')
6403e12c5d1SDavid du Colombier 					goto Step;
6413e12c5d1SDavid du Colombier 				break;
6423e12c5d1SDavid du Colombier 			case CCLASS:
6433e12c5d1SDavid du Colombier 				if(c>=0 && classmatch(inst->rclass, c, 0))
6443e12c5d1SDavid du Colombier 					goto Addinst;
6453e12c5d1SDavid du Colombier 				break;
6463e12c5d1SDavid du Colombier 			case NCCLASS:
6473e12c5d1SDavid du Colombier 				if(c>=0 && classmatch(inst->rclass, c, 1))
6483e12c5d1SDavid du Colombier 					goto Addinst;
6493e12c5d1SDavid du Colombier 				break;
6503e12c5d1SDavid du Colombier 			case OR:
6513e12c5d1SDavid du Colombier 				/* evaluate right choice later */
652e7f22645SDavid du Colombier 				if(addinst(tlp, inst->right, &tlp->se))
6533e12c5d1SDavid du Colombier 				if(++ntl >= NLIST)
6543e12c5d1SDavid du Colombier 					goto Overflow;
6553e12c5d1SDavid du Colombier 				/* efficiency: advance and re-evaluate */
6563e12c5d1SDavid du Colombier 				inst = inst->left;
6573e12c5d1SDavid du Colombier 				goto Switchstmt;
6583e12c5d1SDavid du Colombier 			case END:	/* Match! */
6593e12c5d1SDavid du Colombier 				tlp->se.p[0].p2 = p;
6603e12c5d1SDavid du Colombier 				newmatch(&tlp->se);
6613e12c5d1SDavid du Colombier 				break;
6623e12c5d1SDavid du Colombier 			}
6633e12c5d1SDavid du Colombier 		}
6643e12c5d1SDavid du Colombier 	}
6653e12c5d1SDavid du Colombier     Return:
6663e12c5d1SDavid du Colombier 	return sel.p[0].p1>=0;
6673e12c5d1SDavid du Colombier }
6683e12c5d1SDavid du Colombier 
6693e12c5d1SDavid du Colombier void
newmatch(Rangeset * sp)6703e12c5d1SDavid du Colombier newmatch(Rangeset *sp)
6713e12c5d1SDavid du Colombier {
6723e12c5d1SDavid du Colombier 	int i;
6733e12c5d1SDavid du Colombier 
6743e12c5d1SDavid du Colombier 	if(sel.p[0].p1<0 || sp->p[0].p1<sel.p[0].p1 ||
6753e12c5d1SDavid du Colombier 	   (sp->p[0].p1==sel.p[0].p1 && sp->p[0].p2>sel.p[0].p2))
6763e12c5d1SDavid du Colombier 		for(i = 0; i<NSUBEXP; i++)
6773e12c5d1SDavid du Colombier 			sel.p[i] = sp->p[i];
6783e12c5d1SDavid du Colombier }
6793e12c5d1SDavid du Colombier 
6803e12c5d1SDavid du Colombier int
bexecute(File * f,Posn startp)6813e12c5d1SDavid du Colombier bexecute(File *f, Posn startp)
6823e12c5d1SDavid du Colombier {
6833e12c5d1SDavid du Colombier 	int flag = 0;
6843e12c5d1SDavid du Colombier 	Inst *inst;
6853e12c5d1SDavid du Colombier 	Ilist *tlp;
6863e12c5d1SDavid du Colombier 	Posn p = startp;
6873e12c5d1SDavid du Colombier 	int nnl = 0, ntl;
6883e12c5d1SDavid du Colombier 	int c;
6893e12c5d1SDavid du Colombier 	int wrapped = 0;
6903e12c5d1SDavid du Colombier 	int startchar = bstartinst->type<OPERATOR? bstartinst->type : 0;
6913e12c5d1SDavid du Colombier 
6923e12c5d1SDavid du Colombier 	list[0][0].inst = list[1][0].inst = 0;
6933e12c5d1SDavid du Colombier 	sel.p[0].p1= -1;
6943e12c5d1SDavid du Colombier 	/* Execute machine once for each character, including terminal NUL */
6953e12c5d1SDavid du Colombier 	for(;;--p){
6963e12c5d1SDavid du Colombier 	doloop:
6977dd7cddfSDavid du Colombier 		if((c = filereadc(f, p - 1))==-1){
6983e12c5d1SDavid du Colombier 			switch(wrapped++){
6993e12c5d1SDavid du Colombier 			case 0:		/* let loop run one more click */
7003e12c5d1SDavid du Colombier 			case 2:
7013e12c5d1SDavid du Colombier 				break;
7023e12c5d1SDavid du Colombier 			case 1:		/* expired; wrap to end */
7033e12c5d1SDavid du Colombier 				if(sel.p[0].p1>=0)
7043e12c5d1SDavid du Colombier 			case 3:
7053e12c5d1SDavid du Colombier 					goto Return;
7063e12c5d1SDavid du Colombier 				list[0][0].inst = list[1][0].inst = 0;
7077dd7cddfSDavid du Colombier 				p = f->nc;
7083e12c5d1SDavid du Colombier 				goto doloop;
7093e12c5d1SDavid du Colombier 			default:
7103e12c5d1SDavid du Colombier 				goto Return;
7113e12c5d1SDavid du Colombier 			}
7123e12c5d1SDavid du Colombier 		}else if(((wrapped && p<=startp) || sel.p[0].p1>0) && nnl==0)
7133e12c5d1SDavid du Colombier 			break;
7143e12c5d1SDavid du Colombier 		/* fast check for first char */
7153e12c5d1SDavid du Colombier 		if(startchar && nnl==0 && c!=startchar)
7163e12c5d1SDavid du Colombier 			continue;
7173e12c5d1SDavid du Colombier 		tl = list[flag];
7183e12c5d1SDavid du Colombier 		nl = list[flag^=1];
7193e12c5d1SDavid du Colombier 		nl->inst = 0;
7203e12c5d1SDavid du Colombier 		ntl = nnl;
7213e12c5d1SDavid du Colombier 		nnl = 0;
7223e12c5d1SDavid du Colombier 		if(sel.p[0].p1<0 && (!wrapped || p>startp)){
7233e12c5d1SDavid du Colombier 			/* Add first instruction to this list */
724e6dcbf51SDavid du Colombier 			/* the minus is so the optimizations in addinst work */
725e6dcbf51SDavid du Colombier 			sempty.p[0].p1 = -p;
726e6dcbf51SDavid du Colombier 			if(addinst(tl, bstartinst, &sempty))
7273e12c5d1SDavid du Colombier 			if(++ntl >= NLIST)
7283e12c5d1SDavid du Colombier 	Overflow:
7293e12c5d1SDavid du Colombier 				error(Eoverflow);
7303e12c5d1SDavid du Colombier 		}
7313e12c5d1SDavid du Colombier 		/* Execute machine until this list is empty */
7323e12c5d1SDavid du Colombier 		for(tlp = tl; inst = tlp->inst; tlp++){	/* assignment = */
7333e12c5d1SDavid du Colombier 	Switchstmt:
7343e12c5d1SDavid du Colombier 			switch(inst->type){
7353e12c5d1SDavid du Colombier 			default:	/* regular character */
7363e12c5d1SDavid du Colombier 				if(inst->type == c){
7373e12c5d1SDavid du Colombier 	Addinst:
738e6dcbf51SDavid du Colombier 					if(addinst(nl, inst->next, &tlp->se))
7393e12c5d1SDavid du Colombier 					if(++nnl >= NLIST)
7403e12c5d1SDavid du Colombier 						goto Overflow;
7413e12c5d1SDavid du Colombier 				}
7423e12c5d1SDavid du Colombier 				break;
7433e12c5d1SDavid du Colombier 			case LBRA:
7443e12c5d1SDavid du Colombier 				if(inst->subid>=0)
7453e12c5d1SDavid du Colombier 					tlp->se.p[inst->subid].p1 = p;
7463e12c5d1SDavid du Colombier 				inst = inst->next;
7473e12c5d1SDavid du Colombier 				goto Switchstmt;
7483e12c5d1SDavid du Colombier 			case RBRA:
7493e12c5d1SDavid du Colombier 				if(inst->subid >= 0)
7503e12c5d1SDavid du Colombier 					tlp->se.p[inst->subid].p2 = p;
7513e12c5d1SDavid du Colombier 				inst = inst->next;
7523e12c5d1SDavid du Colombier 				goto Switchstmt;
7533e12c5d1SDavid du Colombier 			case ANY:
7543e12c5d1SDavid du Colombier 				if(c != '\n')
7553e12c5d1SDavid du Colombier 					goto Addinst;
7563e12c5d1SDavid du Colombier 				break;
7573e12c5d1SDavid du Colombier 			case BOL:
7583e12c5d1SDavid du Colombier 				if(c=='\n' || p==0){
7593e12c5d1SDavid du Colombier 	Step:
7603e12c5d1SDavid du Colombier 					inst = inst->next;
7613e12c5d1SDavid du Colombier 					goto Switchstmt;
7623e12c5d1SDavid du Colombier 				}
7633e12c5d1SDavid du Colombier 				break;
7643e12c5d1SDavid du Colombier 			case EOL:
7657dd7cddfSDavid du Colombier 				if(p==f->nc || filereadc(f, p)=='\n')
7663e12c5d1SDavid du Colombier 					goto Step;
7673e12c5d1SDavid du Colombier 				break;
7683e12c5d1SDavid du Colombier 			case CCLASS:
7693e12c5d1SDavid du Colombier 				if(c>=0 && classmatch(inst->rclass, c, 0))
7703e12c5d1SDavid du Colombier 					goto Addinst;
7713e12c5d1SDavid du Colombier 				break;
7723e12c5d1SDavid du Colombier 			case NCCLASS:
7733e12c5d1SDavid du Colombier 				if(c>=0 && classmatch(inst->rclass, c, 1))
7743e12c5d1SDavid du Colombier 					goto Addinst;
7753e12c5d1SDavid du Colombier 				break;
7763e12c5d1SDavid du Colombier 			case OR:
7773e12c5d1SDavid du Colombier 				/* evaluate right choice later */
778e6dcbf51SDavid du Colombier 				if(addinst(tl, inst->right, &tlp->se))
7793e12c5d1SDavid du Colombier 				if(++ntl >= NLIST)
7803e12c5d1SDavid du Colombier 					goto Overflow;
7813e12c5d1SDavid du Colombier 				/* efficiency: advance and re-evaluate */
7823e12c5d1SDavid du Colombier 				inst = inst->left;
7833e12c5d1SDavid du Colombier 				goto Switchstmt;
7843e12c5d1SDavid du Colombier 			case END:	/* Match! */
7853e12c5d1SDavid du Colombier 				tlp->se.p[0].p1 = -tlp->se.p[0].p1; /* minus sign */
7863e12c5d1SDavid du Colombier 				tlp->se.p[0].p2 = p;
7873e12c5d1SDavid du Colombier 				bnewmatch(&tlp->se);
7883e12c5d1SDavid du Colombier 				break;
7893e12c5d1SDavid du Colombier 			}
7903e12c5d1SDavid du Colombier 		}
7913e12c5d1SDavid du Colombier 	}
7923e12c5d1SDavid du Colombier     Return:
7933e12c5d1SDavid du Colombier 	return sel.p[0].p1>=0;
7943e12c5d1SDavid du Colombier }
7953e12c5d1SDavid du Colombier 
7963e12c5d1SDavid du Colombier void
bnewmatch(Rangeset * sp)7973e12c5d1SDavid du Colombier bnewmatch(Rangeset *sp)
7983e12c5d1SDavid du Colombier {
7993e12c5d1SDavid du Colombier         int  i;
8003e12c5d1SDavid du Colombier         if(sel.p[0].p1<0 || sp->p[0].p1>sel.p[0].p2 || (sp->p[0].p1==sel.p[0].p2 && sp->p[0].p2<sel.p[0].p1))
8013e12c5d1SDavid du Colombier                 for(i = 0; i<NSUBEXP; i++){       /* note the reversal; p1<=p2 */
8023e12c5d1SDavid du Colombier                         sel.p[i].p1 = sp->p[i].p2;
8033e12c5d1SDavid du Colombier                         sel.p[i].p2 = sp->p[i].p1;
8043e12c5d1SDavid du Colombier                 }
8053e12c5d1SDavid du Colombier }
806