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