]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libregexp/rregexec.c
libregexp: simplify regular expression vm implementation
[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         Rethread *head;
9         Rethread **tail;
10 };
11
12 int
13 rregexec(Reprog *p, Rune *str, Resub *sem, int msize)
14 {
15         RethreadQ lists[2], *clist, *nlist, *tmp;
16         Rethread *t, *next, *pool, *avail;
17         Reinst *ci;
18         Rune *rsp, *rep, endr, r;
19         int matchgen, gen;
20
21         if(msize > NSUBEXPM)
22                 msize = NSUBEXPM;
23
24         if(p->startinst->gen != 0) {
25                 for(ci = p->startinst; ci < p->startinst + p->len; ci++)
26                         ci->gen = 0;
27         }
28
29         memset(p->threads, 0, sizeof(Rethread)*p->nthr);
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         pool = p->threads;
39         avail = nil;
40
41         gen = matchgen = 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         for(r = 1; r != L'\0'; rsp++) {
55                 r = *rsp;
56                 gen++;
57                 if(matchgen == 0) {
58                         if(avail == nil) {
59                                 assert(pool < p->threads + p->nthr);
60                                 t = pool++;
61                         } else {
62                                 t = avail;
63                                 avail = avail->next;
64                         }
65                         t->i = p->startinst;
66                         if(msize > 0)
67                                 memset(t->sem, 0, sizeof(Resub)*msize);
68                         t->next = nil;
69                         t->gen = gen;
70                         *clist->tail = t;
71                         clist->tail = &t->next;
72                 }
73                 t = clist->head;
74                 if(t == nil)
75                         break;
76                 ci = t->i;
77 Again:
78                 if(ci->gen == gen || matchgen && t->gen > matchgen)
79                         goto Done;
80                 ci->gen = gen;
81                 switch(ci->op) {
82                 case ORUNE:
83                         if(r != ci->r)
84                                 goto Done;
85                 case OANY: /* fallthrough */
86                         next = t->next;
87                         t->i = ci + 1;
88                         t->next = nil;
89                         *nlist->tail = t;
90                         nlist->tail = &t->next;
91                         if(next == nil)
92                                 break;
93                         t = next;
94                         ci = t->i;
95                         goto Again;
96                 case OCLASS:
97                 Class:
98                         if(r < ci->r)
99                                 goto Done;
100                         if(r > ci->r1) {
101                                 ci++;
102                                 goto Class;
103                         }
104                         next = t->next;
105                         t->i = ci->a;
106                         t->next = nil;
107                         *nlist->tail = t;
108                         nlist->tail = &t->next;
109                         if(next == nil)
110                                 break;
111                         t = next;
112                         ci = t->i;
113                         goto Again;
114                 case ONOTNL:
115                         if(r != L'\n') {
116                                 ci++;
117                                 goto Again;
118                         }
119                         goto Done;
120                 case OBOL:
121                         if(rsp == str || rsp[-1] == L'\n') {
122                                 ci++;
123                                 goto Again;
124                         }
125                         goto Done;
126                 case OEOL:
127                         if(r == L'\n' || r == L'\0' && rep == nil) {
128                                 ci++;
129                                 goto Again;
130                         }
131                         goto Done;
132                 case OJMP:
133                         ci = ci->a;
134                         goto Again;
135                 case OSPLIT:
136                         if(avail == nil) {
137                                 assert(pool < p->threads + p->nthr);
138                                 next = pool++;
139                         } else {
140                                 next = avail;
141                                 avail = avail->next;
142                         }
143                         next->i = ci->b;
144                         if(msize > 0)
145                                 memcpy(next->sem, t->sem, sizeof(Resub)*msize);
146                         next->next = t->next;
147                         next->gen = t->gen;
148                         t->next = next;
149                         ci = ci->a;
150                         goto Again;
151                 case OSAVE:
152                         if(ci->sub < msize)
153                                 t->sem[ci->sub].rsp = rsp;
154                         ci++;
155                         goto Again;
156                 case OUNSAVE:
157                         if(ci->sub == 0) {
158                                 matchgen = t->gen;
159                                 if(sem != nil && msize > 0) {
160                                         memcpy(sem, t->sem, sizeof(Resub)*msize);
161                                         sem->rep = rsp;
162                                 }
163                                 goto Done;
164                         }
165                         if(ci->sub < msize)
166                                 t->sem[ci->sub].rep = rsp;
167                         ci++;
168                         goto Again;
169                 Done:
170                         next = t->next;
171                         t->next = avail;
172                         avail = t;
173                         if(next == nil)
174                                 break;
175                         t = next;
176                         ci = t->i;
177                         goto Again;
178                 }
179                 tmp = clist;
180                 clist = nlist;
181                 nlist = tmp;
182                 nlist->head = nil;
183                 nlist->tail = &nlist->head;
184         }
185         if(rep != nil)
186                 *rep = endr;
187         return matchgen > 0 ? 1 : 0;
188 }