xref: /plan9/sys/src/ape/lib/regexp/regcomp.c (revision 3e12c5d1bb89fc02707907988834ef147769ddaf)
1*3e12c5d1SDavid du Colombier #include <stdlib.h>
2*3e12c5d1SDavid du Colombier #include <stdio.h>
3*3e12c5d1SDavid du Colombier #include <setjmp.h>
4*3e12c5d1SDavid du Colombier #include <string.h>
5*3e12c5d1SDavid du Colombier #include "regexp.h"
6*3e12c5d1SDavid du Colombier #include "regcomp.h"
7*3e12c5d1SDavid du Colombier 
8*3e12c5d1SDavid du Colombier #define	TRUE	1
9*3e12c5d1SDavid du Colombier #define	FALSE	0
10*3e12c5d1SDavid du Colombier 
11*3e12c5d1SDavid du Colombier /*
12*3e12c5d1SDavid du Colombier  * Parser Information
13*3e12c5d1SDavid du Colombier  */
14*3e12c5d1SDavid du Colombier typedef
15*3e12c5d1SDavid du Colombier struct Node
16*3e12c5d1SDavid du Colombier {
17*3e12c5d1SDavid du Colombier 	Reinst*	first;
18*3e12c5d1SDavid du Colombier 	Reinst*	last;
19*3e12c5d1SDavid du Colombier }Node;
20*3e12c5d1SDavid du Colombier 
21*3e12c5d1SDavid du Colombier #define	NSTACK	20
22*3e12c5d1SDavid du Colombier static	Node	andstack[NSTACK];
23*3e12c5d1SDavid du Colombier static	Node	*andp;
24*3e12c5d1SDavid du Colombier static	int	atorstack[NSTACK];
25*3e12c5d1SDavid du Colombier static	int*	atorp;
26*3e12c5d1SDavid du Colombier static	int	cursubid;		/* id of current subexpression */
27*3e12c5d1SDavid du Colombier static	int	subidstack[NSTACK];	/* parallel to atorstack */
28*3e12c5d1SDavid du Colombier static	int*	subidp;
29*3e12c5d1SDavid du Colombier static	int	lastwasand;	/* Last token was operand */
30*3e12c5d1SDavid du Colombier static	int	nbra;
31*3e12c5d1SDavid du Colombier static	char*	exprp;		/* pointer to next character in source expression */
32*3e12c5d1SDavid du Colombier static	int	lexdone;
33*3e12c5d1SDavid du Colombier static	int	nclass;
34*3e12c5d1SDavid du Colombier static	Reclass*classp;
35*3e12c5d1SDavid du Colombier static	Reinst*	freep;
36*3e12c5d1SDavid du Colombier static	int	errors;
37*3e12c5d1SDavid du Colombier static	wchar_t	yyrune;		/* last lex'd rune */
38*3e12c5d1SDavid du Colombier static	Reclass*yyclassp;	/* last lex'd class */
39*3e12c5d1SDavid du Colombier 
40*3e12c5d1SDavid du Colombier /* predeclared crap */
41*3e12c5d1SDavid du Colombier static	void	operator(int);
42*3e12c5d1SDavid du Colombier static	void	pushand(Reinst*, Reinst*);
43*3e12c5d1SDavid du Colombier static	void	pushator(int);
44*3e12c5d1SDavid du Colombier static	void	evaluntil(int);
45*3e12c5d1SDavid du Colombier static	int	bldcclass(void);
46*3e12c5d1SDavid du Colombier 
47*3e12c5d1SDavid du Colombier static jmp_buf regkaboom;
48*3e12c5d1SDavid du Colombier 
49*3e12c5d1SDavid du Colombier static	void
rcerror(char * s)50*3e12c5d1SDavid du Colombier rcerror(char *s)
51*3e12c5d1SDavid du Colombier {
52*3e12c5d1SDavid du Colombier 	errors++;
53*3e12c5d1SDavid du Colombier 	regerror(s);
54*3e12c5d1SDavid du Colombier 	longjmp(regkaboom, 1);
55*3e12c5d1SDavid du Colombier }
56*3e12c5d1SDavid du Colombier 
57*3e12c5d1SDavid du Colombier static	Reinst*
newinst(int t)58*3e12c5d1SDavid du Colombier newinst(int t)
59*3e12c5d1SDavid du Colombier {
60*3e12c5d1SDavid du Colombier 	freep->type = t;
61*3e12c5d1SDavid du Colombier 	freep->l.left = 0;
62*3e12c5d1SDavid du Colombier 	freep->r.right = 0;
63*3e12c5d1SDavid du Colombier 	return freep++;
64*3e12c5d1SDavid du Colombier }
65*3e12c5d1SDavid du Colombier 
66*3e12c5d1SDavid du Colombier static	void
operand(int t)67*3e12c5d1SDavid du Colombier operand(int t)
68*3e12c5d1SDavid du Colombier {
69*3e12c5d1SDavid du Colombier 	Reinst *i;
70*3e12c5d1SDavid du Colombier 
71*3e12c5d1SDavid du Colombier 	if(lastwasand)
72*3e12c5d1SDavid du Colombier 		operator(CAT);	/* catenate is implicit */
73*3e12c5d1SDavid du Colombier 	i = newinst(t);
74*3e12c5d1SDavid du Colombier 
75*3e12c5d1SDavid du Colombier 	if(t == CCLASS || t == NCCLASS)
76*3e12c5d1SDavid du Colombier 		i->r.cp = yyclassp;
77*3e12c5d1SDavid du Colombier 	if(t == RUNE)
78*3e12c5d1SDavid du Colombier 		i->r.r = yyrune;
79*3e12c5d1SDavid du Colombier 
80*3e12c5d1SDavid du Colombier 	pushand(i, i);
81*3e12c5d1SDavid du Colombier 	lastwasand = TRUE;
82*3e12c5d1SDavid du Colombier }
83*3e12c5d1SDavid du Colombier 
84*3e12c5d1SDavid du Colombier static	void
operator(int t)85*3e12c5d1SDavid du Colombier operator(int t)
86*3e12c5d1SDavid du Colombier {
87*3e12c5d1SDavid du Colombier 	if(t==RBRA && --nbra<0)
88*3e12c5d1SDavid du Colombier 		rcerror("unmatched right paren");
89*3e12c5d1SDavid du Colombier 	if(t==LBRA){
90*3e12c5d1SDavid du Colombier 		if(++cursubid >= NSUBEXP)
91*3e12c5d1SDavid du Colombier 			rcerror ("too many subexpressions");
92*3e12c5d1SDavid du Colombier 		nbra++;
93*3e12c5d1SDavid du Colombier 		if(lastwasand)
94*3e12c5d1SDavid du Colombier 			operator(CAT);
95*3e12c5d1SDavid du Colombier 	} else
96*3e12c5d1SDavid du Colombier 		evaluntil(t);
97*3e12c5d1SDavid du Colombier 	if(t != RBRA)
98*3e12c5d1SDavid du Colombier 		pushator(t);
99*3e12c5d1SDavid du Colombier 	lastwasand = FALSE;
100*3e12c5d1SDavid du Colombier 	if(t==STAR || t==QUEST || t==PLUS || t==RBRA)
101*3e12c5d1SDavid du Colombier 		lastwasand = TRUE;	/* these look like operands */
102*3e12c5d1SDavid du Colombier }
103*3e12c5d1SDavid du Colombier 
104*3e12c5d1SDavid du Colombier static	void
regerr2(char * s,int c)105*3e12c5d1SDavid du Colombier regerr2(char *s, int c)
106*3e12c5d1SDavid du Colombier {
107*3e12c5d1SDavid du Colombier 	char buf[100];
108*3e12c5d1SDavid du Colombier 	char *cp = buf;
109*3e12c5d1SDavid du Colombier 	while(*s)
110*3e12c5d1SDavid du Colombier 		*cp++ = *s++;
111*3e12c5d1SDavid du Colombier 	*cp++ = c;
112*3e12c5d1SDavid du Colombier 	*cp = '\0';
113*3e12c5d1SDavid du Colombier 	rcerror(buf);
114*3e12c5d1SDavid du Colombier }
115*3e12c5d1SDavid du Colombier 
116*3e12c5d1SDavid du Colombier static	void
cant(char * s)117*3e12c5d1SDavid du Colombier cant(char *s)
118*3e12c5d1SDavid du Colombier {
119*3e12c5d1SDavid du Colombier 	char buf[100];
120*3e12c5d1SDavid du Colombier 	strcpy(buf, "can't happen: ");
121*3e12c5d1SDavid du Colombier 	strcat(buf, s);
122*3e12c5d1SDavid du Colombier 	rcerror(buf);
123*3e12c5d1SDavid du Colombier }
124*3e12c5d1SDavid du Colombier 
125*3e12c5d1SDavid du Colombier static	void
pushand(Reinst * f,Reinst * l)126*3e12c5d1SDavid du Colombier pushand(Reinst *f, Reinst *l)
127*3e12c5d1SDavid du Colombier {
128*3e12c5d1SDavid du Colombier 	if(andp >= &andstack[NSTACK])
129*3e12c5d1SDavid du Colombier 		cant("operand stack overflow");
130*3e12c5d1SDavid du Colombier 	andp->first = f;
131*3e12c5d1SDavid du Colombier 	andp->last = l;
132*3e12c5d1SDavid du Colombier 	andp++;
133*3e12c5d1SDavid du Colombier }
134*3e12c5d1SDavid du Colombier 
135*3e12c5d1SDavid du Colombier static	void
pushator(int t)136*3e12c5d1SDavid du Colombier pushator(int t)
137*3e12c5d1SDavid du Colombier {
138*3e12c5d1SDavid du Colombier 	if(atorp >= &atorstack[NSTACK])
139*3e12c5d1SDavid du Colombier 		cant("operator stack overflow");
140*3e12c5d1SDavid du Colombier 	*atorp++ = t;
141*3e12c5d1SDavid du Colombier 	*subidp++ = cursubid;
142*3e12c5d1SDavid du Colombier }
143*3e12c5d1SDavid du Colombier 
144*3e12c5d1SDavid du Colombier static	Node*
popand(int op)145*3e12c5d1SDavid du Colombier popand(int op)
146*3e12c5d1SDavid du Colombier {
147*3e12c5d1SDavid du Colombier 	Reinst *inst;
148*3e12c5d1SDavid du Colombier 
149*3e12c5d1SDavid du Colombier 	if(andp <= &andstack[0]){
150*3e12c5d1SDavid du Colombier 		regerr2("missing operand for ", op);
151*3e12c5d1SDavid du Colombier 		inst = newinst(NOP);
152*3e12c5d1SDavid du Colombier 		pushand(inst,inst);
153*3e12c5d1SDavid du Colombier 	}
154*3e12c5d1SDavid du Colombier 	return --andp;
155*3e12c5d1SDavid du Colombier }
156*3e12c5d1SDavid du Colombier 
157*3e12c5d1SDavid du Colombier static	int
popator(void)158*3e12c5d1SDavid du Colombier popator(void)
159*3e12c5d1SDavid du Colombier {
160*3e12c5d1SDavid du Colombier 	if(atorp <= &atorstack[0])
161*3e12c5d1SDavid du Colombier 		cant("operator stack underflow");
162*3e12c5d1SDavid du Colombier 	--subidp;
163*3e12c5d1SDavid du Colombier 	return *--atorp;
164*3e12c5d1SDavid du Colombier }
165*3e12c5d1SDavid du Colombier 
166*3e12c5d1SDavid du Colombier static	void
evaluntil(int pri)167*3e12c5d1SDavid du Colombier evaluntil(int pri)
168*3e12c5d1SDavid du Colombier {
169*3e12c5d1SDavid du Colombier 	Node *op1, *op2;
170*3e12c5d1SDavid du Colombier 	Reinst *inst1, *inst2;
171*3e12c5d1SDavid du Colombier 
172*3e12c5d1SDavid du Colombier 	while(pri==RBRA || atorp[-1]>=pri){
173*3e12c5d1SDavid du Colombier 		switch(popator()){
174*3e12c5d1SDavid du Colombier 		default:
175*3e12c5d1SDavid du Colombier 			rcerror("unknown operator in evaluntil");
176*3e12c5d1SDavid du Colombier 			break;
177*3e12c5d1SDavid du Colombier 		case LBRA:		/* must have been RBRA */
178*3e12c5d1SDavid du Colombier 			op1 = popand('(');
179*3e12c5d1SDavid du Colombier 			inst2 = newinst(RBRA);
180*3e12c5d1SDavid du Colombier 			inst2->r.subid = *subidp;
181*3e12c5d1SDavid du Colombier 			op1->last->l.next = inst2;
182*3e12c5d1SDavid du Colombier 			inst1 = newinst(LBRA);
183*3e12c5d1SDavid du Colombier 			inst1->r.subid = *subidp;
184*3e12c5d1SDavid du Colombier 			inst1->l.next = op1->first;
185*3e12c5d1SDavid du Colombier 			pushand(inst1, inst2);
186*3e12c5d1SDavid du Colombier 			return;
187*3e12c5d1SDavid du Colombier 		case OR:
188*3e12c5d1SDavid du Colombier 			op2 = popand('|');
189*3e12c5d1SDavid du Colombier 			op1 = popand('|');
190*3e12c5d1SDavid du Colombier 			inst2 = newinst(NOP);
191*3e12c5d1SDavid du Colombier 			op2->last->l.next = inst2;
192*3e12c5d1SDavid du Colombier 			op1->last->l.next = inst2;
193*3e12c5d1SDavid du Colombier 			inst1 = newinst(OR);
194*3e12c5d1SDavid du Colombier 			inst1->r.right = op1->first;
195*3e12c5d1SDavid du Colombier 			inst1->l.left = op2->first;
196*3e12c5d1SDavid du Colombier 			pushand(inst1, inst2);
197*3e12c5d1SDavid du Colombier 			break;
198*3e12c5d1SDavid du Colombier 		case CAT:
199*3e12c5d1SDavid du Colombier 			op2 = popand(0);
200*3e12c5d1SDavid du Colombier 			op1 = popand(0);
201*3e12c5d1SDavid du Colombier 			op1->last->l.next = op2->first;
202*3e12c5d1SDavid du Colombier 			pushand(op1->first, op2->last);
203*3e12c5d1SDavid du Colombier 			break;
204*3e12c5d1SDavid du Colombier 		case STAR:
205*3e12c5d1SDavid du Colombier 			op2 = popand('*');
206*3e12c5d1SDavid du Colombier 			inst1 = newinst(OR);
207*3e12c5d1SDavid du Colombier 			op2->last->l.next = inst1;
208*3e12c5d1SDavid du Colombier 			inst1->r.right = op2->first;
209*3e12c5d1SDavid du Colombier 			pushand(inst1, inst1);
210*3e12c5d1SDavid du Colombier 			break;
211*3e12c5d1SDavid du Colombier 		case PLUS:
212*3e12c5d1SDavid du Colombier 			op2 = popand('+');
213*3e12c5d1SDavid du Colombier 			inst1 = newinst(OR);
214*3e12c5d1SDavid du Colombier 			op2->last->l.next = inst1;
215*3e12c5d1SDavid du Colombier 			inst1->r.right = op2->first;
216*3e12c5d1SDavid du Colombier 			pushand(op2->first, inst1);
217*3e12c5d1SDavid du Colombier 			break;
218*3e12c5d1SDavid du Colombier 		case QUEST:
219*3e12c5d1SDavid du Colombier 			op2 = popand('?');
220*3e12c5d1SDavid du Colombier 			inst1 = newinst(OR);
221*3e12c5d1SDavid du Colombier 			inst2 = newinst(NOP);
222*3e12c5d1SDavid du Colombier 			inst1->l.left = inst2;
223*3e12c5d1SDavid du Colombier 			inst1->r.right = op2->first;
224*3e12c5d1SDavid du Colombier 			op2->last->l.next = inst2;
225*3e12c5d1SDavid du Colombier 			pushand(inst1, inst2);
226*3e12c5d1SDavid du Colombier 			break;
227*3e12c5d1SDavid du Colombier 		}
228*3e12c5d1SDavid du Colombier 	}
229*3e12c5d1SDavid du Colombier }
230*3e12c5d1SDavid du Colombier 
231*3e12c5d1SDavid du Colombier static	Reprog*
optimize(Reprog * pp)232*3e12c5d1SDavid du Colombier optimize(Reprog *pp)
233*3e12c5d1SDavid du Colombier {
234*3e12c5d1SDavid du Colombier 	Reinst *inst, *target;
235*3e12c5d1SDavid du Colombier 	int size;
236*3e12c5d1SDavid du Colombier 	Reprog *npp;
237*3e12c5d1SDavid du Colombier 	int diff;
238*3e12c5d1SDavid du Colombier 
239*3e12c5d1SDavid du Colombier 	/*
240*3e12c5d1SDavid du Colombier 	 *  get rid of NOOP chains
241*3e12c5d1SDavid du Colombier 	 */
242*3e12c5d1SDavid du Colombier 	for(inst=pp->firstinst; inst->type!=END; inst++){
243*3e12c5d1SDavid du Colombier 		target = inst->l.next;
244*3e12c5d1SDavid du Colombier 		while(target->type == NOP)
245*3e12c5d1SDavid du Colombier 			target = target->l.next;
246*3e12c5d1SDavid du Colombier 		inst->l.next = target;
247*3e12c5d1SDavid du Colombier 	}
248*3e12c5d1SDavid du Colombier 
249*3e12c5d1SDavid du Colombier 	/*
250*3e12c5d1SDavid du Colombier 	 *  The original allocation is for an area larger than
251*3e12c5d1SDavid du Colombier 	 *  necessary.  Reallocate to the actual space used
252*3e12c5d1SDavid du Colombier 	 *  and then relocate the code.
253*3e12c5d1SDavid du Colombier 	 */
254*3e12c5d1SDavid du Colombier 	size = sizeof(Reprog) + (freep - pp->firstinst)*sizeof(Reinst);
255*3e12c5d1SDavid du Colombier 	npp = realloc(pp, size);
256*3e12c5d1SDavid du Colombier 	if(npp==0 || npp==pp)
257*3e12c5d1SDavid du Colombier 		return pp;
258*3e12c5d1SDavid du Colombier 	diff = (char *)npp - (char *)pp;
259*3e12c5d1SDavid du Colombier 	freep = (Reinst *)((char *)freep + diff);
260*3e12c5d1SDavid du Colombier 	for(inst=npp->firstinst; inst<freep; inst++){
261*3e12c5d1SDavid du Colombier 		switch(inst->type){
262*3e12c5d1SDavid du Colombier 		case OR:
263*3e12c5d1SDavid du Colombier 		case STAR:
264*3e12c5d1SDavid du Colombier 		case PLUS:
265*3e12c5d1SDavid du Colombier 		case QUEST:
266*3e12c5d1SDavid du Colombier 		case CCLASS:
267*3e12c5d1SDavid du Colombier 		case NCCLASS:
268*3e12c5d1SDavid du Colombier 			*(char **)&inst->r.right += diff;
269*3e12c5d1SDavid du Colombier 			break;
270*3e12c5d1SDavid du Colombier 		}
271*3e12c5d1SDavid du Colombier 		*(char **)&inst->l.left += diff;
272*3e12c5d1SDavid du Colombier 	}
273*3e12c5d1SDavid du Colombier 	*(char **)&npp->startinst += diff;
274*3e12c5d1SDavid du Colombier 	return npp;
275*3e12c5d1SDavid du Colombier }
276*3e12c5d1SDavid du Colombier 
277*3e12c5d1SDavid du Colombier #ifdef	DEBUG
278*3e12c5d1SDavid du Colombier static	void
dumpstack(void)279*3e12c5d1SDavid du Colombier dumpstack(void){
280*3e12c5d1SDavid du Colombier 	Node *stk;
281*3e12c5d1SDavid du Colombier 	int *ip;
282*3e12c5d1SDavid du Colombier 
283*3e12c5d1SDavid du Colombier 	print("operators\n");
284*3e12c5d1SDavid du Colombier 	for(ip=atorstack; ip<atorp; ip++)
285*3e12c5d1SDavid du Colombier 		print("0%o\n", *ip);
286*3e12c5d1SDavid du Colombier 	print("operands\n");
287*3e12c5d1SDavid du Colombier 	for(stk=andstack; stk<andp; stk++)
288*3e12c5d1SDavid du Colombier 		print("0%o\t0%o\n", stk->first->type, stk->last->type);
289*3e12c5d1SDavid du Colombier }
290*3e12c5d1SDavid du Colombier 
291*3e12c5d1SDavid du Colombier static	void
dump(Reprog * pp)292*3e12c5d1SDavid du Colombier dump(Reprog *pp)
293*3e12c5d1SDavid du Colombier {
294*3e12c5d1SDavid du Colombier 	Reinst *l;
295*3e12c5d1SDavid du Colombier 	wchar_t *p;
296*3e12c5d1SDavid du Colombier 
297*3e12c5d1SDavid du Colombier 	l = pp->firstinst;
298*3e12c5d1SDavid du Colombier 	do{
299*3e12c5d1SDavid du Colombier 		print("%d:\t0%o\t%d\t%d", l-pp->firstinst, l->type,
300*3e12c5d1SDavid du Colombier 			l->l.left-pp->firstinst, l->l.right-pp->firstinst);
301*3e12c5d1SDavid du Colombier 		if(l->type == RUNE)
302*3e12c5d1SDavid du Colombier 			print("\t%C\n", l->r);
303*3e12c5d1SDavid du Colombier 		else if(l->type == CCLASS || l->type == NCCLASS){
304*3e12c5d1SDavid du Colombier 			print("\t[");
305*3e12c5d1SDavid du Colombier 			if(l->type == NCCLASS)
306*3e12c5d1SDavid du Colombier 				print("^");
307*3e12c5d1SDavid du Colombier 			for(p = l->r.cp->spans; p < l->r.cp->end; p += 2)
308*3e12c5d1SDavid du Colombier 				if(p[0] == p[1])
309*3e12c5d1SDavid du Colombier 					print("%C", p[0]);
310*3e12c5d1SDavid du Colombier 				else
311*3e12c5d1SDavid du Colombier 					print("%C-%C", p[0], p[1]);
312*3e12c5d1SDavid du Colombier 			print("]\n");
313*3e12c5d1SDavid du Colombier 		} else
314*3e12c5d1SDavid du Colombier 			print("\n");
315*3e12c5d1SDavid du Colombier 	}while(l++->type);
316*3e12c5d1SDavid du Colombier }
317*3e12c5d1SDavid du Colombier #endif
318*3e12c5d1SDavid du Colombier 
319*3e12c5d1SDavid du Colombier static	Reclass*
newclass(void)320*3e12c5d1SDavid du Colombier newclass(void)
321*3e12c5d1SDavid du Colombier {
322*3e12c5d1SDavid du Colombier 	if(nclass >= NCLASS)
323*3e12c5d1SDavid du Colombier 		regerr2("too many character classes; limit", NCLASS+'0');
324*3e12c5d1SDavid du Colombier 	return &(classp[nclass++]);
325*3e12c5d1SDavid du Colombier }
326*3e12c5d1SDavid du Colombier 
327*3e12c5d1SDavid du Colombier static	int
nextc(wchar_t * rp)328*3e12c5d1SDavid du Colombier nextc(wchar_t *rp)
329*3e12c5d1SDavid du Colombier {
330*3e12c5d1SDavid du Colombier 	int n;
331*3e12c5d1SDavid du Colombier 
332*3e12c5d1SDavid du Colombier 	if(lexdone){
333*3e12c5d1SDavid du Colombier 		*rp = 0;
334*3e12c5d1SDavid du Colombier 		return 1;
335*3e12c5d1SDavid du Colombier 	}
336*3e12c5d1SDavid du Colombier 	n = mbtowc(rp, exprp, MB_CUR_MAX);
337*3e12c5d1SDavid du Colombier 	if (n <= 0)
338*3e12c5d1SDavid du Colombier 		n = 1;
339*3e12c5d1SDavid du Colombier 	exprp += n;
340*3e12c5d1SDavid du Colombier 	if(*rp == L'\\'){
341*3e12c5d1SDavid du Colombier 		n = mbtowc(rp, exprp, MB_CUR_MAX);
342*3e12c5d1SDavid du Colombier 		if (n <= 0)
343*3e12c5d1SDavid du Colombier 			n = 1;
344*3e12c5d1SDavid du Colombier 		exprp += n;
345*3e12c5d1SDavid du Colombier 		return 1;
346*3e12c5d1SDavid du Colombier 	}
347*3e12c5d1SDavid du Colombier 	if(*rp == 0)
348*3e12c5d1SDavid du Colombier 		lexdone = 1;
349*3e12c5d1SDavid du Colombier 	return 0;
350*3e12c5d1SDavid du Colombier }
351*3e12c5d1SDavid du Colombier 
352*3e12c5d1SDavid du Colombier static	int
lex(int literal,int dot_type)353*3e12c5d1SDavid du Colombier lex(int literal, int dot_type)
354*3e12c5d1SDavid du Colombier {
355*3e12c5d1SDavid du Colombier 	int quoted;
356*3e12c5d1SDavid du Colombier 
357*3e12c5d1SDavid du Colombier 	quoted = nextc(&yyrune);
358*3e12c5d1SDavid du Colombier 	if(literal || quoted){
359*3e12c5d1SDavid du Colombier 		if(yyrune == 0)
360*3e12c5d1SDavid du Colombier 			return END;
361*3e12c5d1SDavid du Colombier 		return RUNE;
362*3e12c5d1SDavid du Colombier 	}
363*3e12c5d1SDavid du Colombier 
364*3e12c5d1SDavid du Colombier 	switch(yyrune){
365*3e12c5d1SDavid du Colombier 	case 0:
366*3e12c5d1SDavid du Colombier 		return END;
367*3e12c5d1SDavid du Colombier 	case L'*':
368*3e12c5d1SDavid du Colombier 		return STAR;
369*3e12c5d1SDavid du Colombier 	case L'?':
370*3e12c5d1SDavid du Colombier 		return QUEST;
371*3e12c5d1SDavid du Colombier 	case L'+':
372*3e12c5d1SDavid du Colombier 		return PLUS;
373*3e12c5d1SDavid du Colombier 	case L'|':
374*3e12c5d1SDavid du Colombier 		return OR;
375*3e12c5d1SDavid du Colombier 	case L'.':
376*3e12c5d1SDavid du Colombier 		return dot_type;
377*3e12c5d1SDavid du Colombier 	case L'(':
378*3e12c5d1SDavid du Colombier 		return LBRA;
379*3e12c5d1SDavid du Colombier 	case L')':
380*3e12c5d1SDavid du Colombier 		return RBRA;
381*3e12c5d1SDavid du Colombier 	case L'^':
382*3e12c5d1SDavid du Colombier 		return BOL;
383*3e12c5d1SDavid du Colombier 	case L'$':
384*3e12c5d1SDavid du Colombier 		return EOL;
385*3e12c5d1SDavid du Colombier 	case L'[':
386*3e12c5d1SDavid du Colombier 		return bldcclass();
387*3e12c5d1SDavid du Colombier 	}
388*3e12c5d1SDavid du Colombier 	return RUNE;
389*3e12c5d1SDavid du Colombier }
390*3e12c5d1SDavid du Colombier 
391*3e12c5d1SDavid du Colombier static int
bldcclass(void)392*3e12c5d1SDavid du Colombier bldcclass(void)
393*3e12c5d1SDavid du Colombier {
394*3e12c5d1SDavid du Colombier 	int type;
395*3e12c5d1SDavid du Colombier 	wchar_t r[NCCRUNE];
396*3e12c5d1SDavid du Colombier 	wchar_t *p, *ep, *np;
397*3e12c5d1SDavid du Colombier 	wchar_t rune;
398*3e12c5d1SDavid du Colombier 	int quoted;
399*3e12c5d1SDavid du Colombier 
400*3e12c5d1SDavid du Colombier 	/* we have already seen the '[' */
401*3e12c5d1SDavid du Colombier 	type = CCLASS;
402*3e12c5d1SDavid du Colombier 	yyclassp = newclass();
403*3e12c5d1SDavid du Colombier 
404*3e12c5d1SDavid du Colombier 	/* look ahead for negation */
405*3e12c5d1SDavid du Colombier 	ep = r;
406*3e12c5d1SDavid du Colombier 	quoted = nextc(&rune);
407*3e12c5d1SDavid du Colombier 	if(!quoted && rune == L'^'){
408*3e12c5d1SDavid du Colombier 		type = NCCLASS;
409*3e12c5d1SDavid du Colombier 		quoted = nextc(&rune);
410*3e12c5d1SDavid du Colombier 		*ep++ = L'\n';
411*3e12c5d1SDavid du Colombier 		*ep++ = L'\n';
412*3e12c5d1SDavid du Colombier 	}
413*3e12c5d1SDavid du Colombier 
414*3e12c5d1SDavid du Colombier 	/* parse class into a set of spans */
415*3e12c5d1SDavid du Colombier 	for(; ep<&r[NCCRUNE];){
416*3e12c5d1SDavid du Colombier 		if(rune == 0){
417*3e12c5d1SDavid du Colombier 			rcerror("malformed '[]'");
418*3e12c5d1SDavid du Colombier 			return 0;
419*3e12c5d1SDavid du Colombier 		}
420*3e12c5d1SDavid du Colombier 		if(!quoted && rune == L']')
421*3e12c5d1SDavid du Colombier 			break;
422*3e12c5d1SDavid du Colombier 		if(!quoted && rune == L'-'){
423*3e12c5d1SDavid du Colombier 			if(ep == r){
424*3e12c5d1SDavid du Colombier 				rcerror("malformed '[]'");
425*3e12c5d1SDavid du Colombier 				return 0;
426*3e12c5d1SDavid du Colombier 			}
427*3e12c5d1SDavid du Colombier 			quoted = nextc(&rune);
428*3e12c5d1SDavid du Colombier 			if((!quoted && rune == L']') || rune == 0){
429*3e12c5d1SDavid du Colombier 				rcerror("malformed '[]'");
430*3e12c5d1SDavid du Colombier 				return 0;
431*3e12c5d1SDavid du Colombier 			}
432*3e12c5d1SDavid du Colombier 			*(ep-1) = rune;
433*3e12c5d1SDavid du Colombier 		} else {
434*3e12c5d1SDavid du Colombier 			*ep++ = rune;
435*3e12c5d1SDavid du Colombier 			*ep++ = rune;
436*3e12c5d1SDavid du Colombier 		}
437*3e12c5d1SDavid du Colombier 		quoted = nextc(&rune);
438*3e12c5d1SDavid du Colombier 	}
439*3e12c5d1SDavid du Colombier 
440*3e12c5d1SDavid du Colombier 	/* sort on span start */
441*3e12c5d1SDavid du Colombier 	for(p = r; p < ep; p += 2){
442*3e12c5d1SDavid du Colombier 		for(np = p; np < ep; np += 2)
443*3e12c5d1SDavid du Colombier 			if(*np < *p){
444*3e12c5d1SDavid du Colombier 				rune = np[0];
445*3e12c5d1SDavid du Colombier 				np[0] = p[0];
446*3e12c5d1SDavid du Colombier 				p[0] = rune;
447*3e12c5d1SDavid du Colombier 				rune = np[1];
448*3e12c5d1SDavid du Colombier 				np[1] = p[1];
449*3e12c5d1SDavid du Colombier 				p[1] = rune;
450*3e12c5d1SDavid du Colombier 			}
451*3e12c5d1SDavid du Colombier 	}
452*3e12c5d1SDavid du Colombier 
453*3e12c5d1SDavid du Colombier 	/* merge spans */
454*3e12c5d1SDavid du Colombier 	np = yyclassp->spans;
455*3e12c5d1SDavid du Colombier 	p = r;
456*3e12c5d1SDavid du Colombier 	if(r == ep)
457*3e12c5d1SDavid du Colombier 		yyclassp->end = np;
458*3e12c5d1SDavid du Colombier 	else {
459*3e12c5d1SDavid du Colombier 		np[0] = *p++;
460*3e12c5d1SDavid du Colombier 		np[1] = *p++;
461*3e12c5d1SDavid du Colombier 		for(; p < ep; p += 2)
462*3e12c5d1SDavid du Colombier 			if(p[0] <= np[1]){
463*3e12c5d1SDavid du Colombier 				if(p[1] > np[1])
464*3e12c5d1SDavid du Colombier 					np[1] = p[1];
465*3e12c5d1SDavid du Colombier 			} else {
466*3e12c5d1SDavid du Colombier 				np += 2;
467*3e12c5d1SDavid du Colombier 				np[0] = p[0];
468*3e12c5d1SDavid du Colombier 				np[1] = p[1];
469*3e12c5d1SDavid du Colombier 			}
470*3e12c5d1SDavid du Colombier 		yyclassp->end = np+2;
471*3e12c5d1SDavid du Colombier 	}
472*3e12c5d1SDavid du Colombier 
473*3e12c5d1SDavid du Colombier 	return type;
474*3e12c5d1SDavid du Colombier }
475*3e12c5d1SDavid du Colombier 
476*3e12c5d1SDavid du Colombier static	Reprog*
regcomp1(char * s,int literal,int dot_type)477*3e12c5d1SDavid du Colombier regcomp1(char *s, int literal, int dot_type)
478*3e12c5d1SDavid du Colombier {
479*3e12c5d1SDavid du Colombier 	int token;
480*3e12c5d1SDavid du Colombier 	Reprog *pp;
481*3e12c5d1SDavid du Colombier 
482*3e12c5d1SDavid du Colombier 	/* get memory for the program */
483*3e12c5d1SDavid du Colombier 	pp = malloc(sizeof(Reprog) + 6*sizeof(Reinst)*strlen(s));
484*3e12c5d1SDavid du Colombier 	if(pp == 0){
485*3e12c5d1SDavid du Colombier 		regerror("out of memory");
486*3e12c5d1SDavid du Colombier 		return 0;
487*3e12c5d1SDavid du Colombier 	}
488*3e12c5d1SDavid du Colombier 	freep = pp->firstinst;
489*3e12c5d1SDavid du Colombier 	classp = pp->class;
490*3e12c5d1SDavid du Colombier 	errors = 0;
491*3e12c5d1SDavid du Colombier 
492*3e12c5d1SDavid du Colombier 	if(setjmp(regkaboom))
493*3e12c5d1SDavid du Colombier 		goto out;
494*3e12c5d1SDavid du Colombier 
495*3e12c5d1SDavid du Colombier 	/* go compile the sucker */
496*3e12c5d1SDavid du Colombier 	lexdone = 0;
497*3e12c5d1SDavid du Colombier 	exprp = s;
498*3e12c5d1SDavid du Colombier 	nclass = 0;
499*3e12c5d1SDavid du Colombier 	nbra = 0;
500*3e12c5d1SDavid du Colombier 	atorp = atorstack;
501*3e12c5d1SDavid du Colombier 	andp = andstack;
502*3e12c5d1SDavid du Colombier 	subidp = subidstack;
503*3e12c5d1SDavid du Colombier 	lastwasand = FALSE;
504*3e12c5d1SDavid du Colombier 	cursubid = 0;
505*3e12c5d1SDavid du Colombier 
506*3e12c5d1SDavid du Colombier 	/* Start with a low priority operator to prime parser */
507*3e12c5d1SDavid du Colombier 	pushator(START-1);
508*3e12c5d1SDavid du Colombier 	while((token = lex(literal, dot_type)) != END){
509*3e12c5d1SDavid du Colombier 		if((token&0300) == OPERATOR)
510*3e12c5d1SDavid du Colombier 			operator(token);
511*3e12c5d1SDavid du Colombier 		else
512*3e12c5d1SDavid du Colombier 			operand(token);
513*3e12c5d1SDavid du Colombier 	}
514*3e12c5d1SDavid du Colombier 
515*3e12c5d1SDavid du Colombier 	/* Close with a low priority operator */
516*3e12c5d1SDavid du Colombier 	evaluntil(START);
517*3e12c5d1SDavid du Colombier 
518*3e12c5d1SDavid du Colombier 	/* Force END */
519*3e12c5d1SDavid du Colombier 	operand(END);
520*3e12c5d1SDavid du Colombier 	evaluntil(START);
521*3e12c5d1SDavid du Colombier #ifdef DEBUG
522*3e12c5d1SDavid du Colombier 	dumpstack();
523*3e12c5d1SDavid du Colombier #endif
524*3e12c5d1SDavid du Colombier 	if(nbra)
525*3e12c5d1SDavid du Colombier 		rcerror("unmatched left paren");
526*3e12c5d1SDavid du Colombier 	--andp;	/* points to first and only operand */
527*3e12c5d1SDavid du Colombier 	pp->startinst = andp->first;
528*3e12c5d1SDavid du Colombier #ifdef DEBUG
529*3e12c5d1SDavid du Colombier 	dump(pp);
530*3e12c5d1SDavid du Colombier #endif
531*3e12c5d1SDavid du Colombier 	pp = optimize(pp);
532*3e12c5d1SDavid du Colombier #ifdef DEBUG
533*3e12c5d1SDavid du Colombier 	print("start: %d\n", andp->first-pp->firstinst);
534*3e12c5d1SDavid du Colombier 	dump(pp);
535*3e12c5d1SDavid du Colombier #endif
536*3e12c5d1SDavid du Colombier out:
537*3e12c5d1SDavid du Colombier 	if(errors){
538*3e12c5d1SDavid du Colombier 		free(pp);
539*3e12c5d1SDavid du Colombier 		pp = 0;
540*3e12c5d1SDavid du Colombier 	}
541*3e12c5d1SDavid du Colombier 	return pp;
542*3e12c5d1SDavid du Colombier }
543*3e12c5d1SDavid du Colombier 
544*3e12c5d1SDavid du Colombier extern	Reprog*
regcomp(char * s)545*3e12c5d1SDavid du Colombier regcomp(char *s)
546*3e12c5d1SDavid du Colombier {
547*3e12c5d1SDavid du Colombier 	return regcomp1(s, 0, ANY);
548*3e12c5d1SDavid du Colombier }
549*3e12c5d1SDavid du Colombier 
550*3e12c5d1SDavid du Colombier extern	Reprog*
regcomplit(char * s)551*3e12c5d1SDavid du Colombier regcomplit(char *s)
552*3e12c5d1SDavid du Colombier {
553*3e12c5d1SDavid du Colombier 	return regcomp1(s, 1, ANY);
554*3e12c5d1SDavid du Colombier }
555*3e12c5d1SDavid du Colombier 
556*3e12c5d1SDavid du Colombier extern	Reprog*
regcompnl(char * s)557*3e12c5d1SDavid du Colombier regcompnl(char *s)
558*3e12c5d1SDavid du Colombier {
559*3e12c5d1SDavid du Colombier 	return regcomp1(s, 0, ANYNL);
560*3e12c5d1SDavid du Colombier }
561