Annotation of researchv9/jtools/src/sam/regexp.c, revision 1.1.1.1

1.1       root        1: #include "sam.h"
                      2: 
                      3: Range          sel;
                      4: String         lastregexp;
                      5: /*
                      6:  * Machine Information
                      7:  */
                      8: typedef struct Inst{
                      9:        int     type;   /* < 0x200 ==> literal, otherwise action */
                     10:        struct Inst *right;
                     11:        struct Inst *left;
                     12: }Inst;
                     13: #define        next    left    /* Left branch is usually just next ptr */
                     14: #define        NPROG   1024
                     15: Inst   program[NPROG];
                     16: Inst   *progp;
                     17: Inst   *startinst;     /* First inst. of program; might not be program[0] */
                     18: Inst   *bstartinst;    /* same for backwards machine */
                     19: 
                     20: typedef struct Ilist{
                     21:        Inst    *inst;          /* Instruction of the thread */
                     22:        Posn    startp;         /* first char of match */
                     23: }Ilist;
                     24: #define        NLIST   128
                     25: Ilist  *tl, *nl;       /* This list, next list */
                     26: Ilist  list[2][NLIST];
                     27: 
                     28: /*
                     29:  * Actions and Tokens
                     30:  *
                     31:  *     0x2xx are operators, value == precedence
                     32:  *     0x3xx are tokens, i.e. operands for operators
                     33:  */
                     34: #define        OPERATOR        0x200   /* Bitmask of all operators */
                     35: #define        START           0x200   /* Start, used for marker on stack */
                     36: #define        RBRA            0x201   /* Right bracket, ) */
                     37: #define        LBRA            0x202   /* Left bracket, ( */
                     38: #define        OR              0x203   /* Alternation, | */
                     39: #define        CAT             0x204   /* Concatentation, implicit operator */
                     40: #define        STAR            0x205   /* Closure, * */
                     41: #define        PLUS            0x206   /* a+ == aa* */
                     42: #define        QUEST           0x207   /* a? == a|nothing, i.e. 0 or 1 a's */
                     43: #define        ANY             0x300   /* Any character but newline, . */
                     44: #define        ANYNL           0x301   /* Any character, including newline, @ */
                     45: #define        NOP             0x302   /* No operation, internal use only */
                     46: #define        BOL             0x303   /* Beginning of line, ^ */
                     47: #define        EOL             0x304   /* End of line, $ */
                     48: #define        CCLASS          0x305   /* Character class, [] */
                     49: #define        END             0x377   /* Terminate: match found */
                     50: 
                     51: /*
                     52:  * Parser Information
                     53:  */
                     54: typedef struct Node{
                     55:        Inst    *first;
                     56:        Inst    *last;
                     57: }Node;
                     58: #define        NSTACK  20
                     59: Node   andstack[NSTACK];
                     60: Node   *andp;
                     61: int    atorstack[NSTACK];
                     62: int    *atorp;
                     63: int    lastwasand;     /* Last token was operand */
                     64: int    backwards;
                     65: int    nbra;
                     66: uchar  *exprp;         /* pointer to next character in source expression */
                     67: #define        NCLASS  8
                     68: int    nclass;
                     69: char   class[NCLASS][32];      /* 32 bytes == 256 bits, one bit per char */
                     70: 
                     71: Inst *
                     72: newinst(t)
                     73:        int t;
                     74: {
                     75:        if(progp>= &program[NPROG])
                     76:                error(Etoolong);
                     77:        progp->type=t;
                     78:        progp->left=0;
                     79:        progp->right=0;
                     80:        return progp++;
                     81: }
                     82: Inst *
                     83: realcompile(s)
                     84:        uchar *s;
                     85: {
                     86:        register token;
                     87: 
                     88:        startlex(s);
                     89:        atorp=atorstack;
                     90:        andp=andstack;
                     91:        lastwasand=FALSE;
                     92:        /* Start with a low priority operator to prime parser */
                     93:        pushator(START-1);
                     94:        while((token=lex()) != END){
                     95:                if((token&0x300) == OPERATOR)
                     96:                        operator(token);
                     97:                else
                     98:                        operand(token);
                     99:        }
                    100:        /* Close with a low priority operator */
                    101:        evaluntil(START);
                    102:        /* Force END */
                    103:        operand(END);
                    104:        evaluntil(START);
                    105:        if(nbra)
                    106:                error(Eleftpar);
                    107:        --andp; /* points to first and only operand */
                    108:        return andp->first;
                    109: }
                    110: compile(r)
                    111:        Regexp *r;
                    112: {
                    113:        register String *s= &r->text;
                    114:        Inst *oprogp;
                    115:        if(s->n==lastregexp.n &&
                    116:            strncmp(s->s, lastregexp.s, lastregexp.n)==0)
                    117:                return;
                    118:        progp=program;
                    119:        backwards=FALSE;
                    120:        startinst=realcompile(s->s);
                    121:        optimize(program);
                    122:        oprogp=progp;
                    123:        backwards=TRUE;
                    124:        bstartinst=realcompile(s->s);
                    125:        optimize(oprogp);
                    126:        strdupstr(&lastregexp, s);
                    127: }
                    128: operand(t)
                    129:        int t;
                    130: {
                    131:        register Inst *i;
                    132:        if(lastwasand)
                    133:                operator(CAT);  /* catenate is implicit */
                    134:        i=newinst(t);
                    135:        if(t==CCLASS)   /* ugh */
                    136:                i->right=(Inst *)class[nclass-1];       /* UGH! */
                    137:        pushand(i, i);
                    138:        lastwasand=TRUE;
                    139: }
                    140: operator(t)
                    141:        int t;
                    142: {
                    143:        if(t==RBRA && --nbra<0)
                    144:                error(Erightpar);
                    145:        if(t==LBRA){
                    146:                nbra++;
                    147:                if(lastwasand)
                    148:                        operator(CAT);
                    149:        }else
                    150:                evaluntil(t);
                    151:        if(t!=RBRA)
                    152:                pushator(t);
                    153:        lastwasand=FALSE;
                    154:        if(t==STAR || t==QUEST || t==PLUS || t==RBRA)
                    155:                lastwasand=TRUE;        /* these look like operands */
                    156: }
                    157: cant(s)
                    158:        char *s;
                    159: {
                    160:        char buf[100];
                    161:        sprint(buf, "can't happen: %s", s);
                    162:        panic(buf);
                    163: }
                    164: pushand(f, l)
                    165:        Inst *f, *l;
                    166: {
                    167:        if(andp >= &andstack[NSTACK])
                    168:                cant("operand stack overflow");
                    169:        andp->first=f;
                    170:        andp->last=l;
                    171:        andp++;
                    172: }
                    173: pushator(t)
                    174:        int t;
                    175: {
                    176:        if(atorp >= &atorstack[NSTACK])
                    177:                cant("operator stack overflow");
                    178:        *atorp++=t;
                    179: }
                    180: Node *
                    181: popand(op)
                    182: {
                    183:        if(andp <= &andstack[0])
                    184:                error_c(Emissop, op);
                    185:        return --andp;
                    186: }
                    187: popator()
                    188: {
                    189:        if(atorp <= &atorstack[0])
                    190:                cant("operator stack underflow");
                    191:        return *--atorp;
                    192: }
                    193: evaluntil(pri)
                    194:        register pri;
                    195: {
                    196:        register Node *op1, *op2, *t;
                    197:        register Inst *inst1, *inst2;
                    198:        while(pri==RBRA || atorp[-1]>=pri){
                    199:                switch(popator()){
                    200:                case LBRA:
                    201:                        return;         /* must have been RBRA */
                    202:                default:
                    203:                        panic("unknown regexp operator");
                    204:                        break;
                    205:                case OR:
                    206:                        op2=popand('|');
                    207:                        op1=popand('|');
                    208:                        inst2=newinst(NOP);
                    209:                        op2->last->next=inst2;
                    210:                        op1->last->next=inst2;
                    211:                        inst1=newinst(OR);
                    212:                        inst1->right=op1->first;
                    213:                        inst1->left=op2->first;
                    214:                        pushand(inst1, inst2);
                    215:                        break;
                    216:                case CAT:
                    217:                        op2=popand(0);
                    218:                        op1=popand(0);
                    219:                        if(backwards && op2->first->type!=END)
                    220:                                t=op1, op1=op2, op2=t;
                    221:                        op1->last->next=op2->first;
                    222:                        pushand(op1->first, op2->last);
                    223:                        break;
                    224:                case STAR:
                    225:                        op2=popand('*');
                    226:                        inst1=newinst(OR);
                    227:                        op2->last->next=inst1;
                    228:                        inst1->right=op2->first;
                    229:                        pushand(inst1, inst1);
                    230:                        break;
                    231:                case PLUS:
                    232:                        op2=popand('+');
                    233:                        inst1=newinst(OR);
                    234:                        op2->last->next=inst1;
                    235:                        inst1->right=op2->first;
                    236:                        pushand(op2->first, inst1);
                    237:                        break;
                    238:                case QUEST:
                    239:                        op2=popand('?');
                    240:                        inst1=newinst(OR);
                    241:                        inst2=newinst(NOP);
                    242:                        inst1->left=inst2;
                    243:                        inst1->right=op2->first;
                    244:                        op2->last->next=inst2;
                    245:                        pushand(inst1, inst2);
                    246:                        break;
                    247:                }
                    248:        }
                    249: }
                    250: optimize(start)
                    251:        register Inst *start;
                    252: {
                    253:        register Inst *inst, *target;
                    254: 
                    255:        for(inst=start; inst->type!=END; inst++){
                    256:                target=inst->next;
                    257:                while(target->type == NOP)
                    258:                        target=target->next;
                    259:                inst->next=target;
                    260:        }
                    261: }
                    262: #ifdef DEBUG
                    263: dumpstack(){
                    264:        Node *stk;
                    265:        int *ip;
                    266: 
                    267:        dprint("operators\n");
                    268:        for(ip=atorstack; ip<atorp; ip++)
                    269:                dprint("0%o\n", *ip);
                    270:        dprint("operands\n");
                    271:        for(stk=andstack; stk<andp; stk++)
                    272:                dprint("0%o\t0%o\n", stk->first->type, stk->last->type);
                    273: }
                    274: dump(){
                    275:        Inst *l;
                    276: 
                    277:        l=program;
                    278:        do{
                    279:                dprint("%d:\t0%o\t%d\t%d\n", l-program, l->type,
                    280:                        l->left-program, l->right-program);
                    281:        }while(l++->type);
                    282: }
                    283: #endif
                    284: startlex(s)
                    285:        uchar *s;
                    286: {
                    287:        exprp=s;
                    288:        nclass=0;
                    289:        nbra=0;
                    290: }
                    291: char *
                    292: newclass(){
                    293:        register char *p;
                    294:        register n;
                    295: 
                    296:        if(nclass >= NCLASS)
                    297:                error(Eclass);
                    298:        p=class[nclass++];
                    299:        for(n=0; n<32; n++)
                    300:                p[n]=0;
                    301:        return p;
                    302: }
                    303: lex(){
                    304:        register c= *exprp++;
                    305: 
                    306:        switch(c){
                    307:        case '\\':
                    308:                if(*exprp)
                    309:                        if((c= *exprp++)=='n')
                    310:                                c='\n';
                    311:                break;
                    312:        case 0:
                    313:                c=END;
                    314:                --exprp;        /* In case we come here again */
                    315:                break;
                    316:        case '*':
                    317:                c=STAR;
                    318:                break;
                    319:        case '?':
                    320:                c=QUEST;
                    321:                break;
                    322:        case '+':
                    323:                c=PLUS;
                    324:                break;
                    325:        case '|':
                    326:                c=OR;
                    327:                break;
                    328:        case '.':
                    329:                c=ANY;
                    330:                break;
                    331:        case '@':
                    332:                c=ANYNL;
                    333:                break;
                    334:        case '(':
                    335:                c=LBRA;
                    336:                break;
                    337:        case ')':
                    338:                c=RBRA;
                    339:                break;
                    340:        case '^':
                    341:                c=BOL;
                    342:                break;
                    343:        case '$':
                    344:                c=EOL;
                    345:                break;
                    346:        case '[':
                    347:                c=CCLASS;
                    348:                bldcclass();
                    349:                break;
                    350:        }
                    351:        return c;
                    352: }
                    353: nextrec(){
                    354:        if(exprp[0]==0 || (exprp[0]=='\\' && exprp[1]==0))
                    355:                error(Ebadclass);
                    356:        if(exprp[0]=='\\'){
                    357:                exprp++;
                    358:                if(*exprp=='n'){
                    359:                        exprp++;
                    360:                        return '\n';
                    361:                }
                    362:                return *exprp++|0x100;
                    363:        }
                    364:        return *exprp++;
                    365: }
                    366: bldcclass(){
                    367:        register c1, c2;
                    368:        register char *classp;
                    369:        register negate=FALSE;
                    370: 
                    371:        classp=newclass();
                    372:        /* we have already seen the '[' */
                    373:        if(*exprp=='^'){
                    374:                negate=TRUE;
                    375:                exprp++;
                    376:        }
                    377:        while((c1=c2=nextrec()) != ']'){
                    378:                if(*exprp=='-'){
                    379:                        exprp++;        /* eat '-' */
                    380:                        if((c2=nextrec()) == ']')
                    381:                                error(Ebadclass);
                    382:                }
                    383:                for((c1&=0xFF), (c2&=0xFF); c1<=c2; c1++)
                    384:                        classp[c1/8] |= 1<<(c1&07);
                    385:        }
                    386:        if(negate){
                    387:                for(c1=0; c1<32; c1++)
                    388:                        classp[c1]^=0xFF;
                    389:                classp[1]&=~(1<<('\n'-8));      /* exclude '\n' */
                    390:        }
                    391:        classp[0]&=0xFE;                /* exclude NUL */
                    392: }
                    393: /*
                    394:  * Note optimization in addinst:
                    395:  *     *l must be pending when addinst called; if *l has been looked
                    396:  *             at already, the optimization is a bug.
                    397:  */
                    398: addinst(l, inst, startp)
                    399:        register Ilist *l;
                    400:        register Inst *inst;
                    401:        Posn startp;
                    402: {
                    403:        register Ilist *p;
                    404:        for(p=l; p->inst; p++){
                    405:                if(p->inst==inst){
                    406:                        if(startp < p->startp)
                    407:                                p->startp=startp;       /* this would be bug */
                    408:                        return; /* It's already there */
                    409:                }
                    410:        }
                    411:        p->inst=inst;
                    412:        p->startp=startp;
                    413:        (++p)->inst=0;
                    414: }
                    415: execute(f, startp, eof)
                    416:        File *f;
                    417:        Posn startp, eof;
                    418: {
                    419:        register flag=0;
                    420:        register Inst *inst;
                    421:        register Ilist *tlp;
                    422:        register Posn p=startp;
                    423:        int nnl=0, ntl;
                    424:        register c;
                    425:        int wrapped=0;
                    426:        register startchar=startinst->type<OPERATOR? startinst->type : 0;
                    427: 
                    428:        list[0][0].inst=list[1][0].inst=0;
                    429:        sel.p1= -1;
                    430:        Fgetcset(f, startp);
                    431:        /* Execute machine once for each character */
                    432:        for(;;p++){
                    433:        doloop:
                    434:                c=Fgetc(f);
                    435:                if(p>=eof || c<0){
                    436:                        switch(wrapped++){
                    437:                        case 0:         /* let loop run one more click */
                    438:                        case 2:
                    439:                                break;
                    440:                        case 1:         /* expired; wrap to beginning */
                    441:                                if(sel.p1>=0 || eof!=INFINITY)
                    442:                                        goto Return;
                    443:                                list[0][0].inst=list[1][0].inst=0;
                    444:                                Fgetcset(f, (Posn)0);
                    445:                                p=0;
                    446:                                goto doloop;
                    447:                        default:
                    448:                                goto Return;
                    449:                        }
                    450:                }else if(((wrapped && p>=startp) || sel.p1>0) && nnl==0)
                    451:                        break;
                    452:                /* fast check for first char */
                    453:                if(startchar && nnl==0 && c!=startchar)
                    454:                        continue;
                    455:                tl=list[flag];
                    456:                nl=list[flag^=1];
                    457:                nl->inst=0;
                    458:                ntl=nnl;
                    459:                nnl=0;
                    460:                if(sel.p1<0 && (!wrapped || p<startp || startp==eof)){
                    461:                        /* Add first instruction to this list */
                    462:                        if(++ntl >= NLIST)
                    463:        Overflow:
                    464:                                error(Eoverflow);
                    465:                        addinst(tl, startinst, p);
                    466:                }
                    467:                /* Execute machine until this list is empty */
                    468:                for(tlp=tl; inst=tlp->inst; tlp++){     /* assignment = */
                    469:        Switchstmt:
                    470:                        switch(inst->type){
                    471:                        default:        /* regular character */
                    472:                                if(inst->type==c){
                    473:        Addinst:
                    474:                                        if(++nnl >= NLIST)
                    475:                                                goto Overflow;
                    476:                                        addinst(nl, inst->next, tlp->startp);
                    477:                                }
                    478:                                break;
                    479:                        case ANYNL:
                    480:                                goto Addinst;
                    481:                        case ANY:
                    482:                                if(c!='\n')
                    483:                                        goto Addinst;
                    484:                                break;
                    485:                        case BOL:
                    486:                                if(p==0){
                    487:        Step:
                    488:                                        inst=inst->next;
                    489:                                        goto Switchstmt;
                    490:                                }
                    491:                                if(f->getci>1){
                    492:                                        if(f->getcbuf[f->getci-2]=='\n')
                    493:                                                goto Step;
                    494:                                }else{
                    495:                                        uchar c;
                    496:                                        if(Fchars(f, &c, p-1, p)==1 && c=='\n')
                    497:                                                goto Step;
                    498:                                }
                    499:                                break;
                    500:                        case EOL:
                    501:                                if(c=='\n')
                    502:                                        goto Step;
                    503:                                break;
                    504:                        case CCLASS:
                    505:                                if(c>=0 && ((char *)inst->right)[c/8]&(1<<(c&07)))
                    506:                                        goto Addinst;
                    507:                                break;
                    508:                        case OR:
                    509:                                /* evaluate right choice later */
                    510:                                if(++ntl >= NLIST)
                    511:                                        goto Overflow;
                    512:                                addinst(tlp, inst->right, tlp->startp);
                    513:                                /* efficiency: advance and re-evaluate */
                    514:                                inst=inst->left;
                    515:                                goto Switchstmt;
                    516:                        case END:       /* Match! */
                    517:                                newmatch(tlp->startp, p);
                    518:                                break;
                    519:                        }
                    520:                }
                    521:        }
                    522:     Return:
                    523:        return sel.p1>=0;
                    524: }
                    525: newmatch(p1, p2)
                    526:        Posn p1, p2;
                    527: {
                    528:        if(sel.p1<0 || p1<sel.p1 || (p1==sel.p1 && p2>sel.p2)){
                    529:                sel.p1=p1;
                    530:                sel.p2=p2;
                    531:        }
                    532: }
                    533: bexecute(f, startp)
                    534:        register File *f;
                    535:        Posn startp;
                    536: {
                    537:        register flag=0;
                    538:        register Inst *inst;
                    539:        register Ilist *tlp;
                    540:        register Posn p=startp;
                    541:        int nnl=0, ntl;
                    542:        register c;
                    543:        int wrapped=0;
                    544:        register startchar=bstartinst->type<OPERATOR? bstartinst->type : 0;
                    545: 
                    546:        list[0][0].inst=list[1][0].inst=0;
                    547:        sel.p1= -1;
                    548:        Fgetcset(f, startp);
                    549:        /* Execute machine once for each character, including terminal NUL */
                    550:        for(;;--p){
                    551:        doloop:
                    552:                if((c=Fbgetc(f))==-1){
                    553:                        switch(wrapped++){
                    554:                        case 0:         /* let loop run one more click */
                    555:                        case 2:
                    556:                                break;
                    557:                        case 1:         /* expired; wrap to end */
                    558:                                if(sel.p1>=0)
                    559:                        case 3:
                    560:                                        goto Return;
                    561:                                list[0][0].inst=list[1][0].inst=0;
                    562:                                Fgetcset(f, f->nbytes);
                    563:                                p=f->nbytes;
                    564:                                goto doloop;
                    565:                        default:
                    566:                                goto Return;
                    567:                        }
                    568:                }else if(((wrapped && p<=startp) || sel.p1>0) && nnl==0)
                    569:                        break;
                    570:                /* fast check for first char */
                    571:                if(startchar && nnl==0 && c!=startchar)
                    572:                        continue;
                    573:                tl=list[flag];
                    574:                nl=list[flag^=1];
                    575:                nl->inst=0;
                    576:                ntl=nnl;
                    577:                nnl=0;
                    578:                if(sel.p1<0 && (!wrapped || p>startp)){
                    579:                        /* Add first instruction to this list */
                    580:                        if(++ntl >= NLIST)
                    581:        Overflow:
                    582:                                error(Eoverflow);
                    583:                        /* the minus is so the optimizations in addinst work */
                    584:                        addinst(tl, bstartinst, -p);
                    585:                }
                    586:                /* Execute machine until this list is empty */
                    587:                for(tlp=tl; inst=tlp->inst; tlp++){     /* assignment = */
                    588:        Switchstmt:
                    589:                        switch(inst->type){
                    590:                        default:        /* regular character */
                    591:                                if(inst->type==c){
                    592:        Addinst:
                    593:                                        if(++nnl >= NLIST)
                    594:                                                goto Overflow;
                    595:                                        addinst(nl, inst->next, tlp->startp);
                    596:                                }
                    597:                                break;
                    598:                        case ANYNL:
                    599:                                goto Addinst;
                    600:                        case ANY:
                    601:                                if(c!='\n')
                    602:                                        goto Addinst;
                    603:                                break;
                    604:                        case BOL:
                    605:                                if(c=='\n'){
                    606:        Step:
                    607:                                        inst=inst->next;
                    608:                                        goto Switchstmt;
                    609:                                }
                    610:                                break;
                    611:                        case EOL:
                    612:                                if(f->getci<f->ngetc-1){
                    613:                                        if(f->getcbuf[f->getci+1]=='\n')
                    614:                                                goto Step;
                    615:                                }else if(p<f->nbytes-1){
                    616:                                        uchar c;
                    617:                                        if(Fchars(f, &c, p+1, p+2)==1 && c=='\n')
                    618:                                                goto Step;
                    619:                                }
                    620:                                break;
                    621:                        case CCLASS:
                    622:                                if(((char *)inst->right)[c/8]&(1<<(c&07)))
                    623:                                        goto Addinst;
                    624:                                break;
                    625:                        case OR:
                    626:                                /* evaluate right choice later */
                    627:                                if(++ntl >= NLIST)
                    628:                                        goto Overflow;
                    629:                                addinst(tlp, inst->right, tlp->startp);
                    630:                                /* efficiency: advance and re-evaluate */
                    631:                                inst=inst->left;
                    632:                                goto Switchstmt;
                    633:                        case END:       /* Match! */
                    634:                                bnewmatch(-tlp->startp, p);     /* minus sign */
                    635:                                break;
                    636:                        }
                    637:                }
                    638:        }
                    639:     Return:
                    640:        return sel.p1>=0;
                    641: }
                    642: bnewmatch(p2, p1)      /* note the reversal; p1<=p2 */
                    643:        Posn p1, p2;
                    644: {
                    645:        if(sel.p1<0 || p2>sel.p2 || (p2==sel.p2 && p1<sel.p1)){
                    646:                sel.p1=p1;
                    647:                sel.p2=p2;
                    648:        }
                    649: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.