URI:
       tdfa.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tdfa.c (14742B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bin.h>
            4 #include <bio.h>
            5 #include <regexp.h>
            6 #include "../../../libregexp/regcomp.h"
            7 #include "dfa.h"
            8 
            9 void rdump(Reprog*);
           10 void dump(Dreprog*);
           11 
           12 /*
           13  * Standard NFA determinization and DFA minimization.
           14  */
           15 typedef struct Deter Deter;
           16 typedef struct Reiset Reiset;
           17 
           18 void ddump(Deter*);
           19 
           20 /* state of determinization */
           21 struct Deter
           22 {
           23         jmp_buf kaboom;        /* jmp on error */
           24 
           25         Bin *bin;                /* bin for temporary allocations */
           26 
           27         Reprog *p;        /* program being determinized */
           28         uint ninst;                /* number of instructions in program */
           29 
           30         Reiset *alloc;        /* chain of all Reisets */
           31         Reiset **last;
           32 
           33         Reiset **hash;        /* hash of all Reisets */
           34         uint nhash;
           35 
           36         Reiset *tmp;        /* temporaries for walk */
           37         uchar *bits;
           38 
           39         Rune *c;                /* ``interesting'' characters */
           40         uint nc;
           41 };
           42 
           43 /* set of Reinsts: perhaps we should use a bit list instead of the indices? */
           44 struct Reiset
           45 {
           46         uint *inst;                /* indices of instructions in set */
           47         uint ninst;                /* size of set */
           48 
           49         Reiset *next;        /* d.alloc chain */
           50         Reiset *hash;        /* d.hash chain */
           51         Reiset **delta;        /* where to go on each interesting char */
           52         uint id;                /* assigned id during minimization */
           53         uint isfinal;        /* is an accepting (final) state */
           54 };
           55 
           56 static Reiset*
           57 ralloc(Deter *d, int ninst)
           58 {
           59         Reiset *t;
           60 
           61         t = binalloc(&d->bin, sizeof(Reiset)+2*d->nc*sizeof(Reiset*)+sizeof(uint)*ninst, 0);
           62         if(t == nil)
           63                 longjmp(d->kaboom, 1);
           64         t->delta = (Reiset**)&t[1];
           65         t->inst = (uint*)&t->delta[2*d->nc];
           66         return t;
           67 }
           68 
           69 /* find the canonical form a given Reiset */
           70 static Reiset*
           71 findreiset(Deter *d, Reiset *s)
           72 {
           73         int i, szinst;
           74         uint h;
           75         Reiset *t;
           76 
           77         h = 0;
           78         for(i=0; i<s->ninst; i++)
           79                 h = h*1000003 + s->inst[i];
           80         h %= d->nhash;
           81 
           82         szinst = s->ninst*sizeof(s->inst[0]);
           83         for(t=d->hash[h]; t; t=t->hash)
           84                 if(t->ninst==s->ninst && memcmp(t->inst, s->inst, szinst)==0)
           85                         return t;
           86 
           87         t = ralloc(d, s->ninst);
           88         t->hash = d->hash[h];
           89         d->hash[h] = t;
           90 
           91         *d->last = t;
           92         d->last = &t->next;
           93         t->next = 0;
           94 
           95         t->ninst = s->ninst;
           96         memmove(t->inst, s->inst, szinst);
           97 
           98         /* delta is filled in later */
           99 
          100         return t;
          101 }
          102 
          103 /* convert bits to a real reiset */
          104 static Reiset*
          105 bits2reiset(Deter *d, uchar *bits)
          106 {
          107         int k;
          108         Reiset *s;
          109 
          110         s = d->tmp;
          111         s->ninst = 0;
          112         for(k=0; k<d->ninst; k++)
          113                 if(bits[k])
          114                         s->inst[s->ninst++] = k;
          115         return findreiset(d, s);
          116 }
          117 
          118 /* add n to state set; if n < k, need to go around again */
          119 static int
          120 add(int n, uchar *bits, int k)
          121 {
          122         if(bits[n])
          123                 return 0;
          124         bits[n] = 1;
          125         return n < k;
          126 }
          127 
          128 /* update bits to follow all the empty (non-character-related) transitions possible */
          129 static void
          130 followempty(Deter *d, uchar *bits, int bol, int eol)
          131 {
          132         int again, k;
          133         Reinst *i;
          134 
          135         do{
          136                 again = 0;
          137                 for(i=d->p->firstinst, k=0; k < d->ninst; i++, k++){
          138                         if(!bits[k])
          139                                 continue;
          140                         switch(i->type){
          141                         case RBRA:
          142                         case LBRA:
          143                                 again |= add(i->u2.next - d->p->firstinst, bits, k);
          144                                 break;
          145                         case OR:
          146                                 again |= add(i->u2.left - d->p->firstinst, bits, k);
          147                                 again |= add(i->u1.right - d->p->firstinst, bits, k);
          148                                 break;
          149                         case BOL:
          150                                 if(bol)
          151                                         again |= add(i->u2.next - d->p->firstinst, bits, k);
          152                                 break;
          153                         case EOL:
          154                                 if(eol)
          155                                         again |= add(i->u2.next - d->p->firstinst, bits, k);
          156                                 break;
          157                         }
          158                 }
          159         }while(again);
          160 
          161         /*
          162          * Clear bits for useless transitions.  We could do this during
          163          * the switch above, but then we have no guarantee of termination
          164          * if we get a loop in the regexp.
          165          */
          166         for(i=d->p->firstinst, k=0; k < d->ninst; i++, k++){
          167                 if(!bits[k])
          168                         continue;
          169                 switch(i->type){
          170                 case RBRA:
          171                 case LBRA:
          172                 case OR:
          173                 case BOL:
          174                 case EOL:
          175                         bits[k] = 0;
          176                         break;
          177                 }
          178         }
          179 }
          180 
          181 /*
          182  * Where does s go if it sees rune r?
          183  * Eol is true if a $ matches the string at the position just after r.
          184  */
          185 static Reiset*
          186 transition(Deter *d, Reiset *s, Rune r, uint eol)
          187 {
          188         int k;
          189         uchar *bits;
          190         Reinst *i, *inst0;
          191         Rune *rp, *ep;
          192 
          193         bits = d->bits;
          194         memset(bits, 0, d->ninst);
          195 
          196         inst0 = d->p->firstinst;
          197         for(k=0; k < s->ninst; k++){
          198                 i = inst0 + s->inst[k];
          199                 switch(i->type){
          200                 default:
          201                         werrstr("bad reprog: got type %d", i->type);
          202                         longjmp(d->kaboom, 1);
          203                 case RBRA:
          204                 case LBRA:
          205                 case OR:
          206                 case BOL:
          207                 case EOL:
          208                         werrstr("internal error: got type %d", i->type);
          209                         longjmp(d->kaboom, 1);
          210 
          211                 case RUNE:
          212                         if(r == i->u1.r)
          213                                 bits[i->u2.next - inst0] = 1;
          214                         break;
          215                 case ANY:
          216                         if(r != L'\n')
          217                                 bits[i->u2.next - inst0] = 1;
          218                         break;
          219                 case ANYNL:
          220                         bits[i->u2.next - inst0] = 1;
          221                         break;
          222                 case NCCLASS:
          223                         if(r == L'\n')
          224                                 break;
          225                         /* fall through */
          226                 case CCLASS:
          227                         ep = i->u1.cp->end;
          228                         for(rp = i->u1.cp->spans; rp < ep; rp += 2)
          229                                 if(rp[0] <= r && r <= rp[1])
          230                                         break;
          231                         if((rp < ep) ^! (i->type == CCLASS))
          232                                 bits[i->u2.next - inst0] = 1;
          233                         break;
          234                 case END:
          235                         break;
          236                 }
          237         }
          238 
          239         followempty(d, bits, r=='\n', eol);
          240         return bits2reiset(d, bits);
          241 }
          242 
          243 static int
          244 countinst(Reprog *pp)
          245 {
          246         int n;
          247         Reinst *l;
          248 
          249         n = 0;
          250         l = pp->firstinst;
          251         while(l++->type)
          252                 n++;
          253         return n;
          254 }
          255 
          256 static void
          257 set(Deter *d, u32int **tab, Rune r)
          258 {
          259         u32int *u;
          260 
          261         if((u = tab[r/4096]) == nil){
          262                 u = binalloc(&d->bin, 4096/8, 1);
          263                 if(u == nil)
          264                         longjmp(d->kaboom, 1);
          265                 tab[r/4096] = u;
          266         }
          267         u[(r%4096)/32] |= 1<<(r%32);
          268 }
          269 
          270 /*
          271  * Compute the list of important characters.
          272  * Other characters behave like the ones that surround them.
          273  */
          274 static void
          275 findchars(Deter *d, Reprog *p)
          276 {
          277         u32int *tab[65536/4096], *u, x;
          278         Reinst *i;
          279         Rune *rp, *ep;
          280         int k, m, n, a;
          281 
          282         memset(tab, 0, sizeof tab);
          283         set(d, tab, 0);
          284         set(d, tab, 0xFFFF);
          285         for(i=p->firstinst; i->type; i++){
          286                 switch(i->type){
          287                 case ANY:
          288                         set(d, tab, L'\n'-1);
          289                         set(d, tab, L'\n');
          290                         set(d, tab, L'\n'+1);
          291                         break;
          292                 case RUNE:
          293                         set(d, tab, i->u1.r-1);
          294                         set(d, tab, i->u1.r);
          295                         set(d, tab, i->u1.r+1);
          296                         break;
          297                 case NCCLASS:
          298                         set(d, tab, L'\n'-1);
          299                         set(d, tab, L'\n');
          300                         set(d, tab, L'\n'+1);
          301                         /* fall through */
          302                 case CCLASS:
          303                         ep = i->u1.cp->end;
          304                         for(rp = i->u1.cp->spans; rp < ep; rp += 2){
          305                                 set(d, tab, rp[0]-1);
          306                                 set(d, tab, rp[0]);
          307                                 set(d, tab, rp[1]);
          308                                 set(d, tab, rp[1]+1);
          309                         }
          310                         break;
          311                 }
          312         }
          313 
          314         n = 0;
          315         for(k=0; k<nelem(tab); k++){
          316                 if((u = tab[k]) == nil)
          317                         continue;
          318                 for(m=0; m<4096/32; m++){
          319                         if((x = u[m]) == 0)
          320                                 continue;
          321                         for(a=0; a<32; a++)
          322                                 if(x&(1<<a))
          323                                         n++;
          324                 }
          325         }
          326 
          327         d->c = binalloc(&d->bin, (n+1)*sizeof(Rune), 0);
          328         if(d->c == 0)
          329                 longjmp(d->kaboom, 1);
          330         d->nc = n;
          331 
          332         n = 0;
          333         for(k=0; k<nelem(tab); k++){
          334                 if((u = tab[k]) == nil)
          335                         continue;
          336                 for(m=0; m<4096/32; m++){
          337                         if((x = u[m]) == 0)
          338                                 continue;
          339                         for(a=0; a<32; a++)
          340                                 if(x&(1<<a))
          341                                         d->c[n++] = k*4096+m*32+a;
          342                 }
          343         }
          344 
          345         d->c[n] = 0;
          346         if(n != d->nc)
          347                 abort();
          348 }
          349 
          350 /*
          351  * convert the Deter and Reisets into a Dreprog.
          352  * if dp and c are nil, just return the count of Drecases needed.
          353  */
          354 static int
          355 buildprog(Deter *d, Reiset **id2set, int nid, Dreprog *dp, Drecase *c)
          356 {
          357         int i, j, id, n, nn;
          358         Dreinst *di;
          359         Reiset *s;
          360 
          361         nn = 0;
          362         di = 0;
          363         for(i=0; i<nid; i++){
          364                 s = id2set[i];
          365                 if(c){
          366                         di = &dp->inst[i];
          367                         di->isfinal = s->isfinal;
          368                 }
          369                 n = 0;
          370                 id = -1;
          371                 for(j=0; j<2*d->nc; j++){
          372                         if(s->delta[j]->id != id){
          373                                 id = s->delta[j]->id;
          374                                 if(c){
          375                                         c[n].start = ((j/d->nc)<<16) | d->c[j%d->nc];
          376                                         c[n].next = &dp->inst[id];
          377                                 }
          378                                 n++;
          379                         }
          380                 }
          381                 if(c){
          382                         if(n == 1 && c[0].next == di)
          383                                 di->isloop = 1;
          384                         di->c = c;
          385                         di->nc = n;
          386                         c += n;
          387                 }
          388                 nn += n;
          389         }
          390         return nn;
          391 }
          392 
          393 Dreprog*
          394 dregcvt(Reprog *p)
          395 {
          396         uchar *bits;
          397         uint again, n, nid, id;
          398         Deter d;
          399         Reiset **id2set, *s, *t, *start[4];
          400         Dreprog *dp;
          401         Drecase *c;
          402 
          403         memset(&d, 0, sizeof d);
          404 
          405         if(setjmp(d.kaboom)){
          406                 binfree(&d.bin);
          407                 return nil;
          408         }
          409 
          410         d.p = p;
          411         d.ninst = countinst(p);
          412 
          413         d.last = &d.alloc;
          414 
          415         n = d.ninst;
          416         /* round up to power of two; this loop is the least of our efficiency problems */
          417         while(n&(n-1))
          418                 n++;
          419         d.nhash = n;
          420         d.hash = binalloc(&d.bin, d.nhash*sizeof(Reinst*), 1);
          421 
          422         /* get list of important runes */
          423         findchars(&d, p);
          424 
          425 #ifdef DUMP
          426         print("relevant chars are: «%S»\n", d.c+1);
          427 #endif
          428 
          429         d.bits = bits = binalloc(&d.bin, d.ninst, 0);
          430         d.tmp = ralloc(&d, d.ninst);
          431 
          432         /*
          433          * Convert to DFA
          434          */
          435 
          436         /* 4 start states, depending on initial bol, eol */
          437         for(n=0; n<4; n++){
          438                 memset(bits, 0, d.ninst);
          439                 bits[p->startinst - p->firstinst] = 1;
          440                 followempty(&d, bits, n&1, n&2);
          441                 start[n] = bits2reiset(&d, bits);
          442         }
          443 
          444         /* explore the reiset space */
          445         for(s=d.alloc; s; s=s->next)
          446                 for(n=0; n<2*d.nc; n++)
          447                         s->delta[n] = transition(&d, s, d.c[n%d.nc], n/d.nc);
          448 
          449 #ifdef DUMP
          450         nid = 0;
          451         for(s=d.alloc; s; s=s->next)
          452                 s->id = nid++;
          453         ddump(&d);
          454 #endif
          455 
          456         /*
          457          * Minimize.
          458          */
          459 
          460         /* first class division is final or not */
          461         for(s=d.alloc; s; s=s->next){
          462                 s->isfinal = 0;
          463                 for(n=0; n<s->ninst; n++)
          464                         if(p->firstinst[s->inst[n]].type == END)
          465                                 s->isfinal = 1;
          466                 s->id = s->isfinal;
          467         }
          468 
          469         /* divide states with different transition tables in id space */
          470         nid = 2;
          471         do{
          472                 again = 0;
          473                 for(s=d.alloc; s; s=s->next){
          474                         id = -1;
          475                         for(t=s->next; t; t=t->next){
          476                                 if(s->id != t->id)
          477                                         continue;
          478                                 for(n=0; n<2*d.nc; n++){
          479                                         /* until we finish the for(t) loop, s->id and id are same */
          480                                         if((s->delta[n]->id == t->delta[n]->id)
          481                                         || (s->delta[n]->id == s->id && t->delta[n]->id == id)
          482                                         || (s->delta[n]->id == id && t->delta[n]->id == s->id))
          483                                                 continue;
          484                                         break;
          485                                 }
          486                                 if(n == 2*d.nc)
          487                                         continue;
          488                                 if(id == -1)
          489                                         id = nid++;
          490                                 t->id = id;
          491                                 again = 1;
          492                         }
          493                 }
          494         }while(again);
          495 
          496 #ifdef DUMP
          497         ddump(&d);
          498 #endif
          499 
          500         /* build dreprog */
          501         id2set = binalloc(&d.bin, nid*sizeof(Reiset*), 1);
          502         if(id2set == nil)
          503                 longjmp(d.kaboom, 1);
          504         for(s=d.alloc; s; s=s->next)
          505                 id2set[s->id] = s;
          506 
          507         n = buildprog(&d, id2set, nid, nil, nil);
          508         dp = mallocz(sizeof(Dreprog)+nid*sizeof(Dreinst)+n*sizeof(Drecase), 1);
          509         if(dp == nil)
          510                 longjmp(d.kaboom, 1);
          511         c = (Drecase*)&dp->inst[nid];
          512         buildprog(&d, id2set, nid, dp, c);
          513 
          514         for(n=0; n<4; n++)
          515                 dp->start[n] = &dp->inst[start[n]->id];
          516         dp->ninst = nid;
          517 
          518         binfree(&d.bin);
          519         return dp;
          520 }
          521 
          522 int
          523 dregexec(Dreprog *p, char *s, int bol)
          524 {
          525         Rune r;
          526         ulong rr;
          527         Dreinst *i;
          528         Drecase *c, *ec;
          529         int best, n;
          530         char *os;
          531 
          532         i = p->start[(bol ? 1 : 0) | (s[1]=='\n' ? 2 : 0)];
          533         best = -1;
          534         os = s;
          535         for(; *s; s+=n){
          536                 if(i->isfinal)
          537                         best = s - os;
          538                 if(i->isloop){
          539                         if(i->isfinal)
          540                                 return strlen(os);
          541                         else
          542                                 return best;
          543                 }
          544                 if((*s&0xFF) < Runeself){
          545                         r = *s;
          546                         n = 1;
          547                 }else
          548                         n = chartorune(&r, s);
          549                 c = i->c;
          550                 ec = c+i->nc;
          551                 rr = r;
          552                 if(s[n] == '\n' || s[n] == '\0')
          553                         rr |= 0x10000;
          554                 for(; c<ec; c++){
          555                         if(c->start > rr){
          556                                 i = c[-1].next;
          557                                 goto Out;
          558                         }
          559                 }
          560                 i = ec[-1].next;
          561         Out:;
          562         }
          563         if(i->isfinal)
          564                 best = s - os;
          565         return best;
          566 }
          567 
          568 
          569 #ifdef DUMP
          570 void
          571 ddump(Deter *d)
          572 {
          573         int i, id;
          574         Reiset *s;
          575 
          576         for(s=d->alloc; s; s=s->next){
          577                 print("%d ", s->id);
          578                 id = -1;
          579                 for(i=0; i<2*d->nc; i++){
          580                         if(id != s->delta[i]->id){
          581                                 if(i==0)
          582                                         print(" [");
          583                                 else if(i/d->nc)
          584                                         print(" [%C$", d->c[i%d->nc]);
          585                                 else
          586                                         print(" [%C", d->c[i%d->nc]);
          587                                 print(" %d]", s->delta[i]->id);
          588                                 id = s->delta[i]->id;
          589                         }
          590                 }
          591                 print("\n");
          592         }
          593 }
          594 
          595 void
          596 rdump(Reprog *pp)
          597 {
          598         Reinst *l;
          599         Rune *p;
          600 
          601         l = pp->firstinst;
          602         do{
          603                 print("%ld:\t0%o\t%ld\t%ld", l-pp->firstinst, l->type,
          604                         l->left-pp->firstinst, l->right-pp->firstinst);
          605                 if(l->type == RUNE)
          606                         print("\t%C\n", l->r);
          607                 else if(l->type == CCLASS || l->type == NCCLASS){
          608                         print("\t[");
          609                         if(l->type == NCCLASS)
          610                                 print("^");
          611                         for(p = l->cp->spans; p < l->cp->end; p += 2)
          612                                 if(p[0] == p[1])
          613                                         print("%C", p[0]);
          614                                 else
          615                                         print("%C-%C", p[0], p[1]);
          616                         print("]\n");
          617                 } else
          618                         print("\n");
          619         }while(l++->type);
          620 }
          621 
          622 void
          623 dump(Dreprog *pp)
          624 {
          625         int i, j;
          626         Dreinst *l;
          627 
          628         print("start %ld %ld %ld %ld\n",
          629                 pp->start[0]-pp->inst,
          630                 pp->start[1]-pp->inst,
          631                 pp->start[2]-pp->inst,
          632                 pp->start[3]-pp->inst);
          633 
          634         for(i=0; i<pp->ninst; i++){
          635                 l = &pp->inst[i];
          636                 print("%d:", i);
          637                 for(j=0; j<l->nc; j++){
          638                         print(" [");
          639                         if(j == 0)
          640                                 if(l->c[j].start != 1)
          641                                         abort();
          642                         if(j != 0)
          643                                 print("%C%s", l->c[j].start&0xFFFF, (l->c[j].start&0x10000) ? "$" : "");
          644                         print("-");
          645                         if(j != l->nc-1)
          646                                 print("%C%s", (l->c[j+1].start&0xFFFF)-1, (l->c[j+1].start&0x10000) ? "$" : "");
          647                         print("] %ld", l->c[j].next - pp->inst);
          648                 }
          649                 if(l->isfinal)
          650                         print(" final");
          651                 if(l->isloop)
          652                         print(" loop");
          653                 print("\n");
          654         }
          655 }
          656 
          657 
          658 void
          659 main(int argc, char **argv)
          660 {
          661         int i;
          662         Reprog *p;
          663         Dreprog *dp;
          664 
          665         i = 1;
          666                 p = regcomp(argv[i]);
          667                 if(p == 0){
          668                         print("=== %s: bad regexp\n", argv[i]);
          669                 }
          670         /*        print("=== %s\n", argv[i]); */
          671         /*        rdump(p); */
          672                 dp = dregcvt(p);
          673                 print("=== dfa\n");
          674                 dump(dp);
          675 
          676         for(i=2; i<argc; i++)
          677                 print("match %d\n", dregexec(dp, argv[i], 0));
          678         exits(0);
          679 }
          680 #endif
          681 
          682 void
          683 Bprintdfa(Biobuf *b, Dreprog *p)
          684 {
          685         int i, j, nc;
          686 
          687         Bprint(b, "# dreprog\n");
          688         nc = 0;
          689         for(i=0; i<p->ninst; i++)
          690                 nc += p->inst[i].nc;
          691         Bprint(b, "%d %d %ld %ld %ld %ld\n", p->ninst, nc,
          692                 p->start[0]-p->inst, p->start[1]-p->inst,
          693                 p->start[2]-p->inst, p->start[3]-p->inst);
          694         for(i=0; i<p->ninst; i++){
          695                 Bprint(b, "%d %d %d", p->inst[i].isfinal, p->inst[i].isloop, p->inst[i].nc);
          696                 for(j=0; j<p->inst[i].nc; j++)
          697                         Bprint(b, " %d %ld", p->inst[i].c[j].start, p->inst[i].c[j].next-p->inst);
          698                 Bprint(b, "\n");
          699         }
          700 }
          701 
          702 static char*
          703 egetline(Biobuf *b, int c, jmp_buf jb)
          704 {
          705         char *p;
          706 
          707         p = Brdline(b, c);
          708         if(p == nil)
          709                 longjmp(jb, 1);
          710         p[Blinelen(b)-1] = '\0';
          711         return p;
          712 }
          713 
          714 static void
          715 egetc(Biobuf *b, int c, jmp_buf jb)
          716 {
          717         if(Bgetc(b) != c)
          718                 longjmp(jb, 1);
          719 }
          720 
          721 static int
          722 egetnum(Biobuf *b, int want, jmp_buf jb)
          723 {
          724         int c;
          725         int n, first;
          726 
          727         n = 0;
          728         first = 1;
          729         while((c = Bgetc(b)) != Beof){
          730                 if(c < '0' || c > '9'){
          731                         if(want == 0){
          732                                 Bungetc(b);
          733                                 c = 0;
          734                         }
          735                         if(first || c != want){
          736                                 werrstr("format error");
          737                                 longjmp(jb, 1);
          738                         }
          739                         return n;
          740                 }
          741                 n = n*10 + c - '0';
          742                 first = 0;
          743         }
          744         werrstr("unexpected eof");
          745         longjmp(jb, 1);
          746         return -1;
          747 }
          748 
          749 Dreprog*
          750 Breaddfa(Biobuf *b)
          751 {
          752         char *s;
          753         int ninst, nc;
          754         jmp_buf jb;
          755         Dreprog *p;
          756         Drecase *c;
          757         Dreinst *l;
          758         int j, k;
          759 
          760         p = nil;
          761         if(setjmp(jb)){
          762                 free(p);
          763                 return nil;
          764         }
          765 
          766         s = egetline(b, '\n', jb);
          767         if(strcmp(s, "# dreprog") != 0){
          768                 werrstr("format error");
          769                 longjmp(jb, 1);
          770         }
          771 
          772         ninst = egetnum(b, ' ', jb);
          773         nc = egetnum(b, ' ', jb);
          774 
          775         p = mallocz(sizeof(Dreprog)+ninst*sizeof(Dreinst)+nc*sizeof(Drecase), 1);
          776         if(p == nil)
          777                 longjmp(jb, 1);
          778         c = (Drecase*)&p->inst[ninst];
          779 
          780         p->start[0] = &p->inst[egetnum(b, ' ', jb)];
          781         p->start[1] = &p->inst[egetnum(b, ' ', jb)];
          782         p->start[2] = &p->inst[egetnum(b, ' ', jb)];
          783         p->start[3] = &p->inst[egetnum(b, '\n', jb)];
          784 
          785         for(j=0; j<ninst; j++){
          786                 l = &p->inst[j];
          787                 l->isfinal = egetnum(b, ' ', jb);
          788                 l->isloop = egetnum(b, ' ', jb);
          789                 l->nc = egetnum(b, 0, jb);
          790                 l->c = c;
          791                 for(k=0; k<l->nc; k++){
          792                         egetc(b, ' ', jb);
          793                         c->start = egetnum(b, ' ', jb);
          794                         c->next = &p->inst[egetnum(b, 0, jb)];
          795                         c++;
          796                 }
          797                 egetc(b, '\n', jb);
          798         }
          799         return p;
          800 }