diff options
author | Maximilian Szengel <gnunet@maxsz.de> | 2012-03-30 16:07:39 +0000 |
---|---|---|
committer | Maximilian Szengel <gnunet@maxsz.de> | 2012-03-30 16:07:39 +0000 |
commit | 3a3cb29c454bf15f32ad70c1edc87c957d2a5818 (patch) | |
tree | df5d246fb644e66d96abaf17b19ca85c0fbe18c3 /src/regex/regex.c | |
parent | 5369e360e3d33c2f4c70480f47c178d8ea96948e (diff) | |
download | gnunet-3a3cb29c454bf15f32ad70c1edc87c957d2a5818.tar.gz gnunet-3a3cb29c454bf15f32ad70c1edc87c957d2a5818.zip |
- DLL instead of SList
- comments
Diffstat (limited to 'src/regex/regex.c')
-rw-r--r-- | src/regex/regex.c | 838 |
1 files changed, 418 insertions, 420 deletions
diff --git a/src/regex/regex.c b/src/regex/regex.c index f045d957d..1b7bd8565 100644 --- a/src/regex/regex.c +++ b/src/regex/regex.c | |||
@@ -27,77 +27,87 @@ | |||
27 | #include "gnunet_regex_lib.h" | 27 | #include "gnunet_regex_lib.h" |
28 | #include "regex.h" | 28 | #include "regex.h" |
29 | 29 | ||
30 | void | 30 | /** |
31 | stack_push (struct GNUNET_CONTAINER_SList *stack, const void *buf, size_t len) | 31 | * Context that contains an id counter for states and transitions |
32 | { | 32 | * as well as a DLL of automatons used as a stack for NFA construction. |
33 | GNUNET_CONTAINER_slist_add (stack, GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC, | 33 | */ |
34 | buf, len); | 34 | struct GNUNET_REGEX_Context |
35 | } | ||
36 | |||
37 | int | ||
38 | stack_empty (struct GNUNET_CONTAINER_SList *stack) | ||
39 | { | ||
40 | return 0 == GNUNET_CONTAINER_slist_count (stack); | ||
41 | } | ||
42 | |||
43 | void * | ||
44 | stack_pop (struct GNUNET_CONTAINER_SList *stack, size_t length) | ||
45 | { | 35 | { |
46 | struct GNUNET_CONTAINER_SList_Iterator it; | 36 | unsigned int state_id; |
47 | void *val; | 37 | unsigned int transition_id; |
48 | size_t len; | ||
49 | |||
50 | it = GNUNET_CONTAINER_slist_begin (stack); | ||
51 | val = GNUNET_CONTAINER_slist_get (&it, &len); | ||
52 | GNUNET_assert (length == len); | ||
53 | GNUNET_CONTAINER_slist_erase (&it); | ||
54 | GNUNET_CONTAINER_slist_iter_destroy (&it); | ||
55 | 38 | ||
56 | return val; | 39 | /** |
57 | } | 40 | * DLL of GNUNET_REGEX_Automaton's used as a stack |
41 | */ | ||
42 | struct GNUNET_REGEX_Automaton *stack_head; | ||
43 | struct GNUNET_REGEX_Automaton *stack_tail; | ||
44 | }; | ||
58 | 45 | ||
59 | void * | 46 | /** |
60 | stack_top (struct GNUNET_CONTAINER_SList *stack, size_t * len) | 47 | * Automaton representation |
48 | */ | ||
49 | struct GNUNET_REGEX_Automaton | ||
61 | { | 50 | { |
62 | struct GNUNET_CONTAINER_SList_Iterator it; | 51 | struct GNUNET_REGEX_Automaton *prev; |
52 | struct GNUNET_REGEX_Automaton *next; | ||
63 | 53 | ||
64 | if (stack_empty (stack)) | 54 | struct State *start; |
65 | return NULL; | 55 | struct State *end; |
66 | 56 | ||
67 | return GNUNET_CONTAINER_slist_get (&it, len); | 57 | struct State *states_head; |
68 | } | 58 | struct State *states_tail; |
59 | }; | ||
69 | 60 | ||
61 | /** | ||
62 | * A state. Can be used in DFA and NFA automatons. | ||
63 | */ | ||
70 | struct State | 64 | struct State |
71 | { | 65 | { |
66 | struct State *prev; | ||
67 | struct State *next; | ||
68 | |||
72 | unsigned int id; | 69 | unsigned int id; |
73 | int accepting; | 70 | int accepting; |
74 | int marked; | 71 | int marked; |
75 | char *name; | 72 | char *name; |
76 | struct GNUNET_CONTAINER_SList *transitions; | ||
77 | struct GNUNET_CONTAINER_SList *nfa_set; | ||
78 | }; | ||
79 | 73 | ||
80 | struct GNUNET_REGEX_Automaton | 74 | struct Transition *transitions_head; |
81 | { | 75 | struct Transition *transitions_tail; |
82 | struct State *start; | 76 | |
83 | struct State *end; | 77 | struct StateSet *nfa_set; |
84 | struct GNUNET_CONTAINER_SList *states; | ||
85 | }; | 78 | }; |
86 | 79 | ||
80 | /** | ||
81 | * Transition between two states. Each state can have 0-n transitions. | ||
82 | * If literal is 0, this is considered to be an epsilon transition. | ||
83 | */ | ||
87 | struct Transition | 84 | struct Transition |
88 | { | 85 | { |
86 | struct Transition *prev; | ||
87 | struct Transition *next; | ||
88 | |||
89 | unsigned int id; | 89 | unsigned int id; |
90 | char literal; | 90 | char literal; |
91 | struct State *state; | 91 | struct State *state; |
92 | }; | 92 | }; |
93 | 93 | ||
94 | struct GNUNET_REGEX_Context | 94 | /** |
95 | * Set of states | ||
96 | */ | ||
97 | struct StateSet | ||
95 | { | 98 | { |
96 | unsigned int state_id; | 99 | /** |
97 | unsigned int transition_id; | 100 | * Array of states |
98 | struct GNUNET_CONTAINER_SList *stack; | 101 | */ |
102 | struct State **states; | ||
103 | unsigned int len; | ||
99 | }; | 104 | }; |
100 | 105 | ||
106 | /** | ||
107 | * Initialize a new context | ||
108 | * | ||
109 | * @param ctx context | ||
110 | */ | ||
101 | void | 111 | void |
102 | GNUNET_REGEX_context_init (struct GNUNET_REGEX_Context *ctx) | 112 | GNUNET_REGEX_context_init (struct GNUNET_REGEX_Context *ctx) |
103 | { | 113 | { |
@@ -108,14 +118,8 @@ GNUNET_REGEX_context_init (struct GNUNET_REGEX_Context *ctx) | |||
108 | } | 118 | } |
109 | ctx->state_id = 0; | 119 | ctx->state_id = 0; |
110 | ctx->transition_id = 0; | 120 | ctx->transition_id = 0; |
111 | ctx->stack = GNUNET_CONTAINER_slist_create (); | 121 | ctx->stack_head = NULL; |
112 | } | 122 | ctx->stack_tail = NULL; |
113 | |||
114 | void | ||
115 | GNUNET_REGEX_context_destroy (struct GNUNET_REGEX_Context *ctx) | ||
116 | { | ||
117 | if (NULL != ctx->stack) | ||
118 | GNUNET_CONTAINER_slist_destroy (ctx->stack); | ||
119 | } | 123 | } |
120 | 124 | ||
121 | void | 125 | void |
@@ -127,35 +131,27 @@ debug_print_state (struct State *s) | |||
127 | } | 131 | } |
128 | 132 | ||
129 | void | 133 | void |
130 | debug_print_states (struct GNUNET_CONTAINER_SList *states) | 134 | debug_print_states (struct StateSet *sset) |
131 | { | 135 | { |
132 | struct GNUNET_CONTAINER_SList_Iterator it; | ||
133 | struct State *s; | 136 | struct State *s; |
137 | int i; | ||
134 | 138 | ||
135 | for (it = GNUNET_CONTAINER_slist_begin (states); | 139 | for (i = 0; i < sset->len; i++) |
136 | GNUNET_YES != GNUNET_CONTAINER_slist_end (&it); | ||
137 | GNUNET_CONTAINER_slist_next (&it)) | ||
138 | { | 140 | { |
139 | s = GNUNET_CONTAINER_slist_get (&it, NULL); | 141 | s = sset->states[i]; |
140 | debug_print_state (s); | 142 | debug_print_state (s); |
141 | } | 143 | } |
142 | GNUNET_CONTAINER_slist_iter_destroy (&it); | ||
143 | } | 144 | } |
144 | 145 | ||
145 | void | 146 | void |
146 | debug_print_transitions (struct State *s) | 147 | debug_print_transitions (struct State *s) |
147 | { | 148 | { |
148 | struct GNUNET_CONTAINER_SList_Iterator it; | ||
149 | struct Transition *t; | 149 | struct Transition *t; |
150 | char *state; | 150 | char *state; |
151 | char literal; | 151 | char literal; |
152 | 152 | ||
153 | for (it = GNUNET_CONTAINER_slist_begin (s->transitions); | 153 | for (t = s->transitions_head; NULL != t; t = t->next) |
154 | GNUNET_YES != GNUNET_CONTAINER_slist_end (&it); | ||
155 | GNUNET_CONTAINER_slist_next (&it)) | ||
156 | { | 154 | { |
157 | t = GNUNET_CONTAINER_slist_get (&it, NULL); | ||
158 | |||
159 | if (0 == t->literal) | 155 | if (0 == t->literal) |
160 | literal = '0'; | 156 | literal = '0'; |
161 | else | 157 | else |
@@ -169,73 +165,45 @@ debug_print_transitions (struct State *s) | |||
169 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transition %i: On %c to %s\n", t->id, | 165 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transition %i: On %c to %s\n", t->id, |
170 | literal, state); | 166 | literal, state); |
171 | } | 167 | } |
172 | |||
173 | GNUNET_CONTAINER_slist_iter_destroy (&it); | ||
174 | } | 168 | } |
175 | 169 | ||
170 | /** | ||
171 | * Compare to state sets by comparing the id's of the states that are | ||
172 | * contained in each set. | ||
173 | * | ||
174 | * @param sset1 first state set | ||
175 | * @param sset2 second state set | ||
176 | * | ||
177 | * @return 0 if they are equal, non 0 otherwise | ||
178 | */ | ||
176 | int | 179 | int |
177 | set_compare (const void *buf1, const size_t len1, const void *buf2, | 180 | state_set_compare (struct StateSet *sset1, struct StateSet *sset2) |
178 | const size_t len2) | ||
179 | { | 181 | { |
180 | int c1; | ||
181 | int c2; | ||
182 | struct GNUNET_CONTAINER_SList_Iterator it1; | ||
183 | struct GNUNET_CONTAINER_SList_Iterator it2; | ||
184 | struct State *s1; | 182 | struct State *s1; |
185 | struct State *s2; | 183 | struct State *s2; |
186 | struct GNUNET_CONTAINER_SList *l1; | 184 | int i1; |
187 | struct GNUNET_CONTAINER_SList *l2; | 185 | int i2; |
188 | const void *el1; | ||
189 | const void *el2; | ||
190 | size_t length1; | ||
191 | size_t length2; | ||
192 | int rslt; | ||
193 | int contains; | 186 | int contains; |
187 | int rslt; | ||
194 | 188 | ||
195 | if (len1 != len2 && len1 != sizeof (struct State) && | 189 | if (sset1->len < 1 || sset2->len < 1) |
196 | len2 != sizeof (struct State)) | 190 | return -1; |
197 | return 1; | ||
198 | |||
199 | s1 = (struct State *) buf1; | ||
200 | s2 = (struct State *) buf2; | ||
201 | |||
202 | l1 = s1->nfa_set; | ||
203 | l2 = s2->nfa_set; | ||
204 | |||
205 | c1 = GNUNET_CONTAINER_slist_count (l1); | ||
206 | c2 = GNUNET_CONTAINER_slist_count (l2); | ||
207 | |||
208 | if (c1 != c2) | ||
209 | return ((c1 > c2) ? 1 : -1); | ||
210 | 191 | ||
211 | rslt = 0; | 192 | rslt = 0; |
212 | 193 | ||
213 | for (it1 = GNUNET_CONTAINER_slist_begin (l1); | 194 | for (i1 = 0; i1 < sset1->len; i1++) |
214 | GNUNET_YES != GNUNET_CONTAINER_slist_end (&it1); | ||
215 | GNUNET_CONTAINER_slist_next (&it1)) | ||
216 | { | 195 | { |
217 | el1 = GNUNET_CONTAINER_slist_get (&it1, &length1); | 196 | s1 = sset1->states[i1]; |
218 | contains = 0; | 197 | contains = 0; |
219 | 198 | for (i2 = 0; i2 < sset2->len; i2++) | |
220 | for (it2 = GNUNET_CONTAINER_slist_begin (l2); | ||
221 | GNUNET_YES != GNUNET_CONTAINER_slist_end (&it2); | ||
222 | GNUNET_CONTAINER_slist_next (&it2)) | ||
223 | { | 199 | { |
224 | el2 = GNUNET_CONTAINER_slist_get (&it2, &length2); | 200 | s2 = sset2->states[i2]; |
225 | 201 | if (s1->id == s2->id) | |
226 | if (length1 != length2) | ||
227 | { | ||
228 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
229 | "Comparing lists failed, element size mismatch\n"); | ||
230 | break; | ||
231 | } | ||
232 | if (((struct State *) el1)->id == ((struct State *) el2)->id) | ||
233 | { | 202 | { |
234 | contains = 1; | 203 | contains = 1; |
235 | break; | 204 | break; |
236 | } | 205 | } |
237 | } | 206 | } |
238 | GNUNET_CONTAINER_slist_iter_destroy (&it2); | ||
239 | 207 | ||
240 | if (0 == contains) | 208 | if (0 == contains) |
241 | { | 209 | { |
@@ -243,40 +211,45 @@ set_compare (const void *buf1, const size_t len1, const void *buf2, | |||
243 | break; | 211 | break; |
244 | } | 212 | } |
245 | } | 213 | } |
246 | GNUNET_CONTAINER_slist_iter_destroy (&it1); | ||
247 | |||
248 | return rslt; | 214 | return rslt; |
249 | } | 215 | } |
250 | 216 | ||
217 | /** | ||
218 | * Checks if 'elem' is contained in 'set' | ||
219 | * | ||
220 | * @param set set of states | ||
221 | * @param elem state | ||
222 | * | ||
223 | * @return GNUNET_YES if 'set' contains 'elem, GNUNET_NO otherwise | ||
224 | */ | ||
251 | int | 225 | int |
252 | transition_literal_compare (const void *buf1, const size_t len1, | 226 | state_set_contains (struct StateSet *set, struct State *elem) |
253 | const void *buf2, const size_t len2) | ||
254 | { | 227 | { |
255 | struct Transition *t1; | 228 | struct State *s; |
256 | struct Transition *t2; | 229 | int i; |
257 | 230 | ||
258 | if (len1 != len2 && len1 != sizeof (struct Transition) && | 231 | for (i = 0; i < set->len; i++) |
259 | len2 != sizeof (struct Transition)) | ||
260 | { | 232 | { |
261 | return 1; | 233 | s = set->states[i]; |
234 | if (0 == memcmp (s, elem, sizeof (struct State))) | ||
235 | return GNUNET_YES; | ||
262 | } | 236 | } |
263 | 237 | return GNUNET_NO; | |
264 | t1 = (struct Transition *) buf1; | ||
265 | t2 = (struct Transition *) buf2; | ||
266 | |||
267 | if (t1->literal == t2->literal) | ||
268 | return 0; | ||
269 | else if (t1->literal > t2->literal) | ||
270 | return 1; | ||
271 | else | ||
272 | return -1; | ||
273 | } | 238 | } |
274 | 239 | ||
240 | /** | ||
241 | * Adds a transition from one state to another on 'literal' | ||
242 | * | ||
243 | * @param ctx context | ||
244 | * @param from_state starting state for the transition | ||
245 | * @param literal transition label | ||
246 | * @param to_state state to where the transition should point to | ||
247 | */ | ||
275 | void | 248 | void |
276 | add_transition (struct GNUNET_REGEX_Context *ctx, struct State *from_state, | 249 | add_transition (struct GNUNET_REGEX_Context *ctx, struct State *from_state, |
277 | const char literal, struct State *to_state) | 250 | const char literal, struct State *to_state) |
278 | { | 251 | { |
279 | struct Transition t; | 252 | struct Transition *t; |
280 | 253 | ||
281 | if (NULL == from_state) | 254 | if (NULL == from_state) |
282 | { | 255 | { |
@@ -284,54 +257,59 @@ add_transition (struct GNUNET_REGEX_Context *ctx, struct State *from_state, | |||
284 | return; | 257 | return; |
285 | } | 258 | } |
286 | 259 | ||
287 | t.id = ctx->transition_id++; | 260 | t = GNUNET_malloc (sizeof (struct Transition)); |
288 | t.literal = literal; | 261 | |
289 | t.state = to_state; | 262 | t->id = ctx->transition_id++; |
263 | t->literal = literal; | ||
264 | t->state = to_state; | ||
290 | 265 | ||
291 | GNUNET_CONTAINER_slist_add (from_state->transitions, | 266 | GNUNET_CONTAINER_DLL_insert (from_state->transitions_head, |
292 | GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, &t, | 267 | from_state->transitions_tail, t); |
293 | sizeof t); | ||
294 | } | 268 | } |
295 | 269 | ||
270 | /** | ||
271 | * Creates a new DFA state based on a set of NFA states. Needs to be freed | ||
272 | * using automaton_destroy_state. | ||
273 | * | ||
274 | * @param ctx context | ||
275 | * @param nfa_states set of NFA states on which the DFA should be based on | ||
276 | * | ||
277 | * @return new DFA state | ||
278 | */ | ||
296 | struct State * | 279 | struct State * |
297 | dfa_create_state (struct GNUNET_REGEX_Context *ctx, | 280 | dfa_state_create (struct GNUNET_REGEX_Context *ctx, struct StateSet *nfa_states) |
298 | struct GNUNET_CONTAINER_SList *states) | ||
299 | { | 281 | { |
300 | struct State *s; | 282 | struct State *s; |
301 | char *name; | 283 | char *name; |
302 | struct GNUNET_CONTAINER_SList_Iterator stateit; | ||
303 | struct GNUNET_CONTAINER_SList_Iterator tranit; | ||
304 | int len = 0; | 284 | int len = 0; |
305 | struct State *cstate; | 285 | struct State *cstate; |
306 | struct Transition *ctran; | 286 | struct Transition *ctran; |
287 | int insert = 1; | ||
288 | struct Transition *t; | ||
289 | int i; | ||
307 | 290 | ||
308 | s = GNUNET_malloc (sizeof (struct State)); | 291 | s = GNUNET_malloc (sizeof (struct State)); |
309 | s->id = ctx->state_id++; | 292 | s->id = ctx->state_id++; |
310 | s->accepting = 0; | 293 | s->accepting = 0; |
311 | s->transitions = GNUNET_CONTAINER_slist_create (); | ||
312 | s->marked = 0; | 294 | s->marked = 0; |
313 | s->name = NULL; | 295 | s->name = NULL; |
314 | 296 | ||
315 | if (NULL == states) | 297 | if (NULL == nfa_states) |
316 | return s; | 298 | return s; |
317 | 299 | ||
318 | s->nfa_set = states; | 300 | s->nfa_set = nfa_states; |
319 | 301 | ||
320 | if (0 == GNUNET_CONTAINER_slist_count (states)) | 302 | if (nfa_states->len < 1) |
321 | return s; | 303 | return s; |
322 | 304 | ||
323 | |||
324 | // Create a name based on 'sset' | 305 | // Create a name based on 'sset' |
325 | s->name = GNUNET_malloc (sizeof (char) * 2); | 306 | s->name = GNUNET_malloc (sizeof (char) * 2); |
326 | strcat (s->name, "{"); | 307 | strcat (s->name, "{"); |
327 | name = NULL; | 308 | name = NULL; |
328 | 309 | ||
329 | for (stateit = GNUNET_CONTAINER_slist_begin (states); | 310 | for (i = 0; i < nfa_states->len; i++) |
330 | GNUNET_NO == GNUNET_CONTAINER_slist_end (&stateit); | ||
331 | GNUNET_CONTAINER_slist_next (&stateit)) | ||
332 | { | 311 | { |
333 | cstate = GNUNET_CONTAINER_slist_get (&stateit, NULL); | 312 | cstate = nfa_states->states[i]; |
334 | GNUNET_CONTAINER_slist_iter_destroy (&tranit); | ||
335 | GNUNET_asprintf (&name, "%i,", cstate->id); | 313 | GNUNET_asprintf (&name, "%i,", cstate->id); |
336 | 314 | ||
337 | if (NULL != name) | 315 | if (NULL != name) |
@@ -344,53 +322,46 @@ dfa_create_state (struct GNUNET_REGEX_Context *ctx, | |||
344 | } | 322 | } |
345 | 323 | ||
346 | // Add a transition for each distinct literal to NULL state | 324 | // Add a transition for each distinct literal to NULL state |
347 | for (tranit = GNUNET_CONTAINER_slist_begin (cstate->transitions); | 325 | for (ctran = cstate->transitions_head; NULL != ctran; ctran = ctran->next) |
348 | GNUNET_NO == GNUNET_CONTAINER_slist_end (&tranit); | ||
349 | GNUNET_CONTAINER_slist_next (&tranit)) | ||
350 | { | 326 | { |
351 | ctran = GNUNET_CONTAINER_slist_get (&tranit, NULL); | 327 | if (0 != ctran->literal) |
352 | if (0 != ctran->literal && | ||
353 | NULL == GNUNET_CONTAINER_slist_contains2 (s->transitions, ctran, | ||
354 | sizeof *ctran, | ||
355 | &transition_literal_compare)) | ||
356 | { | 328 | { |
357 | add_transition (ctx, s, ctran->literal, NULL); | 329 | insert = 1; |
330 | |||
331 | for (t = s->transitions_head; NULL != t; t = t->next) | ||
332 | { | ||
333 | if (t->literal == ctran->literal) | ||
334 | { | ||
335 | insert = 0; | ||
336 | break; | ||
337 | } | ||
338 | } | ||
339 | |||
340 | if (insert) | ||
341 | add_transition (ctx, s, ctran->literal, NULL); | ||
358 | } | 342 | } |
359 | } | 343 | } |
360 | 344 | ||
345 | // If the nfa_states contain an accepting state, the new dfa state is also accepting | ||
361 | if (cstate->accepting) | 346 | if (cstate->accepting) |
362 | s->accepting = 1; | 347 | s->accepting = 1; |
363 | } | 348 | } |
364 | GNUNET_CONTAINER_slist_iter_destroy (&stateit); | ||
365 | 349 | ||
366 | s->name[strlen (s->name) - 1] = '}'; | 350 | s->name[strlen (s->name) - 1] = '}'; |
367 | 351 | ||
368 | return s; | 352 | return s; |
369 | } | 353 | } |
370 | 354 | ||
371 | void | 355 | /** |
372 | dfa_clear_nfa_set (struct GNUNET_CONTAINER_SList *states) | 356 | * Creates a new NFA fragment. Needs to be cleared using automaton_fragment_clear. |
373 | { | 357 | * |
374 | struct GNUNET_CONTAINER_SList_Iterator it; | 358 | * @param start starting state |
375 | struct State *s; | 359 | * @param end end state |
376 | 360 | * | |
377 | for (it = GNUNET_CONTAINER_slist_begin (states); | 361 | * @return new NFA fragment |
378 | GNUNET_YES != GNUNET_CONTAINER_slist_end (&it); | 362 | */ |
379 | GNUNET_CONTAINER_slist_next (&it)) | ||
380 | { | ||
381 | s = GNUNET_CONTAINER_slist_get (&it, NULL); | ||
382 | if (NULL != s->nfa_set) | ||
383 | { | ||
384 | GNUNET_CONTAINER_slist_destroy (s->nfa_set); | ||
385 | s->nfa_set = NULL; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | GNUNET_CONTAINER_slist_iter_destroy (&it); | ||
390 | } | ||
391 | |||
392 | struct GNUNET_REGEX_Automaton * | 363 | struct GNUNET_REGEX_Automaton * |
393 | nfa_create (struct State *start, struct State *end) | 364 | nfa_fragment_create (struct State *start, struct State *end) |
394 | { | 365 | { |
395 | struct GNUNET_REGEX_Automaton *n; | 366 | struct GNUNET_REGEX_Automaton *n; |
396 | 367 | ||
@@ -398,18 +369,12 @@ nfa_create (struct State *start, struct State *end) | |||
398 | 369 | ||
399 | n->start = NULL; | 370 | n->start = NULL; |
400 | n->end = NULL; | 371 | n->end = NULL; |
401 | n->states = GNUNET_CONTAINER_slist_create (); | ||
402 | 372 | ||
403 | if (NULL == start && NULL == end) | 373 | if (NULL == start && NULL == end) |
404 | return n; | 374 | return n; |
405 | 375 | ||
406 | GNUNET_CONTAINER_slist_add (n->states, | 376 | GNUNET_CONTAINER_DLL_insert (n->states_head, n->states_tail, end); |
407 | GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC, end, | 377 | GNUNET_CONTAINER_DLL_insert (n->states_head, n->states_tail, start); |
408 | sizeof *end); | ||
409 | |||
410 | GNUNET_CONTAINER_slist_add (n->states, | ||
411 | GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC, start, | ||
412 | sizeof *start); | ||
413 | 378 | ||
414 | n->start = start; | 379 | n->start = start; |
415 | n->end = end; | 380 | n->end = end; |
@@ -417,38 +382,53 @@ nfa_create (struct State *start, struct State *end) | |||
417 | return n; | 382 | return n; |
418 | } | 383 | } |
419 | 384 | ||
385 | /** | ||
386 | * Adds a list of states to the given automaton 'n'. | ||
387 | * | ||
388 | * @param n automaton to which the states should be added | ||
389 | * @param states_head head of the DLL of states | ||
390 | * @param states_tail tail of the DLL of states | ||
391 | */ | ||
420 | void | 392 | void |
421 | nfa_add_states (struct GNUNET_REGEX_Automaton *n, | 393 | nfa_add_states (struct GNUNET_REGEX_Automaton *n, struct State *states_head, |
422 | struct GNUNET_CONTAINER_SList *states) | 394 | struct State *states_tail) |
423 | { | 395 | { |
424 | // This isn't very pretty. Would be better to use GNUNET_CONTAINER_slist_append, but | 396 | if (NULL == n || NULL == states_head) |
425 | // this function adds to the beginning of dst, which currently breaks "pretty" | 397 | { |
426 | // printing of the graph... | 398 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not add states\n"); |
427 | struct GNUNET_CONTAINER_SList_Iterator i; | 399 | return; |
428 | struct State *s; | 400 | } |
429 | 401 | ||
430 | for (i = GNUNET_CONTAINER_slist_begin (states); | 402 | if (NULL == n->states_head) |
431 | GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES; | 403 | { |
432 | GNUNET_CONTAINER_slist_next (&i)) | 404 | n->states_head = states_head; |
405 | n->states_tail = states_tail; | ||
406 | return; | ||
407 | } | ||
433 | 408 | ||
409 | if (NULL != states_head) | ||
434 | { | 410 | { |
435 | s = GNUNET_CONTAINER_slist_get (&i, NULL); | 411 | n->states_tail->next = states_head; |
436 | GNUNET_CONTAINER_slist_add_end (n->states, | 412 | n->states_tail = states_tail; |
437 | GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC, | ||
438 | s, sizeof *s); | ||
439 | } | 413 | } |
440 | GNUNET_CONTAINER_slist_iter_destroy (&i); | ||
441 | } | 414 | } |
442 | 415 | ||
416 | /** | ||
417 | * Creates a new NFA state. Needs to be freed using automaton_destroy_state. | ||
418 | * | ||
419 | * @param ctx context | ||
420 | * @param accepting is it an accepting state or not | ||
421 | * | ||
422 | * @return new NFA state | ||
423 | */ | ||
443 | struct State * | 424 | struct State * |
444 | nfa_create_state (struct GNUNET_REGEX_Context *ctx, int accepting) | 425 | nfa_state_create (struct GNUNET_REGEX_Context *ctx, int accepting) |
445 | { | 426 | { |
446 | struct State *s; | 427 | struct State *s; |
447 | 428 | ||
448 | s = GNUNET_malloc (sizeof (struct State)); | 429 | s = GNUNET_malloc (sizeof (struct State)); |
449 | s->id = ctx->state_id++; | 430 | s->id = ctx->state_id++; |
450 | s->accepting = accepting; | 431 | s->accepting = accepting; |
451 | s->transitions = GNUNET_CONTAINER_slist_create (); | ||
452 | s->marked = 0; | 432 | s->marked = 0; |
453 | s->name = NULL; | 433 | s->name = NULL; |
454 | GNUNET_asprintf (&s->name, "s%i", s->id); | 434 | GNUNET_asprintf (&s->name, "s%i", s->id); |
@@ -456,44 +436,59 @@ nfa_create_state (struct GNUNET_REGEX_Context *ctx, int accepting) | |||
456 | return s; | 436 | return s; |
457 | } | 437 | } |
458 | 438 | ||
439 | /** | ||
440 | * Clears an automaton fragment. Does not destroy the states inside | ||
441 | * the automaton. | ||
442 | * | ||
443 | * @param a automaton to be cleared | ||
444 | */ | ||
459 | void | 445 | void |
460 | automaton_fragment_clear (struct GNUNET_REGEX_Automaton *a) | 446 | automaton_fragment_clear (struct GNUNET_REGEX_Automaton *a) |
461 | { | 447 | { |
462 | GNUNET_CONTAINER_slist_destroy (a->states); | ||
463 | a->start = NULL; | 448 | a->start = NULL; |
464 | a->end = NULL; | 449 | a->end = NULL; |
450 | a->states_head = NULL; | ||
451 | a->states_tail = NULL; | ||
465 | GNUNET_free (a); | 452 | GNUNET_free (a); |
466 | } | 453 | } |
467 | 454 | ||
455 | /** | ||
456 | * Frees the memory used by State 's' | ||
457 | * | ||
458 | * @param s state that should be destroyed | ||
459 | */ | ||
468 | void | 460 | void |
469 | automaton_destroy_state (struct State *s) | 461 | automaton_destroy_state (struct State *s) |
470 | { | 462 | { |
471 | if (NULL != s->transitions) | 463 | struct Transition *t; |
472 | GNUNET_CONTAINER_slist_destroy (s->transitions); | 464 | struct Transition *next_t; |
465 | |||
473 | if (NULL != s->name) | 466 | if (NULL != s->name) |
474 | GNUNET_free (s->name); | 467 | GNUNET_free (s->name); |
475 | if (NULL != s->nfa_set) | ||
476 | GNUNET_CONTAINER_slist_destroy (s->nfa_set); | ||
477 | GNUNET_free (s); | ||
478 | } | ||
479 | 468 | ||
480 | void | 469 | for (t = s->transitions_head; NULL != t;) |
481 | mark_all_states (struct GNUNET_REGEX_Automaton *n, int marked) | 470 | { |
482 | { | 471 | next_t = t->next; |
483 | struct GNUNET_CONTAINER_SList_Iterator it; | 472 | GNUNET_CONTAINER_DLL_remove (s->transitions_head, s->transitions_tail, t); |
484 | struct State *s; | 473 | GNUNET_free (t); |
474 | t = next_t; | ||
475 | } | ||
485 | 476 | ||
486 | for (it = GNUNET_CONTAINER_slist_begin (n->states); | 477 | if (NULL != s->nfa_set) |
487 | GNUNET_YES != GNUNET_CONTAINER_slist_end (&it); | ||
488 | GNUNET_CONTAINER_slist_next (&it)) | ||
489 | { | 478 | { |
490 | s = GNUNET_CONTAINER_slist_get (&it, NULL); | 479 | if (s->nfa_set->len > 0) |
491 | s->marked = marked; | 480 | GNUNET_free (s->nfa_set->states); |
481 | GNUNET_free (s->nfa_set); | ||
492 | } | 482 | } |
493 | 483 | ||
494 | GNUNET_CONTAINER_slist_iter_destroy (&it); | 484 | GNUNET_free (s); |
495 | } | 485 | } |
496 | 486 | ||
487 | /** | ||
488 | * Pops two NFA fragments (a, b) from the stack and concatenates them (ab) | ||
489 | * | ||
490 | * @param ctx context | ||
491 | */ | ||
497 | void | 492 | void |
498 | nfa_add_concatenation (struct GNUNET_REGEX_Context *ctx) | 493 | nfa_add_concatenation (struct GNUNET_REGEX_Context *ctx) |
499 | { | 494 | { |
@@ -501,24 +496,31 @@ nfa_add_concatenation (struct GNUNET_REGEX_Context *ctx) | |||
501 | struct GNUNET_REGEX_Automaton *b; | 496 | struct GNUNET_REGEX_Automaton *b; |
502 | struct GNUNET_REGEX_Automaton *new; | 497 | struct GNUNET_REGEX_Automaton *new; |
503 | 498 | ||
504 | b = stack_pop (ctx->stack, sizeof (struct GNUNET_REGEX_Automaton)); | 499 | b = ctx->stack_tail; |
505 | a = stack_pop (ctx->stack, sizeof (struct GNUNET_REGEX_Automaton)); | 500 | GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, b); |
501 | a = ctx->stack_tail; | ||
502 | GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, a); | ||
506 | 503 | ||
507 | add_transition (ctx, a->end, 0, b->start); | 504 | add_transition (ctx, a->end, 0, b->start); |
508 | a->end->accepting = 0; | 505 | a->end->accepting = 0; |
509 | b->end->accepting = 1; | 506 | b->end->accepting = 1; |
510 | 507 | ||
511 | new = nfa_create (NULL, NULL); | 508 | new = nfa_fragment_create (NULL, NULL); |
512 | nfa_add_states (new, a->states); | 509 | nfa_add_states (new, a->states_head, a->states_tail); |
513 | nfa_add_states (new, b->states); | 510 | nfa_add_states (new, b->states_head, b->states_tail); |
514 | new->start = a->start; | 511 | new->start = a->start; |
515 | new->end = b->end; | 512 | new->end = b->end; |
516 | automaton_fragment_clear (a); | 513 | automaton_fragment_clear (a); |
517 | automaton_fragment_clear (b); | 514 | automaton_fragment_clear (b); |
518 | 515 | ||
519 | stack_push (ctx->stack, new, sizeof *new); | 516 | GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, new); |
520 | } | 517 | } |
521 | 518 | ||
519 | /** | ||
520 | * Pops a NFA fragment from the stack (a) and adds a new fragment (a*) | ||
521 | * | ||
522 | * @param ctx context | ||
523 | */ | ||
522 | void | 524 | void |
523 | nfa_add_star_op (struct GNUNET_REGEX_Context *ctx) | 525 | nfa_add_star_op (struct GNUNET_REGEX_Context *ctx) |
524 | { | 526 | { |
@@ -527,7 +529,8 @@ nfa_add_star_op (struct GNUNET_REGEX_Context *ctx) | |||
527 | struct State *start; | 529 | struct State *start; |
528 | struct State *end; | 530 | struct State *end; |
529 | 531 | ||
530 | a = stack_pop (ctx->stack, sizeof (struct GNUNET_REGEX_Automaton)); | 532 | a = ctx->stack_tail; |
533 | GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, a); | ||
531 | 534 | ||
532 | if (NULL == a) | 535 | if (NULL == a) |
533 | { | 536 | { |
@@ -536,8 +539,8 @@ nfa_add_star_op (struct GNUNET_REGEX_Context *ctx) | |||
536 | return; | 539 | return; |
537 | } | 540 | } |
538 | 541 | ||
539 | start = nfa_create_state (ctx, 0); | 542 | start = nfa_state_create (ctx, 0); |
540 | end = nfa_create_state (ctx, 1); | 543 | end = nfa_state_create (ctx, 1); |
541 | 544 | ||
542 | add_transition (ctx, start, 0, a->start); | 545 | add_transition (ctx, start, 0, a->start); |
543 | add_transition (ctx, start, 0, end); | 546 | add_transition (ctx, start, 0, end); |
@@ -547,25 +550,37 @@ nfa_add_star_op (struct GNUNET_REGEX_Context *ctx) | |||
547 | a->end->accepting = 0; | 550 | a->end->accepting = 0; |
548 | end->accepting = 1; | 551 | end->accepting = 1; |
549 | 552 | ||
550 | new = nfa_create (start, end); | 553 | new = nfa_fragment_create (start, end); |
551 | nfa_add_states (new, a->states); | 554 | nfa_add_states (new, a->states_head, a->states_tail); |
552 | automaton_fragment_clear (a); | 555 | automaton_fragment_clear (a); |
553 | 556 | ||
554 | stack_push (ctx->stack, new, sizeof *new); | 557 | GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, new); |
555 | } | 558 | } |
556 | 559 | ||
560 | /** | ||
561 | * Pops an NFA fragment (a) from the stack and adds a new fragment (a+) | ||
562 | * | ||
563 | * @param ctx context | ||
564 | */ | ||
557 | void | 565 | void |
558 | nfa_add_plus_op (struct GNUNET_REGEX_Context *ctx) | 566 | nfa_add_plus_op (struct GNUNET_REGEX_Context *ctx) |
559 | { | 567 | { |
560 | struct GNUNET_REGEX_Automaton *a; | 568 | struct GNUNET_REGEX_Automaton *a; |
561 | 569 | ||
562 | a = stack_pop (ctx->stack, sizeof (struct GNUNET_REGEX_Automaton)); | 570 | a = ctx->stack_tail; |
571 | GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, a); | ||
563 | 572 | ||
564 | add_transition (ctx, a->end, 0, a->start); | 573 | add_transition (ctx, a->end, 0, a->start); |
565 | 574 | ||
566 | stack_push (ctx->stack, a, sizeof *a); | 575 | GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, a); |
567 | } | 576 | } |
568 | 577 | ||
578 | /** | ||
579 | * Pops two NFA fragments (a, b) from the stack and adds a new NFA fragment | ||
580 | * that alternates between a and b (a|b) | ||
581 | * | ||
582 | * @param ctx context | ||
583 | */ | ||
569 | void | 584 | void |
570 | nfa_add_alternation (struct GNUNET_REGEX_Context *ctx) | 585 | nfa_add_alternation (struct GNUNET_REGEX_Context *ctx) |
571 | { | 586 | { |
@@ -575,11 +590,13 @@ nfa_add_alternation (struct GNUNET_REGEX_Context *ctx) | |||
575 | struct State *start; | 590 | struct State *start; |
576 | struct State *end; | 591 | struct State *end; |
577 | 592 | ||
578 | b = stack_pop (ctx->stack, sizeof (struct GNUNET_REGEX_Automaton)); | 593 | b = ctx->stack_tail; |
579 | a = stack_pop (ctx->stack, sizeof (struct GNUNET_REGEX_Automaton)); | 594 | GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, b); |
595 | a = ctx->stack_tail; | ||
596 | GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, a); | ||
580 | 597 | ||
581 | start = nfa_create_state (ctx, 0); | 598 | start = nfa_state_create (ctx, 0); |
582 | end = nfa_create_state (ctx, 1); | 599 | end = nfa_state_create (ctx, 1); |
583 | add_transition (ctx, start, 0, a->start); | 600 | add_transition (ctx, start, 0, a->start); |
584 | add_transition (ctx, start, 0, b->start); | 601 | add_transition (ctx, start, 0, b->start); |
585 | 602 | ||
@@ -590,15 +607,21 @@ nfa_add_alternation (struct GNUNET_REGEX_Context *ctx) | |||
590 | b->end->accepting = 0; | 607 | b->end->accepting = 0; |
591 | end->accepting = 1; | 608 | end->accepting = 1; |
592 | 609 | ||
593 | new = nfa_create (start, end); | 610 | new = nfa_fragment_create (start, end); |
594 | nfa_add_states (new, a->states); | 611 | nfa_add_states (new, a->states_head, a->states_tail); |
595 | nfa_add_states (new, b->states); | 612 | nfa_add_states (new, b->states_head, b->states_tail); |
596 | automaton_fragment_clear (a); | 613 | automaton_fragment_clear (a); |
597 | automaton_fragment_clear (b); | 614 | automaton_fragment_clear (b); |
598 | 615 | ||
599 | stack_push (ctx->stack, new, sizeof *new); | 616 | GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, new); |
600 | } | 617 | } |
601 | 618 | ||
619 | /** | ||
620 | * Adds a new nfa fragment to the stack | ||
621 | * | ||
622 | * @param ctx context | ||
623 | * @param lit literal for nfa transition | ||
624 | */ | ||
602 | void | 625 | void |
603 | nfa_add_literal (struct GNUNET_REGEX_Context *ctx, const char lit) | 626 | nfa_add_literal (struct GNUNET_REGEX_Context *ctx, const char lit) |
604 | { | 627 | { |
@@ -606,121 +629,112 @@ nfa_add_literal (struct GNUNET_REGEX_Context *ctx, const char lit) | |||
606 | struct State *start; | 629 | struct State *start; |
607 | struct State *end; | 630 | struct State *end; |
608 | 631 | ||
609 | start = nfa_create_state (ctx, 0); | 632 | GNUNET_assert (NULL != ctx); |
610 | end = nfa_create_state (ctx, 1); | 633 | |
634 | start = nfa_state_create (ctx, 0); | ||
635 | end = nfa_state_create (ctx, 1); | ||
611 | add_transition (ctx, start, lit, end); | 636 | add_transition (ctx, start, lit, end); |
612 | n = nfa_create (start, end); | 637 | n = nfa_fragment_create (start, end); |
613 | stack_push (ctx->stack, n, sizeof *n); | 638 | GNUNET_assert (NULL != n); |
639 | GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, n); | ||
614 | } | 640 | } |
615 | 641 | ||
616 | /** | 642 | /** |
617 | * Calculates the closure set for the given set of states. | 643 | * Calculates the NFA closure set for the given state |
618 | * | 644 | * |
619 | * @param states list of states on which to base the closure on | 645 | * @param s starting point state |
620 | * @param literal transitioning literal for which to base the closure on, | 646 | * @param literal transitioning literal on which to base the closure on, |
621 | * pass 0 for epsilon transition | 647 | * pass 0 for epsilon transition |
622 | * | 648 | * |
623 | * @return nfa closure on literal (epsilon closure if 'literal' == 0) | 649 | * @return nfa closure on 'literal' (epsilon closure if 'literal' is 0) |
624 | */ | 650 | */ |
625 | struct GNUNET_CONTAINER_SList * | 651 | struct StateSet * |
626 | create_nfa_closure (struct GNUNET_CONTAINER_SList *states, const char literal) | 652 | nfa_closure_create (struct State *s, const char literal) |
627 | { | 653 | { |
628 | struct GNUNET_CONTAINER_SList_Iterator stateit; | 654 | struct StateSet *cls; |
629 | struct GNUNET_CONTAINER_SList_Iterator tranit; | 655 | struct StateSet *cls_check; |
630 | struct GNUNET_CONTAINER_SList *cls; | ||
631 | struct GNUNET_CONTAINER_SList *cls_check; | ||
632 | struct State *s; | ||
633 | struct State *currentstate; | ||
634 | struct Transition *currenttransition; | ||
635 | struct State *clsstate; | 656 | struct State *clsstate; |
657 | struct State *currentstate; | ||
658 | struct Transition *ctran; | ||
636 | 659 | ||
637 | cls = GNUNET_CONTAINER_slist_create (); | 660 | if (NULL == s) |
661 | return NULL; | ||
638 | 662 | ||
639 | for (stateit = GNUNET_CONTAINER_slist_begin (states); | 663 | cls = GNUNET_malloc (sizeof (struct StateSet)); |
640 | GNUNET_YES != GNUNET_CONTAINER_slist_end (&stateit); | 664 | cls_check = GNUNET_malloc (sizeof (struct StateSet)); |
641 | GNUNET_CONTAINER_slist_next (&stateit)) | ||
642 | { | ||
643 | s = GNUNET_CONTAINER_slist_get (&stateit, NULL); | ||
644 | cls_check = GNUNET_CONTAINER_slist_create (); | ||
645 | 665 | ||
646 | // Add start state to closure only for epsilon closure | 666 | // Add start state to closure only for epsilon closure |
647 | if (0 == literal) | 667 | if (0 == literal) |
648 | { | 668 | GNUNET_array_append (cls->states, cls->len, s); |
649 | GNUNET_CONTAINER_slist_add (cls, | ||
650 | GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC, s, | ||
651 | sizeof *s); | ||
652 | } | ||
653 | 669 | ||
654 | stack_push (cls_check, s, sizeof *s); | 670 | GNUNET_array_append (cls_check->states, cls_check->len, s); |
671 | while (cls_check->len > 0) | ||
672 | { | ||
673 | currentstate = cls_check->states[cls_check->len - 1]; | ||
674 | GNUNET_array_grow (cls_check->states, cls_check->len, cls_check->len - 1); | ||
655 | 675 | ||
656 | while (!stack_empty (cls_check)) | 676 | for (ctran = currentstate->transitions_head; NULL != ctran; |
677 | ctran = ctran->next) | ||
657 | { | 678 | { |
658 | currentstate = stack_pop (cls_check, sizeof (struct State)); | 679 | if (NULL != ctran->state && literal == ctran->literal) |
659 | |||
660 | for (tranit = GNUNET_CONTAINER_slist_begin (currentstate->transitions); | ||
661 | GNUNET_CONTAINER_slist_end (&tranit) != GNUNET_YES; | ||
662 | GNUNET_CONTAINER_slist_next (&tranit)) | ||
663 | { | 680 | { |
664 | currenttransition = GNUNET_CONTAINER_slist_get (&tranit, NULL); | 681 | clsstate = ctran->state; |
665 | 682 | ||
666 | if (NULL != currenttransition->state && | 683 | if (NULL != clsstate && |
667 | literal == currenttransition->literal) | 684 | GNUNET_YES != state_set_contains (cls, clsstate)) |
668 | { | 685 | { |
669 | clsstate = currenttransition->state; | 686 | GNUNET_array_append (cls->states, cls->len, clsstate); |
670 | 687 | GNUNET_array_append (cls_check->states, cls_check->len, clsstate); | |
671 | if (NULL == clsstate) | ||
672 | break; | ||
673 | |||
674 | if (GNUNET_YES != | ||
675 | GNUNET_CONTAINER_slist_contains (cls, clsstate, sizeof *clsstate)) | ||
676 | { | ||
677 | GNUNET_CONTAINER_slist_add (cls, | ||
678 | GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC, | ||
679 | clsstate, sizeof *clsstate); | ||
680 | stack_push (cls_check, clsstate, sizeof *clsstate); | ||
681 | } | ||
682 | } | 688 | } |
683 | } | 689 | } |
684 | GNUNET_CONTAINER_slist_iter_destroy (&tranit); | ||
685 | } | 690 | } |
686 | |||
687 | GNUNET_assert (stack_empty (cls_check)); | ||
688 | GNUNET_CONTAINER_slist_destroy (cls_check); | ||
689 | } | 691 | } |
690 | GNUNET_CONTAINER_slist_iter_destroy (&stateit); | 692 | GNUNET_assert (0 == cls_check->len); |
693 | GNUNET_free (cls_check); | ||
691 | 694 | ||
692 | return cls; | 695 | return cls; |
693 | } | 696 | } |
694 | 697 | ||
695 | struct GNUNET_CONTAINER_SList * | 698 | /** |
696 | GNUNET_REGEX_move (struct GNUNET_REGEX_Automaton *a, struct State *s, | 699 | * Calculates the closure set for the given set of states. |
697 | const char literal) | 700 | * |
701 | * @param states list of states on which to base the closure on | ||
702 | * @param literal transitioning literal for which to base the closure on, | ||
703 | * pass 0 for epsilon transition | ||
704 | * | ||
705 | * @return nfa closure on 'literal' (epsilon closure if 'literal' is 0) | ||
706 | */ | ||
707 | struct StateSet * | ||
708 | nfa_closure_set_create (struct StateSet *states, const char literal) | ||
698 | { | 709 | { |
699 | struct GNUNET_CONTAINER_SList *l; | 710 | struct State *s; |
700 | struct GNUNET_CONTAINER_SList_Iterator it; | 711 | struct StateSet *sset; |
701 | struct Transition *ctran; | 712 | struct StateSet *cls; |
713 | int i; | ||
714 | int j; | ||
702 | 715 | ||
703 | if (!GNUNET_CONTAINER_slist_contains (a->states, s, sizeof *s)) | 716 | if (NULL == states) |
704 | { | ||
705 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
706 | "State %s is not part of the given automaton", s->name); | ||
707 | return NULL; | 717 | return NULL; |
708 | } | ||
709 | 718 | ||
710 | l = GNUNET_CONTAINER_slist_create (); | 719 | cls = GNUNET_malloc (sizeof (struct StateSet)); |
711 | 720 | ||
712 | for (it = GNUNET_CONTAINER_slist_begin (s->transitions); | 721 | for (i = 0; i < states->len; i++) |
713 | GNUNET_YES != GNUNET_CONTAINER_slist_end (&it); | ||
714 | GNUNET_CONTAINER_slist_next (&it)) | ||
715 | { | 722 | { |
716 | ctran = GNUNET_CONTAINER_slist_get (&it, NULL); | 723 | s = states->states[i]; |
717 | if (literal == ctran->literal) | 724 | sset = nfa_closure_create (s, literal); |
718 | GNUNET_CONTAINER_slist_add (l, GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC, | 725 | |
719 | ctran->state, sizeof *(ctran->state)); | 726 | for (j = 0; j < sset->len; j++) |
727 | GNUNET_array_append (cls->states, cls->len, sset->states[j]); | ||
728 | |||
729 | if (NULL != sset) | ||
730 | { | ||
731 | if (sset->len > 0) | ||
732 | GNUNET_free (sset->states); | ||
733 | GNUNET_free (sset); | ||
734 | } | ||
720 | } | 735 | } |
721 | GNUNET_CONTAINER_slist_iter_destroy (&it); | ||
722 | 736 | ||
723 | return l; | 737 | return cls; |
724 | } | 738 | } |
725 | 739 | ||
726 | /** | 740 | /** |
@@ -729,10 +743,10 @@ GNUNET_REGEX_move (struct GNUNET_REGEX_Automaton *a, struct State *s, | |||
729 | * @param regex regular expression string | 743 | * @param regex regular expression string |
730 | * @param len length of the string | 744 | * @param len length of the string |
731 | * | 745 | * |
732 | * @return NFA.Needs to be freed using GNUNET_REGEX_destroy_automaton | 746 | * @return NFA, needs to be freed using GNUNET_REGEX_destroy_automaton |
733 | */ | 747 | */ |
734 | struct GNUNET_REGEX_Automaton * | 748 | struct GNUNET_REGEX_Automaton * |
735 | GNUNET_REGEX_construct_nfa(const char *regex, const size_t len) | 749 | GNUNET_REGEX_construct_nfa (const char *regex, const size_t len) |
736 | { | 750 | { |
737 | struct GNUNET_REGEX_Context ctx; | 751 | struct GNUNET_REGEX_Context ctx; |
738 | struct GNUNET_REGEX_Automaton *nfa; | 752 | struct GNUNET_REGEX_Automaton *nfa; |
@@ -847,9 +861,11 @@ GNUNET_REGEX_construct_nfa(const char *regex, const size_t len) | |||
847 | if (NULL != p) | 861 | if (NULL != p) |
848 | GNUNET_free (p); | 862 | GNUNET_free (p); |
849 | 863 | ||
850 | nfa = stack_pop (ctx.stack, sizeof (struct GNUNET_REGEX_Automaton)); | 864 | nfa = ctx.stack_tail; |
865 | GNUNET_CONTAINER_DLL_remove (ctx.stack_head, ctx.stack_tail, nfa); | ||
866 | |||
851 | 867 | ||
852 | if (!stack_empty (ctx.stack)) | 868 | if (NULL != ctx.stack_head) |
853 | { | 869 | { |
854 | error_msg = "Creating the NFA failed. NFA stack was not empty!"; | 870 | error_msg = "Creating the NFA failed. NFA stack was not empty!"; |
855 | goto error; | 871 | goto error; |
@@ -857,9 +873,7 @@ GNUNET_REGEX_construct_nfa(const char *regex, const size_t len) | |||
857 | 873 | ||
858 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 874 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
859 | "Created NFA with %i States and a total of %i Transitions\n", | 875 | "Created NFA with %i States and a total of %i Transitions\n", |
860 | GNUNET_CONTAINER_slist_count (nfa->states), ctx.transition_id); | 876 | ctx.state_id, ctx.transition_id); |
861 | |||
862 | GNUNET_REGEX_context_destroy (&ctx); | ||
863 | 877 | ||
864 | return nfa; | 878 | return nfa; |
865 | 879 | ||
@@ -868,10 +882,12 @@ error: | |||
868 | if (NULL != error_msg) | 882 | if (NULL != error_msg) |
869 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", error_msg); | 883 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", error_msg); |
870 | GNUNET_free (p); | 884 | GNUNET_free (p); |
871 | while (!stack_empty (ctx.stack)) | 885 | while (NULL != ctx.stack_tail) |
872 | GNUNET_REGEX_automaton_destroy (stack_pop (ctx.stack, | 886 | { |
873 | sizeof (struct GNUNET_REGEX_Automaton))); | 887 | GNUNET_REGEX_automaton_destroy (ctx.stack_tail); |
874 | GNUNET_REGEX_context_destroy (&ctx); | 888 | GNUNET_CONTAINER_DLL_remove (ctx.stack_head, ctx.stack_tail, |
889 | ctx.stack_tail); | ||
890 | } | ||
875 | return NULL; | 891 | return NULL; |
876 | } | 892 | } |
877 | 893 | ||
@@ -882,31 +898,31 @@ error: | |||
882 | * @param a automaton to be destroyed | 898 | * @param a automaton to be destroyed |
883 | */ | 899 | */ |
884 | void | 900 | void |
885 | GNUNET_REGEX_automaton_destroy(struct GNUNET_REGEX_Automaton *a) | 901 | GNUNET_REGEX_automaton_destroy (struct GNUNET_REGEX_Automaton *a) |
886 | { | 902 | { |
887 | struct GNUNET_CONTAINER_SList_Iterator it; | 903 | struct State *s; |
904 | struct State *next_state; | ||
888 | 905 | ||
889 | if (NULL == a) | 906 | if (NULL == a) |
890 | return; | 907 | return; |
891 | 908 | ||
892 | for (it = GNUNET_CONTAINER_slist_begin (a->states); | 909 | for (s = a->states_head; NULL != s;) |
893 | GNUNET_YES != GNUNET_CONTAINER_slist_end (&it); | ||
894 | GNUNET_CONTAINER_slist_next (&it)) | ||
895 | { | 910 | { |
896 | automaton_destroy_state (GNUNET_CONTAINER_slist_get (&it, NULL)); | 911 | next_state = s->next; |
912 | automaton_destroy_state (s); | ||
913 | s = next_state; | ||
897 | } | 914 | } |
898 | GNUNET_CONTAINER_slist_iter_destroy (&it); | 915 | |
899 | GNUNET_CONTAINER_slist_destroy (a->states); | ||
900 | GNUNET_free (a); | 916 | GNUNET_free (a); |
901 | } | 917 | } |
902 | 918 | ||
903 | /** | 919 | /** |
904 | * Construct DFA for the given 'regex' of lenght 'len' | 920 | * Construct DFA for the given 'regex' of length 'len' |
905 | * | 921 | * |
906 | * @param regex regular expression string | 922 | * @param regex regular expression string |
907 | * @param len length of the regular expression | 923 | * @param len length of the regular expression |
908 | * | 924 | * |
909 | * @return DFA. Needs to be freed using GNUNET_REGEX_destroy_automaton | 925 | * @return DFA, needs to be freed using GNUNET_REGEX_destroy_automaton |
910 | */ | 926 | */ |
911 | struct GNUNET_REGEX_Automaton * | 927 | struct GNUNET_REGEX_Automaton * |
912 | GNUNET_REGEX_construct_dfa (const char *regex, const size_t len) | 928 | GNUNET_REGEX_construct_dfa (const char *regex, const size_t len) |
@@ -914,83 +930,78 @@ GNUNET_REGEX_construct_dfa (const char *regex, const size_t len) | |||
914 | struct GNUNET_REGEX_Context ctx; | 930 | struct GNUNET_REGEX_Context ctx; |
915 | struct GNUNET_REGEX_Automaton *dfa; | 931 | struct GNUNET_REGEX_Automaton *dfa; |
916 | struct GNUNET_REGEX_Automaton *nfa; | 932 | struct GNUNET_REGEX_Automaton *nfa; |
917 | struct GNUNET_CONTAINER_SList *tmp; | 933 | struct StateSet *tmp; |
918 | struct GNUNET_CONTAINER_SList *nfa_set; | 934 | struct StateSet *nfa_set; |
919 | struct GNUNET_CONTAINER_SList *sset; | 935 | struct StateSet *dfa_stack; |
920 | struct GNUNET_CONTAINER_SList *dfa_stack; | 936 | struct Transition *ctran; |
921 | struct GNUNET_CONTAINER_SList_Iterator tranit; | ||
922 | struct Transition *currenttransition; | ||
923 | struct State *dfa_state; | 937 | struct State *dfa_state; |
924 | struct State *new_dfa_state; | 938 | struct State *new_dfa_state; |
925 | struct State *state_contains; | 939 | struct State *state_contains; |
940 | struct State *state_iter; | ||
926 | 941 | ||
927 | GNUNET_REGEX_context_init (&ctx); | 942 | GNUNET_REGEX_context_init (&ctx); |
928 | 943 | ||
929 | // Create NFA | 944 | // Create NFA |
930 | nfa = GNUNET_REGEX_construct_nfa (regex, len); | 945 | nfa = GNUNET_REGEX_construct_nfa (regex, len); |
931 | 946 | ||
932 | dfa_stack = GNUNET_CONTAINER_slist_create (); | ||
933 | |||
934 | // Initialize new dfa | ||
935 | dfa = GNUNET_malloc (sizeof (struct GNUNET_REGEX_Automaton)); | 947 | dfa = GNUNET_malloc (sizeof (struct GNUNET_REGEX_Automaton)); |
936 | dfa->states = GNUNET_CONTAINER_slist_create (); | ||
937 | 948 | ||
938 | // Create DFA start state from epsilon closure | 949 | // Create DFA start state from epsilon closure |
939 | sset = GNUNET_CONTAINER_slist_create (); | 950 | dfa_stack = GNUNET_malloc (sizeof (struct StateSet)); |
940 | GNUNET_CONTAINER_slist_add (sset, GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC, | 951 | nfa_set = nfa_closure_create (nfa->start, 0); |
941 | nfa->start, sizeof *(nfa->start)); | 952 | dfa->start = dfa_state_create (&ctx, nfa_set); |
942 | nfa_set = create_nfa_closure (sset, 0); | 953 | GNUNET_CONTAINER_DLL_insert (dfa->states_head, dfa->states_tail, dfa->start); |
943 | GNUNET_CONTAINER_slist_destroy (sset); | 954 | GNUNET_array_append (dfa_stack->states, dfa_stack->len, dfa->start); |
944 | dfa->start = dfa_create_state (&ctx, nfa_set); | 955 | while (dfa_stack->len > 0) |
945 | GNUNET_CONTAINER_slist_add (dfa->states, | ||
946 | GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC, | ||
947 | dfa->start, sizeof *(dfa->start)); | ||
948 | stack_push (dfa_stack, dfa->start, sizeof *(dfa->start)); | ||
949 | |||
950 | while (!stack_empty (dfa_stack)) | ||
951 | { | 956 | { |
952 | dfa_state = stack_pop (dfa_stack, sizeof (struct State)); | 957 | dfa_state = dfa_stack->states[dfa_stack->len - 1]; |
958 | GNUNET_array_grow (dfa_stack->states, dfa_stack->len, dfa_stack->len - 1); | ||
953 | 959 | ||
954 | for (tranit = GNUNET_CONTAINER_slist_begin (dfa_state->transitions); | 960 | for (ctran = dfa_state->transitions_head; NULL != ctran; |
955 | GNUNET_YES != GNUNET_CONTAINER_slist_end (&tranit); | 961 | ctran = ctran->next) |
956 | GNUNET_CONTAINER_slist_next (&tranit)) | ||
957 | { | 962 | { |
958 | currenttransition = GNUNET_CONTAINER_slist_get (&tranit, NULL); | 963 | if (0 != ctran->literal && NULL == ctran->state) |
959 | |||
960 | if (0 != currenttransition->literal && NULL == currenttransition->state) | ||
961 | { | 964 | { |
962 | tmp = create_nfa_closure (dfa_state->nfa_set, | 965 | tmp = nfa_closure_set_create (dfa_state->nfa_set, ctran->literal); |
963 | currenttransition->literal); | 966 | nfa_set = nfa_closure_set_create (tmp, 0); |
964 | nfa_set = create_nfa_closure (tmp, 0); | 967 | if (NULL != tmp) |
965 | new_dfa_state = dfa_create_state (&ctx, nfa_set); | 968 | { |
966 | GNUNET_CONTAINER_slist_destroy (tmp); | 969 | if (tmp->len > 0) |
967 | 970 | GNUNET_free (tmp->states); | |
968 | state_contains = | 971 | GNUNET_free (tmp); |
969 | GNUNET_CONTAINER_slist_contains2 (dfa->states, new_dfa_state, | 972 | } |
970 | sizeof *new_dfa_state, | 973 | new_dfa_state = dfa_state_create (&ctx, nfa_set); |
971 | &set_compare); | 974 | state_contains = NULL; |
975 | for (state_iter = dfa->states_head; NULL != state_iter; | ||
976 | state_iter = state_iter->next) | ||
977 | { | ||
978 | if (0 == | ||
979 | state_set_compare (state_iter->nfa_set, new_dfa_state->nfa_set)) | ||
980 | state_contains = state_iter; | ||
981 | } | ||
982 | |||
972 | if (NULL == state_contains) | 983 | if (NULL == state_contains) |
973 | { | 984 | { |
974 | GNUNET_CONTAINER_slist_add_end (dfa->states, | 985 | GNUNET_CONTAINER_DLL_insert_tail (dfa->states_head, dfa->states_tail, |
975 | GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC, | 986 | new_dfa_state); |
976 | new_dfa_state, sizeof *new_dfa_state); | 987 | GNUNET_array_append (dfa_stack->states, dfa_stack->len, |
977 | stack_push (dfa_stack, new_dfa_state, sizeof *new_dfa_state); | 988 | new_dfa_state); |
978 | currenttransition->state = new_dfa_state; | 989 | ctran->state = new_dfa_state; |
979 | } | 990 | } |
980 | else | 991 | else |
981 | currenttransition->state = state_contains; | 992 | { |
993 | ctran->state = state_contains; | ||
994 | automaton_destroy_state (new_dfa_state); | ||
995 | } | ||
982 | } | 996 | } |
983 | } | 997 | } |
984 | |||
985 | GNUNET_CONTAINER_slist_iter_destroy (&tranit); | ||
986 | } | 998 | } |
987 | GNUNET_CONTAINER_slist_destroy (dfa_stack); | 999 | |
1000 | GNUNET_free (dfa_stack); | ||
988 | GNUNET_REGEX_automaton_destroy (nfa); | 1001 | GNUNET_REGEX_automaton_destroy (nfa); |
989 | GNUNET_REGEX_context_destroy (&ctx); | ||
990 | dfa_clear_nfa_set (dfa->states); | ||
991 | 1002 | ||
992 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created DFA with %i States\n", | 1003 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created DFA with %i States\n", |
993 | GNUNET_CONTAINER_slist_count (dfa->states)); | 1004 | ctx.state_id); |
994 | 1005 | ||
995 | return dfa; | 1006 | return dfa; |
996 | } | 1007 | } |
@@ -1002,11 +1013,9 @@ GNUNET_REGEX_construct_dfa (const char *regex, const size_t len) | |||
1002 | * @param filename where to save the file | 1013 | * @param filename where to save the file |
1003 | */ | 1014 | */ |
1004 | void | 1015 | void |
1005 | GNUNET_REGEX_automaton_save_graph(struct GNUNET_REGEX_Automaton *a, | 1016 | GNUNET_REGEX_automaton_save_graph (struct GNUNET_REGEX_Automaton *a, |
1006 | const char *filename) | 1017 | const char *filename) |
1007 | { | 1018 | { |
1008 | struct GNUNET_CONTAINER_SList_Iterator stateit; | ||
1009 | struct GNUNET_CONTAINER_SList_Iterator tranit; | ||
1010 | struct State *s; | 1019 | struct State *s; |
1011 | struct Transition *ctran; | 1020 | struct Transition *ctran; |
1012 | char *s_acc = NULL; | 1021 | char *s_acc = NULL; |
@@ -1039,13 +1048,8 @@ GNUNET_REGEX_automaton_save_graph(struct GNUNET_REGEX_Automaton *a, | |||
1039 | start = "digraph G {\nrankdir=LR\n"; | 1048 | start = "digraph G {\nrankdir=LR\n"; |
1040 | fwrite (start, strlen (start), 1, p); | 1049 | fwrite (start, strlen (start), 1, p); |
1041 | 1050 | ||
1042 | for (stateit = GNUNET_CONTAINER_slist_begin (a->states); | 1051 | for (s = a->states_head; NULL != s; s = s->next) |
1043 | GNUNET_YES != GNUNET_CONTAINER_slist_end (&stateit); | ||
1044 | GNUNET_CONTAINER_slist_next (&stateit)) | ||
1045 | { | 1052 | { |
1046 | |||
1047 | s = GNUNET_CONTAINER_slist_get (&stateit, NULL); | ||
1048 | |||
1049 | if (s->accepting) | 1053 | if (s->accepting) |
1050 | { | 1054 | { |
1051 | GNUNET_asprintf (&s_acc, "\"%s\" [shape=doublecircle];\n", s->name); | 1055 | GNUNET_asprintf (&s_acc, "\"%s\" [shape=doublecircle];\n", s->name); |
@@ -1055,12 +1059,8 @@ GNUNET_REGEX_automaton_save_graph(struct GNUNET_REGEX_Automaton *a, | |||
1055 | 1059 | ||
1056 | s->marked = 1; | 1060 | s->marked = 1; |
1057 | 1061 | ||
1058 | for (tranit = GNUNET_CONTAINER_slist_begin (s->transitions); | 1062 | for (ctran = s->transitions_head; NULL != ctran; ctran = ctran->next) |
1059 | GNUNET_YES != GNUNET_CONTAINER_slist_end (&tranit); | ||
1060 | GNUNET_CONTAINER_slist_next (&tranit)) | ||
1061 | { | 1063 | { |
1062 | ctran = GNUNET_CONTAINER_slist_get (&tranit, NULL); | ||
1063 | |||
1064 | if (NULL == ctran->state) | 1064 | if (NULL == ctran->state) |
1065 | { | 1065 | { |
1066 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1066 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
@@ -1083,9 +1083,7 @@ GNUNET_REGEX_automaton_save_graph(struct GNUNET_REGEX_Automaton *a, | |||
1083 | fwrite (s_tran, strlen (s_tran), 1, p); | 1083 | fwrite (s_tran, strlen (s_tran), 1, p); |
1084 | GNUNET_free (s_tran); | 1084 | GNUNET_free (s_tran); |
1085 | } | 1085 | } |
1086 | GNUNET_CONTAINER_slist_iter_destroy (&tranit); | ||
1087 | } | 1086 | } |
1088 | GNUNET_CONTAINER_slist_iter_destroy (&stateit); | ||
1089 | 1087 | ||
1090 | end = "\n}\n"; | 1088 | end = "\n}\n"; |
1091 | fwrite (end, strlen (end), 1, p); | 1089 | fwrite (end, strlen (end), 1, p); |