]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libregexp/rregexec.c
New libregexp and APE ported to native
[plan9front.git] / sys / src / libregexp / rregexec.c
1 #include <u.h>
2 #include <libc.h>
3 #include <regexp.h>
4 #include "regimpl.h"
5
6 typedef struct RethreadQ RethreadQ;
7 struct RethreadQ
8 {
9         Rethread *head;
10         Rethread **tail;
11 };
12
13 int
14 rregexec(Reprog *prog, Rune *str, Resub *sem, int msize)
15 {
16         RethreadQ lists[2], *clist, *nlist, *tmp;
17         Rethread *t, *nextthr, **availthr;
18         Reinst *curinst;
19         Rune *rsp, *rep, endr, last;
20         int i, match, first, gen, pri, matchpri;
21
22         if(msize > NSUBEXPM)
23                 msize = NSUBEXPM;
24
25         if(prog->startinst->gen != 0) {
26                 for(curinst = prog->startinst; curinst < prog->startinst + prog->len; curinst++)
27                         curinst->gen = 0;
28         }
29
30         clist = lists;
31         clist->head = nil;
32         clist->tail = &clist->head;
33         nlist = lists + 1;
34         nlist->head = nil;
35         nlist->tail = &nlist->head;
36
37         for(i = 0; i < prog->nthr; i++)
38                 prog->thrpool[i] = prog->threads + i;
39         availthr = prog->thrpool + prog->nthr;
40
41         pri = matchpri = gen = match = 0;
42         rsp = str;
43         rep = nil;
44         endr = L'\0';
45         if(sem != nil && msize > 0) {
46                 if(sem->rsp != nil)
47                         rsp = sem->rsp;
48                 if(sem->rep != nil && *sem->rep != L'\0') {
49                         rep = sem->rep;
50                         endr = *sem->rep;
51                         *sem->rep = '\0';
52                 }
53         }
54         last = 1;
55         for(; last != L'\0'; rsp++) {
56                 gen++;
57                 last = *rsp;
58                 first = 1;
59                 t = clist->head;
60                 if(t == nil)
61                         goto Start;
62                 curinst = t->pc;
63 Again:
64                 if(curinst->gen == gen)
65                         goto Done;
66                 curinst->gen = gen;
67                 switch(curinst->op) {
68                 case ORUNE:
69                         if(*rsp != curinst->r)
70                                 goto Done;
71                 case OANY: /* fallthrough */
72                 Any:
73                         nextthr = t->next;
74                         t->pc = curinst + 1;
75                         t->next = nil;
76                         *nlist->tail = t;
77                         nlist->tail = &t->next;
78                         if(nextthr == nil)
79                                 break;
80                         t = nextthr;
81                         curinst = t->pc;
82                         goto Again;
83                 case OCLASS:
84                 Class:
85                         if(*rsp < curinst->r)
86                                 goto Done;
87                         if(*rsp > curinst->r1) {
88                                 curinst++;
89                                 goto Class;
90                         }
91                         nextthr = t->next;
92                         t->pc = curinst->a;
93                         t->next = nil;
94                         *nlist->tail = t;
95                         nlist->tail = &t->next;
96                         if(nextthr == nil)
97                                 break;
98                         t = nextthr;
99                         curinst = t->pc;
100                         goto Again;
101                 case ONOTNL:
102                         if(*rsp != L'\n') {
103                                 curinst++;
104                                 goto Again;
105                         }
106                         goto Done;
107                 case OBOL:
108                         if(rsp == str || rsp[-1] == L'\n') {
109                                 curinst++;
110                                 goto Again;
111                         }
112                         goto Done;
113                 case OEOL:
114                         if(*rsp == L'\0' && rep == nil) {
115                                 curinst++;
116                                 goto Again;
117                         }
118                         if(*rsp == '\n')
119                                 goto Any;
120                         goto Done;
121                 case OJMP:
122                         curinst = curinst->a;
123                         goto Again;
124                 case OSPLIT:
125                         nextthr = *--availthr;
126                         nextthr->pc = curinst->b;
127                         if(msize > 0)
128                                 memcpy(nextthr->sem, t->sem, sizeof(Resub)*msize);
129                         nextthr->pri = t->pri;
130                         nextthr->next = t->next;
131                         t->next = nextthr;
132                         curinst = curinst->a;
133                         goto Again;
134                 case OSAVE:
135                         if(curinst->sub < msize)
136                                 t->sem[curinst->sub].rsp = rsp;
137                         curinst++;
138                         goto Again;
139                 case OUNSAVE:
140                         if(curinst->sub == 0) {
141                                 /* "Highest" priority is the left-most longest. */
142                                 if (t->pri > matchpri)
143                                         goto Done;
144                                 match = 1;
145                                 matchpri = t->pri;
146                                 if(sem != nil && msize > 0) {
147                                         memcpy(sem, t->sem, sizeof(Resub)*msize);
148                                         sem->rep = rsp;
149                                 }
150                                 goto Done;
151                         }
152                         if(curinst->sub < msize)
153                                 t->sem[curinst->sub].rep = rsp;
154                         curinst++;
155                         goto Again;
156                 Done:
157                         *availthr++ = t;
158                         t = t->next;
159                         if(t == nil)
160                                 break;
161                         curinst = t->pc;
162                         goto Again;
163                 }
164 Start:
165                 /* Start again once if we haven't found anything. */
166                 if(first == 1 && match == 0) {
167                         first = 0;
168                         t = *--availthr;
169                         if(msize > 0)
170                                 memset(t->sem, 0, sizeof(Resub)*msize);
171                         /* "Lower" priority thread */
172                         t->pri = matchpri = pri++;
173                         t->next = nil;
174                         curinst = prog->startinst;
175                         goto Again;
176                 }
177                 /* If we have a match and no extant threads, we are done. */
178                 if(match == 1 && nlist->head == nil)
179                         break;
180                 tmp = clist;
181                 clist = nlist;
182                 nlist = tmp;
183                 nlist->head = nil;
184                 nlist->tail = &nlist->head;
185         }
186         if(rep != nil)
187                 *rep = endr;
188         return match;
189 }