regx.c 16 KB

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