|
|
1.1 root 1: #include "regprog.h"
2:
3: /*
4: * Parser Information
5: */
6: typedef struct Node{
7: Inst *first;
8: Inst *last;
9: }Node;
10: #define NSTACK 20
11: static Node andstack[NSTACK];
12: static Node *andp;
13: static int atorstack[NSTACK];
14: static int *atorp;
15: static int cursubid; /* id of current subexpression */
16: static int subidstack[NSTACK]; /* parallel to atorstack */
17: static int *subidp;
18: static int lastwasand; /* Last token was operand */
19: static int nbra;
20: static char *exprp; /* pointer to next character in source expression */
21: static int nclass;
22: static Class *classp;
23: static Inst *freep;
24: static int errors;
25:
26: /* predeclared crap */
27: static void operator();
28: static void pushand();
29: static void pushator();
30: static void evaluntil();
31: static void bldcclass();
32:
33: static void
34: rcerror(s)
35: char *s;
36: {
37: errors++;
38: regerror(s);
39: }
40:
41: static Inst *
42: newinst(t)
43: int t;
44: {
45: freep->type=t;
46: freep->left=0;
47: freep->right=0;
48: return freep++;
49: }
50:
51: static void
52: operand(t)
53: int t;
54: {
55: register Inst *i;
56: if(lastwasand)
57: operator(CAT); /* catenate is implicit */
58: i=newinst(t);
59: if(t==CCLASS) /* ugh */
60: i->right=(Inst *)&(classp[nclass-1]); /* UGH! */
61: pushand(i, i);
62: lastwasand=TRUE;
63: }
64:
65: static void
66: operator(t)
67: int t;
68: {
69: if(t==RBRA && --nbra<0)
70: rcerror("unmatched right paren");
71: if(t==LBRA) {
72: if (++cursubid >= NSUBEXP)
73: rcerror ("too many subexpressions");
74: nbra++;
75: if (lastwasand)
76: operator(CAT);
77: } else
78: evaluntil(t);
79: if(t!=RBRA)
80: pushator(t);
81: lastwasand=FALSE;
82: if(t==STAR || t==QUEST || t==PLUS || t==RBRA)
83: lastwasand=TRUE; /* these look like operands */
84: }
85:
86: static void
87: regerr2(s, c)
88: char *s;
89: {
90: char buf[100];
91: char *cp = buf;
92: while(*s)
93: *cp++ = *s++;
94: *cp++ = c;
95: *cp = '\0';
96: rcerror(buf);
97: }
98:
99: static void
100: cant(s)
101: char *s;
102: {
103: char buf[100];
104: strcpy(buf, "can't happen: ");
105: strcat(buf, s);
106: rcerror(buf);
107: }
108:
109: static void
110: pushand(f, l)
111: Inst *f, *l;
112: {
113: if(andp >= &andstack[NSTACK])
114: cant("operand stack overflow");
115: andp->first=f;
116: andp->last=l;
117: andp++;
118: }
119:
120: static void
121: pushator(t)
122: int t;
123: {
124: if(atorp >= &atorstack[NSTACK])
125: cant("operator stack overflow");
126: *atorp++=t;
127: *subidp++=cursubid;
128: }
129:
130: static Node *
131: popand(op)
132: {
133: if(andp <= &andstack[0])
134: regerr2("missing operand for", op);
135: return --andp;
136: }
137:
138: static int
139: popator()
140: {
141: if(atorp <= &atorstack[0])
142: cant("operator stack underflow");
143: --subidp;
144: return *--atorp;
145: }
146:
147: static void
148: evaluntil(pri)
149: register pri;
150: {
151: register Node *op1, *op2;
152: register Inst *inst1, *inst2;
153:
154: while(pri==RBRA || atorp[-1]>=pri){
155: switch(popator()){
156: default:
157: rcerror("unknown operator in evaluntil");
158: break;
159: case LBRA: /* must have been RBRA */
160: op1=popand(0);
161: inst2=newinst(RBRA);
162: inst2->subid = *subidp;
163: op1->last->next = inst2;
164: inst1=newinst(LBRA);
165: inst1->subid = *subidp;
166: inst1->next=op1->first;
167: pushand(inst1, inst2);
168: return;
169: case OR:
170: op2=popand('|');
171: op1=popand('|');
172: inst2=newinst(NOP);
173: op2->last->next=inst2;
174: op1->last->next=inst2;
175: inst1=newinst(OR);
176: inst1->right=op1->first;
177: inst1->left=op2->first;
178: pushand(inst1, inst2);
179: break;
180: case CAT:
181: op2=popand(0);
182: op1=popand(0);
183: op1->last->next=op2->first;
184: pushand(op1->first, op2->last);
185: break;
186: case STAR:
187: op2=popand('*');
188: inst1=newinst(OR);
189: op2->last->next=inst1;
190: inst1->right=op2->first;
191: pushand(inst1, inst1);
192: break;
193: case PLUS:
194: op2=popand('+');
195: inst1=newinst(OR);
196: op2->last->next=inst1;
197: inst1->right=op2->first;
198: pushand(op2->first, inst1);
199: break;
200: case QUEST:
201: op2=popand('?');
202: inst1=newinst(OR);
203: inst2=newinst(NOP);
204: inst1->left=inst2;
205: inst1->right=op2->first;
206: op2->last->next=inst2;
207: pushand(inst1, inst2);
208: break;
209: }
210: }
211: }
212:
213: static void
214: optimize(pp)
215: Prog *pp;
216: {
217: register Inst *inst, *target;
218:
219: for(inst=pp->firstinst; inst->type!=END; inst++){
220: target=inst->next;
221: while(target->type == NOP)
222: target=target->next;
223: inst->next=target;
224: }
225: }
226:
227: #ifdef DEBUG
228: static void
229: dumpstack(){
230: Node *stk;
231: int *ip;
232:
233: printf("operators\n");
234: for(ip=atorstack; ip<atorp; ip++)
235: printf("0%o\n", *ip);
236: printf("operands\n");
237: for(stk=andstack; stk<andp; stk++)
238: printf("0%o\t0%o\n", stk->first->type, stk->last->type);
239: }
240:
241: static void
242: dump(pp)
243: Prog *pp;
244: {
245: Inst *l;
246:
247: l=pp->firstinst;
248: do{
249: printf("%d:\t0%o\t%d\t%d\n", l-pp->firstinst, l->type,
250: l->left-pp->firstinst, l->right-pp->firstinst);
251: }while(l++->type);
252: }
253: #endif
254:
255: static void
256: startlex(s)
257: char *s;
258: {
259: exprp=s;
260: nclass=0;
261: nbra=0;
262: }
263:
264: static Class *
265: newclass(){
266: register Class *p;
267: register n;
268:
269: if(nclass >= NCLASS)
270: regerr2("too many character classes; limit", NCLASS+'0');
271: p=&(classp[nclass++]);
272: for(n=0; n<16; n++)
273: p->map[n]=0;
274: return p;
275: }
276:
277: static int
278: lex(){
279: register c= *exprp++;
280:
281: switch(c){
282: case '\\':
283: if(*exprp)
284: c= *exprp++;
285: break;
286: case 0:
287: c=END;
288: --exprp; /* In case we come here again */
289: break;
290: case '*':
291: c=STAR;
292: break;
293: case '?':
294: c=QUEST;
295: break;
296: case '+':
297: c=PLUS;
298: break;
299: case '|':
300: c=OR;
301: break;
302: case '.':
303: c=ANY;
304: break;
305: case '(':
306: c=LBRA;
307: break;
308: case ')':
309: c=RBRA;
310: break;
311: case '^':
312: c=BOL;
313: break;
314: case '$':
315: c=EOL;
316: break;
317: case '[':
318: c=CCLASS;
319: bldcclass();
320: break;
321: }
322: return c;
323: }
324:
325: static int
326: nextc(){
327: if(exprp[0]==0 || (exprp[0]=='\\' && exprp[1]==0))
328: rcerror("malformed '[]'");
329: if(exprp[0]=='\\'){
330: exprp++;
331: return *exprp++|0200;
332: }
333: return *exprp++;
334: }
335:
336: static void
337: bldcclass(){
338: register c1, c2;
339: register Class *classp;
340: register negate=FALSE;
341:
342: classp=newclass();
343: /* we have already seen the '[' */
344: if(*exprp=='^'){
345: negate=TRUE;
346: exprp++;
347: }
348: while((c1=c2=nextc()) != ']'){
349: if(*exprp=='-'){
350: exprp++; /* eat '-' */
351: if((c2=nextc()) == ']')
352: rcerror("malformed '[]'");
353: }
354: for((c1&=0177), (c2&=0177); c1<=c2; c1++)
355: classp->map[c1/8] |= 1<<(c1&07);
356: }
357: if(negate)
358: for(c1=0; c1<16; c1++)
359: classp->map[c1]^=0377;
360: classp->map[0]&=376; /* exclude NUL */
361: }
362:
363: extern char *
364: regcomp(s)
365: char *s;
366: {
367: register token;
368: Prog *pp;
369:
370: /* get memory for the program */
371: pp = (Prog *)malloc(sizeof(Prog) + sizeof(Inst)*strlen(s));
372: if (pp == NULL) {
373: rcerror("out of memory");
374: return NULL;
375: }
376: freep = pp->firstinst;
377: classp = pp->class;
378: errors = 0;
379:
380: /* go compile the sucker */
381: startlex(s);
382: atorp=atorstack;
383: andp=andstack;
384: subidp=subidstack;
385: lastwasand=FALSE;
386: cursubid=0;
387:
388: /* Start with a low priority operator to prime parser */
389: pushator(START-1);
390: while((token=lex()) != END){
391: if((token&0300) == OPERATOR)
392: operator(token);
393: else
394: operand(token);
395: }
396:
397: /* Close with a low priority operator */
398: evaluntil(START);
399:
400: /* Force END */
401: operand(END);
402: evaluntil(START);
403: #ifdef DEBUG
404: dumpstack();
405: #endif
406: if(nbra)
407: rcerror("unmatched left paren");
408: --andp; /* points to first and only operand */
409: pp->startinst=andp->first;
410: #ifdef DEBUG
411: dump(pp);
412: #endif
413: optimize(pp);
414: #ifdef DEBUG
415: printf("start: %d\n", andp->first-pp->firstinst);
416: dump(pp);
417: #endif
418: if (errors) {
419: free(pp);
420: pp = NULL;
421: }
422: return (char *)pp;
423: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.