aboutsummaryrefslogtreecommitdiff
path: root/src/regex/regex.c
diff options
context:
space:
mode:
authorMaximilian Szengel <gnunet@maxsz.de>2012-03-30 16:07:39 +0000
committerMaximilian Szengel <gnunet@maxsz.de>2012-03-30 16:07:39 +0000
commit3a3cb29c454bf15f32ad70c1edc87c957d2a5818 (patch)
treedf5d246fb644e66d96abaf17b19ca85c0fbe18c3 /src/regex/regex.c
parent5369e360e3d33c2f4c70480f47c178d8ea96948e (diff)
downloadgnunet-3a3cb29c454bf15f32ad70c1edc87c957d2a5818.tar.gz
gnunet-3a3cb29c454bf15f32ad70c1edc87c957d2a5818.zip
- DLL instead of SList
- comments
Diffstat (limited to 'src/regex/regex.c')
-rw-r--r--src/regex/regex.c838
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
30void 30/**
31stack_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); 34struct GNUNET_REGEX_Context
35}
36
37int
38stack_empty (struct GNUNET_CONTAINER_SList *stack)
39{
40 return 0 == GNUNET_CONTAINER_slist_count (stack);
41}
42
43void *
44stack_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
59void * 46/**
60stack_top (struct GNUNET_CONTAINER_SList *stack, size_t * len) 47 * Automaton representation
48 */
49struct 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 */
70struct State 64struct 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
80struct 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 */
87struct Transition 84struct 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
94struct GNUNET_REGEX_Context 94/**
95 * Set of states
96 */
97struct 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 */
101void 111void
102GNUNET_REGEX_context_init (struct GNUNET_REGEX_Context *ctx) 112GNUNET_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
114void
115GNUNET_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
121void 125void
@@ -127,35 +131,27 @@ debug_print_state (struct State *s)
127} 131}
128 132
129void 133void
130debug_print_states (struct GNUNET_CONTAINER_SList *states) 134debug_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
145void 146void
146debug_print_transitions (struct State *s) 147debug_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 */
176int 179int
177set_compare (const void *buf1, const size_t len1, const void *buf2, 180state_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 */
251int 225int
252transition_literal_compare (const void *buf1, const size_t len1, 226state_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 */
275void 248void
276add_transition (struct GNUNET_REGEX_Context *ctx, struct State *from_state, 249add_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 */
296struct State * 279struct State *
297dfa_create_state (struct GNUNET_REGEX_Context *ctx, 280dfa_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
371void 355/**
372dfa_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
392struct GNUNET_REGEX_Automaton * 363struct GNUNET_REGEX_Automaton *
393nfa_create (struct State *start, struct State *end) 364nfa_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 */
420void 392void
421nfa_add_states (struct GNUNET_REGEX_Automaton *n, 393nfa_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 */
443struct State * 424struct State *
444nfa_create_state (struct GNUNET_REGEX_Context *ctx, int accepting) 425nfa_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 */
459void 445void
460automaton_fragment_clear (struct GNUNET_REGEX_Automaton *a) 446automaton_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 */
468void 460void
469automaton_destroy_state (struct State *s) 461automaton_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
480void 469 for (t = s->transitions_head; NULL != t;)
481mark_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 */
497void 492void
498nfa_add_concatenation (struct GNUNET_REGEX_Context *ctx) 493nfa_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 */
522void 524void
523nfa_add_star_op (struct GNUNET_REGEX_Context *ctx) 525nfa_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 */
557void 565void
558nfa_add_plus_op (struct GNUNET_REGEX_Context *ctx) 566nfa_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 */
569void 584void
570nfa_add_alternation (struct GNUNET_REGEX_Context *ctx) 585nfa_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 */
602void 625void
603nfa_add_literal (struct GNUNET_REGEX_Context *ctx, const char lit) 626nfa_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 */
625struct GNUNET_CONTAINER_SList * 651struct StateSet *
626create_nfa_closure (struct GNUNET_CONTAINER_SList *states, const char literal) 652nfa_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
695struct GNUNET_CONTAINER_SList * 698/**
696GNUNET_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 */
707struct StateSet *
708nfa_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 */
734struct GNUNET_REGEX_Automaton * 748struct GNUNET_REGEX_Automaton *
735GNUNET_REGEX_construct_nfa(const char *regex, const size_t len) 749GNUNET_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 */
884void 900void
885GNUNET_REGEX_automaton_destroy(struct GNUNET_REGEX_Automaton *a) 901GNUNET_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 */
911struct GNUNET_REGEX_Automaton * 927struct GNUNET_REGEX_Automaton *
912GNUNET_REGEX_construct_dfa (const char *regex, const size_t len) 928GNUNET_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 */
1004void 1015void
1005GNUNET_REGEX_automaton_save_graph(struct GNUNET_REGEX_Automaton *a, 1016GNUNET_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);