dfa.c 14 KB

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