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