tregexp.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tregexp.c (15575B) | |
--- | |
1 #include "sam.h" | |
2 | |
3 Rangeset sel; | |
4 String lastregexp; | |
5 /* | |
6 * Machine Information | |
7 */ | |
8 typedef struct Inst Inst; | |
9 | |
10 struct Inst | |
11 { | |
12 long type; /* < OPERATOR ==> literal, otherwise ac… | |
13 union { | |
14 int rsid; | |
15 int rsubid; | |
16 int class; | |
17 struct Inst *rother; | |
18 struct Inst *rright; | |
19 } r; | |
20 union{ | |
21 struct Inst *lleft; | |
22 struct Inst *lnext; | |
23 } l; | |
24 }; | |
25 #define sid r.rsid | |
26 #define subid r.rsubid | |
27 #define rclass r.class | |
28 #define other r.rother | |
29 #define right r.rright | |
30 #define left l.lleft | |
31 #define next l.lnext | |
32 | |
33 #define NPROG 1024 | |
34 Inst program[NPROG]; | |
35 Inst *progp; | |
36 Inst *startinst; /* First inst. of program; might not be p… | |
37 Inst *bstartinst; /* same for backwards machine */ | |
38 | |
39 typedef struct Ilist Ilist; | |
40 struct Ilist | |
41 { | |
42 Inst *inst; /* Instruction of the thread */ | |
43 Rangeset se; | |
44 Posn startp; /* first char of match */ | |
45 }; | |
46 | |
47 #define NLIST 127 | |
48 | |
49 Ilist *tl, *nl; /* This list, next list */ | |
50 Ilist list[2][NLIST+1]; /* +1 for trailing null */ | |
51 static Rangeset sempty; | |
52 | |
53 /* | |
54 * Actions and Tokens | |
55 * | |
56 * 0x10000xx are operators, value == precedence | |
57 * 0x20000xx are tokens, i.e. operands for operators | |
58 */ | |
59 #define OPERATOR 0x1000000 /* Bit set in all operat… | |
60 #define START (OPERATOR+0) /* Start, used f… | |
61 #define RBRA (OPERATOR+1) /* Right bracket,… | |
62 #define LBRA (OPERATOR+2) /* Left bracket, … | |
63 #define OR (OPERATOR+3) /* Alternation, | */ | |
64 #define CAT (OPERATOR+4) /* Concatentation,… | |
65 #define STAR (OPERATOR+5) /* Closure, * */ | |
66 #define PLUS (OPERATOR+6) /* a+ == aa* */ | |
67 #define QUEST (OPERATOR+7) /* a? == a|nothi… | |
68 #define ANY 0x2000000 /* Any character but … | |
69 #define NOP (ANY+1) /* No operation, intern… | |
70 #define BOL (ANY+2) /* Beginning of line, ^… | |
71 #define EOL (ANY+3) /* End of line, $ */ | |
72 #define CCLASS (ANY+4) /* Character class, … | |
73 #define NCCLASS (ANY+5) /* Negated characte… | |
74 #define END (ANY+0x77) /* Terminate: match … | |
75 | |
76 #define ISATOR OPERATOR | |
77 #define ISAND ANY | |
78 | |
79 #define QUOTED 0x4000000 /* Bit set for \-ed lex ch… | |
80 | |
81 /* | |
82 * Parser Information | |
83 */ | |
84 typedef struct Node Node; | |
85 struct Node | |
86 { | |
87 Inst *first; | |
88 Inst *last; | |
89 }; | |
90 | |
91 #define NSTACK 20 | |
92 Node andstack[NSTACK]; | |
93 Node *andp; | |
94 int atorstack[NSTACK]; | |
95 int *atorp; | |
96 int lastwasand; /* Last token was operand */ | |
97 int cursubid; | |
98 int subidstack[NSTACK]; | |
99 int *subidp; | |
100 int backwards; | |
101 int nbra; | |
102 Rune *exprp; /* pointer to next character in sourc… | |
103 #define DCLASS 10 /* allocation increment */ | |
104 int nclass; /* number active */ | |
105 int Nclass; /* high water mark */ | |
106 Rune **class; | |
107 int negateclass; | |
108 | |
109 int addinst(Ilist *l, Inst *inst, Rangeset *sep); | |
110 void newmatch(Rangeset*); | |
111 void bnewmatch(Rangeset*); | |
112 void pushand(Inst*, Inst*); | |
113 void pushator(int); | |
114 Node *popand(int); | |
115 int popator(void); | |
116 void startlex(Rune*); | |
117 int lex(void); | |
118 void operator(int); | |
119 void operand(int); | |
120 void evaluntil(int); | |
121 void optimize(Inst*); | |
122 void bldcclass(void); | |
123 | |
124 void | |
125 regerror(Err e) | |
126 { | |
127 Strzero(&lastregexp); | |
128 error(e); | |
129 } | |
130 | |
131 void | |
132 regerror_c(Err e, int c) | |
133 { | |
134 Strzero(&lastregexp); | |
135 error_c(e, c); | |
136 } | |
137 | |
138 Inst * | |
139 newinst(int t) | |
140 { | |
141 if(progp >= &program[NPROG]) | |
142 regerror(Etoolong); | |
143 progp->type = t; | |
144 progp->left = 0; | |
145 progp->right = 0; | |
146 return progp++; | |
147 } | |
148 | |
149 Inst * | |
150 realcompile(Rune *s) | |
151 { | |
152 int token; | |
153 | |
154 startlex(s); | |
155 atorp = atorstack; | |
156 andp = andstack; | |
157 subidp = subidstack; | |
158 cursubid = 0; | |
159 lastwasand = FALSE; | |
160 /* Start with a low priority operator to prime parser */ | |
161 pushator(START-1); | |
162 while((token=lex()) != END){ | |
163 if((token&ISATOR) == OPERATOR) | |
164 operator(token); | |
165 else | |
166 operand(token); | |
167 } | |
168 /* Close with a low priority operator */ | |
169 evaluntil(START); | |
170 /* Force END */ | |
171 operand(END); | |
172 evaluntil(START); | |
173 if(nbra) | |
174 regerror(Eleftpar); | |
175 --andp; /* points to first and only operand */ | |
176 return andp->first; | |
177 } | |
178 | |
179 void | |
180 compile(String *s) | |
181 { | |
182 int i; | |
183 Inst *oprogp; | |
184 | |
185 if(Strcmp(s, &lastregexp)==0) | |
186 return; | |
187 for(i=0; i<nclass; i++) | |
188 free(class[i]); | |
189 nclass = 0; | |
190 progp = program; | |
191 backwards = FALSE; | |
192 startinst = realcompile(s->s); | |
193 optimize(program); | |
194 oprogp = progp; | |
195 backwards = TRUE; | |
196 bstartinst = realcompile(s->s); | |
197 optimize(oprogp); | |
198 Strduplstr(&lastregexp, s); | |
199 } | |
200 | |
201 void | |
202 operand(int t) | |
203 { | |
204 Inst *i; | |
205 if(lastwasand) | |
206 operator(CAT); /* catenate is implicit */ | |
207 i = newinst(t); | |
208 if(t == CCLASS){ | |
209 if(negateclass) | |
210 i->type = NCCLASS; /* UGH */ | |
211 i->rclass = nclass-1; /* UGH */ | |
212 } | |
213 pushand(i, i); | |
214 lastwasand = TRUE; | |
215 } | |
216 | |
217 void | |
218 operator(int t) | |
219 { | |
220 if(t==RBRA && --nbra<0) | |
221 regerror(Erightpar); | |
222 if(t==LBRA){ | |
223 /* | |
224 * if(++cursubid >= NSUBEXP) | |
225 * regerror(Esubexp); | |
226 */ | |
227 cursubid++; /* silently ignored */ | |
228 nbra++; | |
229 if(lastwasand) | |
230 operator(CAT); | |
231 }else | |
232 evaluntil(t); | |
233 if(t!=RBRA) | |
234 pushator(t); | |
235 lastwasand = FALSE; | |
236 if(t==STAR || t==QUEST || t==PLUS || t==RBRA) | |
237 lastwasand = TRUE; /* these look like operands */ | |
238 } | |
239 | |
240 void | |
241 cant(char *s) | |
242 { | |
243 char buf[100]; | |
244 | |
245 sprint(buf, "regexp: can't happen: %s", s); | |
246 panic(buf); | |
247 } | |
248 | |
249 void | |
250 pushand(Inst *f, Inst *l) | |
251 { | |
252 if(andp >= &andstack[NSTACK]) | |
253 cant("operand stack overflow"); | |
254 andp->first = f; | |
255 andp->last = l; | |
256 andp++; | |
257 } | |
258 | |
259 void | |
260 pushator(int t) | |
261 { | |
262 if(atorp >= &atorstack[NSTACK]) | |
263 cant("operator stack overflow"); | |
264 *atorp++=t; | |
265 if(cursubid >= NSUBEXP) | |
266 *subidp++= -1; | |
267 else | |
268 *subidp++=cursubid; | |
269 } | |
270 | |
271 Node * | |
272 popand(int op) | |
273 { | |
274 if(andp <= &andstack[0]) | |
275 if(op) | |
276 regerror_c(Emissop, op); | |
277 else | |
278 regerror(Ebadregexp); | |
279 return --andp; | |
280 } | |
281 | |
282 int | |
283 popator(void) | |
284 { | |
285 if(atorp <= &atorstack[0]) | |
286 cant("operator stack underflow"); | |
287 --subidp; | |
288 return *--atorp; | |
289 } | |
290 | |
291 void | |
292 evaluntil(int pri) | |
293 { | |
294 Node *op1, *op2, *t; | |
295 Inst *inst1, *inst2; | |
296 | |
297 while(pri==RBRA || atorp[-1]>=pri){ | |
298 switch(popator()){ | |
299 case LBRA: | |
300 op1 = popand('('); | |
301 inst2 = newinst(RBRA); | |
302 inst2->subid = *subidp; | |
303 op1->last->next = inst2; | |
304 inst1 = newinst(LBRA); | |
305 inst1->subid = *subidp; | |
306 inst1->next = op1->first; | |
307 pushand(inst1, inst2); | |
308 return; /* must have been RBRA */ | |
309 default: | |
310 panic("unknown regexp operator"); | |
311 break; | |
312 case OR: | |
313 op2 = popand('|'); | |
314 op1 = popand('|'); | |
315 inst2 = newinst(NOP); | |
316 op2->last->next = inst2; | |
317 op1->last->next = inst2; | |
318 inst1 = newinst(OR); | |
319 inst1->right = op1->first; | |
320 inst1->left = op2->first; | |
321 pushand(inst1, inst2); | |
322 break; | |
323 case CAT: | |
324 op2 = popand(0); | |
325 op1 = popand(0); | |
326 if(backwards && op2->first->type!=END) | |
327 t = op1, op1 = op2, op2 = t; | |
328 op1->last->next = op2->first; | |
329 pushand(op1->first, op2->last); | |
330 break; | |
331 case STAR: | |
332 op2 = popand('*'); | |
333 inst1 = newinst(OR); | |
334 op2->last->next = inst1; | |
335 inst1->right = op2->first; | |
336 pushand(inst1, inst1); | |
337 break; | |
338 case PLUS: | |
339 op2 = popand('+'); | |
340 inst1 = newinst(OR); | |
341 op2->last->next = inst1; | |
342 inst1->right = op2->first; | |
343 pushand(op2->first, inst1); | |
344 break; | |
345 case QUEST: | |
346 op2 = popand('?'); | |
347 inst1 = newinst(OR); | |
348 inst2 = newinst(NOP); | |
349 inst1->left = inst2; | |
350 inst1->right = op2->first; | |
351 op2->last->next = inst2; | |
352 pushand(inst1, inst2); | |
353 break; | |
354 } | |
355 } | |
356 } | |
357 | |
358 | |
359 void | |
360 optimize(Inst *start) | |
361 { | |
362 Inst *inst, *target; | |
363 | |
364 for(inst=start; inst->type!=END; inst++){ | |
365 target = inst->next; | |
366 while(target->type == NOP) | |
367 target = target->next; | |
368 inst->next = target; | |
369 } | |
370 } | |
371 | |
372 #ifdef DEBUG | |
373 void | |
374 dumpstack(void){ | |
375 Node *stk; | |
376 int *ip; | |
377 | |
378 dprint("operators\n"); | |
379 for(ip = atorstack; ip<atorp; ip++) | |
380 dprint("0%o\n", *ip); | |
381 dprint("operands\n"); | |
382 for(stk = andstack; stk<andp; stk++) | |
383 dprint("0%o\t0%o\n", stk->first->type, stk->last->type); | |
384 } | |
385 void | |
386 dump(void){ | |
387 Inst *l; | |
388 | |
389 l = program; | |
390 do{ | |
391 dprint("%d:\t0%o\t%d\t%d\n", l-program, l->type, | |
392 l->left-program, l->right-program); | |
393 }while(l++->type); | |
394 } | |
395 #endif | |
396 | |
397 void | |
398 startlex(Rune *s) | |
399 { | |
400 exprp = s; | |
401 nbra = 0; | |
402 } | |
403 | |
404 | |
405 int | |
406 lex(void){ | |
407 int c= *exprp++; | |
408 | |
409 switch(c){ | |
410 case '\\': | |
411 if(*exprp) | |
412 if((c= *exprp++)=='n') | |
413 c='\n'; | |
414 break; | |
415 case 0: | |
416 c = END; | |
417 --exprp; /* In case we come here again */ | |
418 break; | |
419 case '*': | |
420 c = STAR; | |
421 break; | |
422 case '?': | |
423 c = QUEST; | |
424 break; | |
425 case '+': | |
426 c = PLUS; | |
427 break; | |
428 case '|': | |
429 c = OR; | |
430 break; | |
431 case '.': | |
432 c = ANY; | |
433 break; | |
434 case '(': | |
435 c = LBRA; | |
436 break; | |
437 case ')': | |
438 c = RBRA; | |
439 break; | |
440 case '^': | |
441 c = BOL; | |
442 break; | |
443 case '$': | |
444 c = EOL; | |
445 break; | |
446 case '[': | |
447 c = CCLASS; | |
448 bldcclass(); | |
449 break; | |
450 } | |
451 return c; | |
452 } | |
453 | |
454 long | |
455 nextrec(void){ | |
456 if(exprp[0]==0 || (exprp[0]=='\\' && exprp[1]==0)) | |
457 regerror(Ebadclass); | |
458 if(exprp[0] == '\\'){ | |
459 exprp++; | |
460 if(*exprp=='n'){ | |
461 exprp++; | |
462 return '\n'; | |
463 } | |
464 return *exprp++|QUOTED; | |
465 } | |
466 return *exprp++; | |
467 } | |
468 | |
469 void | |
470 bldcclass(void) | |
471 { | |
472 long c1, c2, n, na; | |
473 Rune *classp; | |
474 | |
475 classp = emalloc(DCLASS*RUNESIZE); | |
476 n = 0; | |
477 na = DCLASS; | |
478 /* we have already seen the '[' */ | |
479 if(*exprp == '^'){ | |
480 classp[n++] = '\n'; /* don't match newline in neg… | |
481 negateclass = TRUE; | |
482 exprp++; | |
483 }else | |
484 negateclass = FALSE; | |
485 while((c1 = nextrec()) != ']'){ | |
486 if(c1 == '-'){ | |
487 Error: | |
488 free(classp); | |
489 regerror(Ebadclass); | |
490 } | |
491 if(n+4 >= na){ /* 3 runes plus NUL */ | |
492 na += DCLASS; | |
493 classp = erealloc(classp, na*RUNESIZE); | |
494 } | |
495 if(*exprp == '-'){ | |
496 exprp++; /* eat '-' */ | |
497 if((c2 = nextrec()) == ']') | |
498 goto Error; | |
499 classp[n+0] = Runemax; | |
500 classp[n+1] = c1; | |
501 classp[n+2] = c2; | |
502 n += 3; | |
503 }else | |
504 classp[n++] = c1 & ~QUOTED; | |
505 } | |
506 classp[n] = 0; | |
507 if(nclass == Nclass){ | |
508 Nclass += DCLASS; | |
509 class = erealloc(class, Nclass*sizeof(Rune*)); | |
510 } | |
511 class[nclass++] = classp; | |
512 } | |
513 | |
514 int | |
515 classmatch(int classno, int c, int negate) | |
516 { | |
517 Rune *p; | |
518 | |
519 p = class[classno]; | |
520 while(*p){ | |
521 if(*p == Runemax){ | |
522 if(p[1]<=c && c<=p[2]) | |
523 return !negate; | |
524 p += 3; | |
525 }else if(*p++ == c) | |
526 return !negate; | |
527 } | |
528 return negate; | |
529 } | |
530 | |
531 /* | |
532 * Note optimization in addinst: | |
533 * *l must be pending when addinst called; if *l has been looked | |
534 * at already, the optimization is a bug. | |
535 */ | |
536 int | |
537 addinst(Ilist *l, Inst *inst, Rangeset *sep) | |
538 { | |
539 Ilist *p; | |
540 | |
541 for(p = l; p->inst; p++){ | |
542 if(p->inst==inst){ | |
543 if((sep)->p[0].p1 < p->se.p[0].p1) | |
544 p->se= *sep; /* this would be bug… | |
545 return 0; /* It's already there */ | |
546 } | |
547 } | |
548 p->inst = inst; | |
549 p->se= *sep; | |
550 (p+1)->inst = 0; | |
551 return 1; | |
552 } | |
553 | |
554 int | |
555 execute(File *f, Posn startp, Posn eof) | |
556 { | |
557 int flag = 0; | |
558 Inst *inst; | |
559 Ilist *tlp; | |
560 Posn p = startp; | |
561 int nnl = 0, ntl; | |
562 int c; | |
563 int wrapped = 0; | |
564 int startchar = startinst->type<OPERATOR? startinst->type : 0; | |
565 | |
566 list[0][0].inst = list[1][0].inst = 0; | |
567 sel.p[0].p1 = -1; | |
568 /* Execute machine once for each character */ | |
569 for(;;p++){ | |
570 doloop: | |
571 c = filereadc(f, p); | |
572 if(p>=eof || c<0){ | |
573 switch(wrapped++){ | |
574 case 0: /* let loop run one more … | |
575 case 2: | |
576 break; | |
577 case 1: /* expired; wrap to begin… | |
578 if(sel.p[0].p1>=0 || eof!=INFINITY) | |
579 goto Return; | |
580 list[0][0].inst = list[1][0].inst = 0; | |
581 p = 0; | |
582 goto doloop; | |
583 default: | |
584 goto Return; | |
585 } | |
586 }else if(((wrapped && p>=startp) || sel.p[0].p1>0) && nn… | |
587 break; | |
588 /* fast check for first char */ | |
589 if(startchar && nnl==0 && c!=startchar) | |
590 continue; | |
591 tl = list[flag]; | |
592 nl = list[flag^=1]; | |
593 nl->inst = 0; | |
594 ntl = nnl; | |
595 nnl = 0; | |
596 if(sel.p[0].p1<0 && (!wrapped || p<startp || startp==eof… | |
597 /* Add first instruction to this list */ | |
598 sempty.p[0].p1 = p; | |
599 if(addinst(tl, startinst, &sempty)) | |
600 if(++ntl >= NLIST) | |
601 Overflow: | |
602 error(Eoverflow); | |
603 } | |
604 /* Execute machine until this list is empty */ | |
605 for(tlp = tl; inst = tlp->inst; tlp++){ /* assign… | |
606 Switchstmt: | |
607 switch(inst->type){ | |
608 default: /* regular character */ | |
609 if(inst->type==c){ | |
610 Addinst: | |
611 if(addinst(nl, inst->next, &tlp-… | |
612 if(++nnl >= NLIST) | |
613 goto Overflow; | |
614 } | |
615 break; | |
616 case LBRA: | |
617 if(inst->subid>=0) | |
618 tlp->se.p[inst->subid].p1 = p; | |
619 inst = inst->next; | |
620 goto Switchstmt; | |
621 case RBRA: | |
622 if(inst->subid>=0) | |
623 tlp->se.p[inst->subid].p2 = p; | |
624 inst = inst->next; | |
625 goto Switchstmt; | |
626 case ANY: | |
627 if(c!='\n') | |
628 goto Addinst; | |
629 break; | |
630 case BOL: | |
631 if(p==0 || filereadc(f, p - 1)=='\n'){ | |
632 Step: | |
633 inst = inst->next; | |
634 goto Switchstmt; | |
635 } | |
636 break; | |
637 case EOL: | |
638 if(c == '\n') | |
639 goto Step; | |
640 break; | |
641 case CCLASS: | |
642 if(c>=0 && classmatch(inst->rclass, c, 0… | |
643 goto Addinst; | |
644 break; | |
645 case NCCLASS: | |
646 if(c>=0 && classmatch(inst->rclass, c, 1… | |
647 goto Addinst; | |
648 break; | |
649 case OR: | |
650 /* evaluate right choice later */ | |
651 if(addinst(tl, inst->right, &tlp->se)) | |
652 if(++ntl >= NLIST) | |
653 goto Overflow; | |
654 /* efficiency: advance and re-evaluate */ | |
655 inst = inst->left; | |
656 goto Switchstmt; | |
657 case END: /* Match! */ | |
658 tlp->se.p[0].p2 = p; | |
659 newmatch(&tlp->se); | |
660 break; | |
661 } | |
662 } | |
663 } | |
664 Return: | |
665 return sel.p[0].p1>=0; | |
666 } | |
667 | |
668 void | |
669 newmatch(Rangeset *sp) | |
670 { | |
671 int i; | |
672 | |
673 if(sel.p[0].p1<0 || sp->p[0].p1<sel.p[0].p1 || | |
674 (sp->p[0].p1==sel.p[0].p1 && sp->p[0].p2>sel.p[0].p2)) | |
675 for(i = 0; i<NSUBEXP; i++) | |
676 sel.p[i] = sp->p[i]; | |
677 } | |
678 | |
679 int | |
680 bexecute(File *f, Posn startp) | |
681 { | |
682 int flag = 0; | |
683 Inst *inst; | |
684 Ilist *tlp; | |
685 Posn p = startp; | |
686 int nnl = 0, ntl; | |
687 int c; | |
688 int wrapped = 0; | |
689 int startchar = bstartinst->type<OPERATOR? bstartinst->type : 0; | |
690 | |
691 list[0][0].inst = list[1][0].inst = 0; | |
692 sel.p[0].p1= -1; | |
693 /* Execute machine once for each character, including terminal N… | |
694 for(;;--p){ | |
695 doloop: | |
696 if((c = filereadc(f, p - 1))==-1){ | |
697 switch(wrapped++){ | |
698 case 0: /* let loop run one more … | |
699 case 2: | |
700 break; | |
701 case 1: /* expired; wrap to end */ | |
702 if(sel.p[0].p1>=0) | |
703 goto Return; | |
704 list[0][0].inst = list[1][0].inst = 0; | |
705 p = f->b.nc; | |
706 goto doloop; | |
707 case 3: | |
708 default: | |
709 goto Return; | |
710 } | |
711 }else if(((wrapped && p<=startp) || sel.p[0].p1>0) && nn… | |
712 break; | |
713 /* fast check for first char */ | |
714 if(startchar && nnl==0 && c!=startchar) | |
715 continue; | |
716 tl = list[flag]; | |
717 nl = list[flag^=1]; | |
718 nl->inst = 0; | |
719 ntl = nnl; | |
720 nnl = 0; | |
721 if(sel.p[0].p1<0 && (!wrapped || p>startp)){ | |
722 /* Add first instruction to this list */ | |
723 /* the minus is so the optimizations in addinst … | |
724 sempty.p[0].p1 = -p; | |
725 if(addinst(tl, bstartinst, &sempty)) | |
726 if(++ntl >= NLIST) | |
727 Overflow: | |
728 error(Eoverflow); | |
729 } | |
730 /* Execute machine until this list is empty */ | |
731 for(tlp = tl; inst = tlp->inst; tlp++){ /* assign… | |
732 Switchstmt: | |
733 switch(inst->type){ | |
734 default: /* regular character */ | |
735 if(inst->type == c){ | |
736 Addinst: | |
737 if(addinst(nl, inst->next, &tlp-… | |
738 if(++nnl >= NLIST) | |
739 goto Overflow; | |
740 } | |
741 break; | |
742 case LBRA: | |
743 if(inst->subid>=0) | |
744 tlp->se.p[inst->subid].p1 = p; | |
745 inst = inst->next; | |
746 goto Switchstmt; | |
747 case RBRA: | |
748 if(inst->subid >= 0) | |
749 tlp->se.p[inst->subid].p2 = p; | |
750 inst = inst->next; | |
751 goto Switchstmt; | |
752 case ANY: | |
753 if(c != '\n') | |
754 goto Addinst; | |
755 break; | |
756 case BOL: | |
757 if(c=='\n' || p==0){ | |
758 Step: | |
759 inst = inst->next; | |
760 goto Switchstmt; | |
761 } | |
762 break; | |
763 case EOL: | |
764 if(p==f->b.nc || filereadc(f, p)=='\n') | |
765 goto Step; | |
766 break; | |
767 case CCLASS: | |
768 if(c>=0 && classmatch(inst->rclass, c, 0… | |
769 goto Addinst; | |
770 break; | |
771 case NCCLASS: | |
772 if(c>=0 && classmatch(inst->rclass, c, 1… | |
773 goto Addinst; | |
774 break; | |
775 case OR: | |
776 /* evaluate right choice later */ | |
777 if(addinst(tlp, inst->right, &tlp->se)) | |
778 if(++ntl >= NLIST) | |
779 goto Overflow; | |
780 /* efficiency: advance and re-evaluate */ | |
781 inst = inst->left; | |
782 goto Switchstmt; | |
783 case END: /* Match! */ | |
784 tlp->se.p[0].p1 = -tlp->se.p[0].p1; /* m… | |
785 tlp->se.p[0].p2 = p; | |
786 bnewmatch(&tlp->se); | |
787 break; | |
788 } | |
789 } | |
790 } | |
791 Return: | |
792 return sel.p[0].p1>=0; | |
793 } | |
794 | |
795 void | |
796 bnewmatch(Rangeset *sp) | |
797 { | |
798 int i; | |
799 if(sel.p[0].p1<0 || sp->p[0].p1>sel.p[0].p2 || (sp->p[0].p1==sel… | |
800 for(i = 0; i<NSUBEXP; i++){ /* note the reversal; … | |
801 sel.p[i].p1 = sp->p[i].p2; | |
802 sel.p[i].p2 = sp->p[i].p1; | |
803 } | |
804 } |