regx.c 16 KB

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