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