Algorithms_in_C 1.0.0
Set of algorithms implemented in C.
Loading...
Searching...
No Matches
mcnaughton_yamada_thompson.c File Reference

McNaughton–Yamada–Thompson algorithm More...

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
Include dependency graph for mcnaughton_yamada_thompson.c:

Data Structures

struct  ASTNode
 for assert() More...
 
struct  transRule
 Definition for a NFA state transition rule. More...
 
struct  NFAState
 Definition for a NFA state. More...
 
struct  NFA
 Definition for the NFA itself. More...
 

Functions

struct ASTNodecreateNode (const char content)
 creates and initializes a AST node
 
void destroyNode (struct ASTNode *node)
 recursively destroys a AST
 
char * preProcessing (const char *input)
 performs preprocessing on a regex string, making all implicit concatenations explicit
 
struct ASTNodebuildAST (const char *input)
 recursively constructs a AST from a preprocessed regex string
 
struct transRulecreateRule (struct NFAState *state, char c)
 creates and initializes a transition rule
 
void destroyRule (struct transRule *rule)
 destroys a transition rule object
 
struct NFAStatecreateState (void)
 creates and initializes a NFA state
 
void destroyState (struct NFAState *state)
 destroys a NFA state
 
struct NFAcreateNFA (void)
 creates and initializes a NFA
 
void destroyNFA (struct NFA *nfa)
 recursively destroys a NFA
 
void addState (struct NFA *nfa, struct NFAState *state)
 adds a state to a NFA
 
void addRule (struct NFA *nfa, struct transRule *rule, int loc)
 adds a transition rule to a NFA
 
void postProcessing (struct NFA *nfa)
 performs postprocessing on a compiled NFA, add circular empty character transition rules where it's needed for the NFA to function correctly
 
void transit (struct NFA *nfa, char input)
 moves a NFA forward
 
int isAccepting (const struct NFA *nfa)
 determines whether the NFA is currently in its accepting state
 
int isLiteral (const char ch)
 helper function to determine whether a character should be considered a character literal
 
size_t indexOf (const char *str, char key)
 utility function to locate the first occurrence of a character in a string while respecting parentheses
 
char * subString (const char *str, size_t begin, size_t end)
 utility function to create a subString
 
void redirect (struct NFA *nfa, struct NFAState *src, struct NFAState *dest)
 helper function to recursively redirect transition rule targets
 
struct NFAcompileFromAST (struct ASTNode *root)
 
int contains (struct NFAState **states, int len, struct NFAState *state)
 helper function to determine an element's presence in an array
 
void findEmpty (struct NFAState *target, struct NFAState **states, int *sc)
 helper function to manage empty character transitions
 
void testHelper (const char *regex, const char *string, const int expected)
 Testing helper function.
 
static void test (void)
 Self-test implementations.
 
int main (void)
 Main function.
 

Detailed Description

McNaughton–Yamada–Thompson algorithm

From Wikipedia: In computer science, Thompson's construction algorithm, also called the McNaughton–Yamada–Thompson algorithm, is a method of transforming a regular expression into an equivalent nondeterministic finite automaton (NFA). This implementation implements the all three operations (implicit concatenation, '|' for union, '*' for Kleene star) required by the formal definition of regular expressions.

Author
Sharon Cassidy

Function Documentation

◆ addRule()

void addRule ( struct NFA nfa,
struct transRule rule,
int  loc 
)

adds a transition rule to a NFA

Parameters
nfatarget NFA
rulethe rule to be added
locwhich state this rule should be added to
Returns
void
380 {
381 nfa->rulePool[nfa->ruleCount++] = rule;
382 struct NFAState* state = nfa->statePool[loc];
383 state->rules[state->ruleCount++] = rule;
384}
struct transRule ** rulePool
the pool of all transition rules
Definition mcnaughton_yamada_thompson.c:74
int ruleCount
the total number of transition rules in this NFA
Definition mcnaughton_yamada_thompson.c:73
struct NFAState ** statePool
the pool of all available states
Definition mcnaughton_yamada_thompson.c:72
Definition for a NFA state.
Definition mcnaughton_yamada_thompson.c:54
int ruleCount
number of transition rules this state have
Definition mcnaughton_yamada_thompson.c:55
struct transRule ** rules
the transition rules
Definition mcnaughton_yamada_thompson.c:56

◆ addState()

void addState ( struct NFA nfa,
struct NFAState state 
)

adds a state to a NFA

Parameters
nfatarget NFA
statethe NFA state to be added
Returns
void
369 {
370 nfa->statePool[nfa->stateCount++] = state;
371}
int stateCount
the total number of states this NFA have
Definition mcnaughton_yamada_thompson.c:71

◆ buildAST()

struct ASTNode * buildAST ( const char *  input)

recursively constructs a AST from a preprocessed regex string

Parameters
inputregex
Returns
pointer to the resulting tree
189 {
190
191 struct ASTNode* node = createNode('\0');
192 node->left = NULL;
193 node->right = NULL;
194 const size_t len = strlen(input);
195 size_t index;
196
197 // Empty input
198 if(len == 0) return node;
199
200 // Character literals
201 if(len == 1) {
202 node->content = input[0];
203 return node;
204 }
205
206 // Discard parentheses
207 if(input[0] == '(' && input[len - 1] == ')') {
208 char* temp = subString(input, 1, len - 2);
210 node = buildAST(temp);
211
212 free(temp);
213 return node;
214 }
215
216 // Union
217 index = indexOf(input, '|');
218 if(index) {
219 node->content = '|';
220
221 char* temp1 = subString(input, 0, index - 1);
222 char* temp2 = subString(input, index + 1, len - 1);
223 node->left = buildAST(temp1);
224 node->right = buildAST(temp2);
225
226 free(temp2);
227 free(temp1);
228 return node;
229 }
230
231 // Concatenation
232 index = indexOf(input, '\n');
233 if(index) {
234 node->content = '\n';
235
236 char* temp1 = subString(input, 0, index - 1);
237 char* temp2 = subString(input, index + 1, len - 1);
238 node->left = buildAST(temp1);
239 node->right = buildAST(temp2);
240
241 free(temp2);
242 free(temp1);
243 return node;
244 }
245
246 // Kleene star
247 // Testing with indexOf() is unnecessary here,
248 // Since all other possibilities have been exhausted
249 node->content = '*';
250 char* temp = subString(input, 0, len - 2);
251 node->left = buildAST(temp);
252 node->right = NULL;
253
254 free(temp);
255 return node;
256}
#define free(ptr)
This macro replace the standard free function with free_dbg.
Definition malloc_dbg.h:26
char * subString(const char *str, size_t begin, size_t end)
utility function to create a subString
Definition mcnaughton_yamada_thompson.c:177
struct ASTNode * createNode(char content)
creates and initializes a AST node
Definition mcnaughton_yamada_thompson.c:606
struct ASTNode * buildAST(const char *input)
recursively constructs a AST from a preprocessed regex string
Definition mcnaughton_yamada_thompson.c:189
void destroyNode(struct ASTNode *node)
recursively destroys a AST
Definition mcnaughton_yamada_thompson.c:619
size_t indexOf(const char *str, char key)
utility function to locate the first occurrence of a character in a string while respecting parenthes...
Definition mcnaughton_yamada_thompson.c:151
for assert()
Definition mcnaughton_yamada_thompson.c:27
Node, the basic data structure in the tree.
Definition binary_search_tree.c:15
struct node * right
right child
Definition binary_search_tree.c:17
struct node * left
left child
Definition binary_search_tree.c:16
Here is the call graph for this function:

◆ compileFromAST()

struct NFA * compileFromAST ( struct ASTNode root)
279 {
280
281 struct NFA* nfa = createNFA();
282
283 // Empty input
284 if (root->content == '\0') {
285 addRule(nfa, createRule(nfa->statePool[1], '\0'), 0);
286 return nfa;
287 }
288
289 // Character literals
290 if (isLiteral(root->content)) {
291 addRule(nfa, createRule(nfa->statePool[1], root->content), 0);
292 return nfa;
293 }
294
295 switch (root->content) {
296
297 case '\n': {
298 struct NFA* ln = compileFromAST(root->left);
299 struct NFA* rn = compileFromAST(root->right);
300
301 // Redirects all rules targeting ln's accepting state to
302 // target rn's starting state
303 redirect(ln, ln->statePool[1], rn->statePool[0]);
304
305 // Manually creates and initializes a special
306 // "wrapper" NFA
307 destroyNFA(nfa);
308 struct NFA* wrapper = malloc(sizeof(struct NFA));
309 wrapper->stateCount = 2;
310 wrapper->statePool = malloc(sizeof(struct NFAState*) * 2);
311 wrapper->subCount = 0;
312 wrapper->subs = malloc(sizeof(struct NFA*) * 2);
313 wrapper->ruleCount = 0;
314 wrapper->rulePool = malloc(sizeof(struct transRule*) * 3);
315 wrapper->CSCount = 0;
316 wrapper->currentStates = malloc(sizeof(struct NFAState*) * 2);
317 wrapper->wrapperFlag = 1;
318 wrapper->subs[wrapper->subCount++] = ln;
319 wrapper->subs[wrapper->subCount++] = rn;
320
321 // Maps the wrapper NFA's starting and ending states
322 // to its sub NFAs
323 wrapper->statePool[0] = ln->statePool[0];
324 wrapper->statePool[1] = rn->statePool[1];
325
326 return wrapper;
327 }
328 case '|': {
329
330 struct NFA* ln = compileFromAST(root->left);
331 struct NFA* rn = compileFromAST(root->right);
332 nfa->subs[nfa->subCount++] = ln;
333 nfa->subs[nfa->subCount++] = rn;
334
335 // Adds empty character transition rules
336 addRule(nfa, createRule(ln->statePool[0], '\0'), 0);
337 addRule(ln, createRule(nfa->statePool[1], '\0'), 1);
338 addRule(nfa, createRule(rn->statePool[0], '\0'), 0);
339 addRule(rn, createRule(nfa->statePool[1], '\0'), 1);
340
341 return nfa;
342 }
343 case '*': {
344 struct NFA* ln = compileFromAST(root->left);
345 nfa->subs[nfa->subCount++] = ln;
346
347 addRule(ln, createRule(ln->statePool[0], '\0'), 1);
348 addRule(nfa, createRule(ln->statePool[0], '\0'), 0);
349 addRule(ln, createRule(nfa->statePool[1], '\0'), 1);
350 addRule(nfa, createRule(nfa->statePool[1], '\0'), 0);
351
352 return nfa;
353 }
354 }
355
356 // Fallback, shouldn't happen in normal operation
357 destroyNFA(nfa);
358 return NULL;
359}
#define malloc(bytes)
This macro replace the standard malloc function with malloc_dbg.
Definition malloc_dbg.h:18
struct transRule * createRule(struct NFAState *state, char c)
creates and initializes a transition rule
Definition mcnaughton_yamada_thompson.c:637
struct NFA * createNFA(void)
creates and initializes a NFA
Definition mcnaughton_yamada_thompson.c:678
void addRule(struct NFA *nfa, struct transRule *rule, int loc)
adds a transition rule to a NFA
Definition mcnaughton_yamada_thompson.c:380
void destroyNFA(struct NFA *nfa)
recursively destroys a NFA
Definition mcnaughton_yamada_thompson.c:701
int isLiteral(const char ch)
helper function to determine whether a character should be considered a character literal
Definition mcnaughton_yamada_thompson.c:99
void redirect(struct NFA *nfa, struct NFAState *src, struct NFAState *dest)
helper function to recursively redirect transition rule targets
Definition mcnaughton_yamada_thompson.c:267
Definition for the NFA itself.
Definition mcnaughton_yamada_thompson.c:70
int CSCount
the number of currently active states
Definition mcnaughton_yamada_thompson.c:75
int wrapperFlag
whether this NFA is a concatenation wrapper
Definition mcnaughton_yamada_thompson.c:79
int subCount
the number of sub NFAs
Definition mcnaughton_yamada_thompson.c:77
struct NFA ** subs
the pool of all sub NFAs
Definition mcnaughton_yamada_thompson.c:78
struct NFAState ** currentStates
the pool of all active states
Definition mcnaughton_yamada_thompson.c:76
Definition for a NFA state transition rule.
Definition mcnaughton_yamada_thompson.c:41

◆ contains()

int contains ( struct NFAState **  states,
int  len,
struct NFAState state 
)

helper function to determine an element's presence in an array

Parameters
statestarget array
lenlength of the target array
statethe element to search for
Returns
1 if the element is present, 0 otherwise
428 {
429 int f = 0;
430 for (int i = 0; i < len; ++i) {
431 if(states[i] == state) {
432 f = 1;
433 break;
434 }
435 }
436 return f;
437}

◆ createNFA()

struct NFA * createNFA ( void  )

creates and initializes a NFA

Returns
pointer to the newly created NFA
678 {
679 struct NFA* nfa = malloc(sizeof(struct NFA));
680
681 nfa->stateCount = 0;
682 nfa->statePool = malloc(sizeof(struct NFAState*) * 5);
683 nfa->ruleCount = 0;
684 nfa->rulePool = malloc(sizeof(struct transRule*) * 10);
685 nfa->CSCount = 0;
686 nfa->currentStates = malloc(sizeof(struct NFAState*) * 5);
687 nfa->subCount = 0;
688 nfa->subs = malloc(sizeof(struct NFA*) * 5);
689 nfa->wrapperFlag = 0;
690
691 addState(nfa, createState());
692 addState(nfa, createState());
693 return nfa;
694}
void addState(struct NFA *nfa, struct NFAState *state)
adds a state to a NFA
Definition mcnaughton_yamada_thompson.c:369
struct NFAState * createState(void)
creates and initializes a NFA state
Definition mcnaughton_yamada_thompson.c:657
Here is the call graph for this function:

◆ createNode()

struct ASTNode * createNode ( const char  content)

creates and initializes a AST node

Parameters
contentdata to initializes the node with
Returns
pointer to the newly created node
606 {
607 struct ASTNode* node = malloc(sizeof(struct ASTNode));
608 node->content = content;
609 node->left = NULL;
610 node->right = NULL;
611 return node;
612}
char content
the content of this node
Definition mcnaughton_yamada_thompson.c:28

◆ createRule()

struct transRule * createRule ( struct NFAState state,
char  c 
)

creates and initializes a transition rule

Parameters
statetransition target
ctransition condition
Returns
pointer to the newly created rule
637 {
638 struct transRule* rule = malloc(sizeof(struct transRule));
639 rule->target = state;
640 rule->cond = c;
641 return rule;
642}
struct NFAState * target
pointer to the state to transit to
Definition mcnaughton_yamada_thompson.c:42
char cond
the input required to activate this transition
Definition mcnaughton_yamada_thompson.c:43

◆ createState()

struct NFAState * createState ( void  )

creates and initializes a NFA state

Returns
pointer to the newly created NFA state
657 {
658 struct NFAState* state = malloc(sizeof(struct NFAState));
659 state->ruleCount = 0;
660 state->rules = malloc(sizeof(struct transRule*) * 3);
661 return state;
662}

◆ destroyNFA()

void destroyNFA ( struct NFA nfa)

recursively destroys a NFA

Parameters
nfapointer to the object to be deleted
Returns
void
701 {
702 for (int i = 0; i < nfa->subCount; ++i) {
703 destroyNFA(nfa->subs[i]);
704 }
705
706 // In case of a wrapper NFA, do not free its states
707 // because it doesn't really have any states of its own
708 if (!nfa->wrapperFlag) {
709 for (int i = 0; i < nfa->stateCount; ++i) {
710 destroyState(nfa->statePool[i]);
711 }
712 }
713 for (int i = 0; i < nfa->ruleCount; ++i) {
714 destroyRule(nfa->rulePool[i]);
715 }
716 free(nfa->statePool);
717 free(nfa->currentStates);
718 free(nfa->rulePool);
719 free(nfa->subs);
720 free(nfa);
721}
void destroyState(struct NFAState *state)
destroys a NFA state
Definition mcnaughton_yamada_thompson.c:669
void destroyRule(struct transRule *rule)
destroys a transition rule object
Definition mcnaughton_yamada_thompson.c:649
Here is the call graph for this function:

◆ destroyNode()

void destroyNode ( struct ASTNode node)

recursively destroys a AST

Parameters
nodethe root node of the tree to be deleted
Returns
void
619 {
620 if(node->left != NULL) {
622 }
623
624 if(node->right != NULL) {
626 }
627
628 free(node);
629}
Here is the call graph for this function:

◆ destroyRule()

void destroyRule ( struct transRule rule)

destroys a transition rule object

Parameters
rulepointer to the object to be deleted
Returns
void
649 {
650 free(rule);
651}

◆ destroyState()

void destroyState ( struct NFAState state)

destroys a NFA state

Parameters
statepointer to the object to be deleted
Returns
void
669 {
670 free(state->rules);
671 free(state);
672}

◆ findEmpty()

void findEmpty ( struct NFAState target,
struct NFAState **  states,
int *  sc 
)

helper function to manage empty character transitions

Parameters
targettarget NFA
statespointer to results storage location
scpointer to results count storage location
Returns
void
446 {
447 for (int i = 0; i < target->ruleCount; ++i) {
448 const struct transRule *pRule = target->rules[i];
449
450 if (pRule->cond == '\0' && !contains(states, *sc, pRule->target)) {
451 states[(*sc)++] = pRule->target;
452 // the use of `states` and `sc` is necessary
453 // to sync data across recursion levels
454 findEmpty(pRule->target, states, sc);
455 }
456 }
457}
void findEmpty(struct NFAState *target, struct NFAState **states, int *sc)
helper function to manage empty character transitions
Definition mcnaughton_yamada_thompson.c:446
int contains(struct NFAState **states, int len, struct NFAState *state)
helper function to determine an element's presence in an array
Definition mcnaughton_yamada_thompson.c:428
Here is the call graph for this function:

◆ indexOf()

size_t indexOf ( const char *  str,
char  key 
)

utility function to locate the first occurrence of a character in a string while respecting parentheses

Parameters
strtarget string
keythe character to be located
Returns
the index of its first occurrence, 0 if it could not be found
151 {
152 int depth = 0;
153
154 for (size_t i = 0; i < strlen(str); ++i) {
155 const char c = str[i];
156
157 if(depth == 0 && c == key) {
158 return i;
159 }
160 if(c == '(') depth++;
161 if(c == ')') depth--;
162 }
163 // Due to the way this function is intended to be used,
164 // it's safe to assume the character will not appear as
165 // the string's first character
166 // thus `0` is used as the `not found` value
167 return 0;
168}

◆ isAccepting()

int isAccepting ( const struct NFA nfa)

determines whether the NFA is currently in its accepting state

Parameters
nfatarget NFA
Returns
1 if the NFA is in its accepting state
0 otherwise
522 {
523 for (int i = 0; i < nfa->CSCount; ++i) {
524 if(nfa->currentStates[i] == nfa->statePool[1]) {
525 return 1;
526 }
527 }
528 return 0;
529}

◆ isLiteral()

int isLiteral ( const char  ch)

helper function to determine whether a character should be considered a character literal

Parameters
chthe character to be tested
Returns
1 if it is a character literal
0 otherwise
99 {
100 return !(ch == '(' || ch == ')' || ch == '*' || ch == '\n' || ch == '|');
101}

◆ main()

int main ( void  )

Main function.

Returns
0 on exit
593 {
594 test(); // run self-test implementations
595 return 0;
596}
static void test(void)
Self-test implementations.
Definition mcnaughton_yamada_thompson.c:572
Here is the call graph for this function:

◆ postProcessing()

void postProcessing ( struct NFA nfa)

performs postprocessing on a compiled NFA, add circular empty character transition rules where it's needed for the NFA to function correctly

Parameters
nfatarget NFA
Returns
void
393 {
394 // Since the sub NFA's states and rules are managed
395 // through their own pools, recursion is necessary
396 for (int i = 0; i < nfa->subCount; ++i) {
397 postProcessing(nfa->subs[i]);
398 }
399
400 // If a state does not have any empty character accepting rule,
401 // we add a rule that circles back to itself
402 // So this state will be preserved when
403 // empty characters are inputted
404 for (int i = 0; i < nfa->stateCount; ++i) {
405
406 struct NFAState* pState = nfa->statePool[i];
407 int f = 0;
408 for (int j = 0; j < pState->ruleCount; ++j) {
409 if(pState->rules[j]->cond == '\0') {
410 f = 1;
411 break;
412 }
413 }
414
415 if (!f) {
416 addRule(nfa, createRule(pState, '\0'), i);
417 }
418 }
419}
void postProcessing(struct NFA *nfa)
performs postprocessing on a compiled NFA, add circular empty character transition rules where it's n...
Definition mcnaughton_yamada_thompson.c:393
Here is the call graph for this function:

◆ preProcessing()

char * preProcessing ( const char *  input)

performs preprocessing on a regex string, making all implicit concatenations explicit

Parameters
inputtarget regex string
Returns
pointer to the processing result
109 {
110 const size_t len = strlen(input);
111 if(len == 0) {
112 char* str = malloc(1);
113 str[0] = '\0';
114 return str;
115 }
116
117 char* str = malloc(len * 2);
118 size_t op = 0;
119
120 for (size_t i = 0; i < len - 1; ++i) {
121 char c = input[i];
122 str[op++] = c;
123 // one character lookahead
124 char c1 = input[i + 1];
125
126 if( (isLiteral(c) && isLiteral(c1)) ||
127 (isLiteral(c) && c1 == '(') ||
128 (c == ')' && c1 == '(') ||
129 (c == ')' && isLiteral(c1)) ||
130 (c == '*' && isLiteral(c1)) ||
131 (c == '*' && c1 == '(')
132 ) {
133 // '\n' is used to represent concatenation
134 // in this implementation
135 str[op++] = '\n';
136 }
137 }
138
139 str[op++] = input[len - 1];
140 str[op] = '\0';
141 return str;
142}
Here is the call graph for this function:

◆ redirect()

void redirect ( struct NFA nfa,
struct NFAState src,
struct NFAState dest 
)

helper function to recursively redirect transition rule targets

Parameters
nfatarget NFA
srcthe state to redirect away from
destthe state to redirect to
Returns
void
267 {
268 for (int i = 0; i < nfa->subCount; ++i) {
269 redirect(nfa->subs[i], src, dest);
270 }
271 for (int i = 0; i < nfa->ruleCount; ++i) {
272 struct transRule* rule = nfa->rulePool[i];
273 if (rule->target == src) {
274 rule->target = dest;
275 }
276 }
277}
Here is the call graph for this function:

◆ subString()

char * subString ( const char *  str,
size_t  begin,
size_t  end 
)

utility function to create a subString

Parameters
strtarget string
beginstarting index, inclusive
endending index, inclusive
Returns
pointer to the newly created subString
177 {
178 char* res = malloc(end - begin + 2);
179 strncpy(res, str + begin, end - begin + 1);
180 res[end - begin + 1] = '\0';
181 return res;
182}
void * begin(Vector *vec)
This function returns the pointer to the begining of the Vector.
Definition vector.c:116
Here is the call graph for this function:

◆ test()

static void test ( void  )
static

Self-test implementations.

Returns
void
572 {
573 testHelper("(c|a*b)", "c", 1);
574 testHelper("(c|a*b)", "aab", 1);
575 testHelper("(c|a*b)", "ca", 0);
576 testHelper("(c|a*b)*", "caaab", 1);
577 testHelper("(c|a*b)*", "caba", 0);
578 testHelper("", "", 1);
579 testHelper("", "1", 0);
580 testHelper("(0|(1(01*(00)*0)*1)*)*","11",1);
581 testHelper("(0|(1(01*(00)*0)*1)*)*","110",1);
582 testHelper("(0|(1(01*(00)*0)*1)*)*","1100",1);
583 testHelper("(0|(1(01*(00)*0)*1)*)*","10000",0);
584 testHelper("(0|(1(01*(00)*0)*1)*)*","00000",1);
585
586 printf("All tests have successfully passed!\n");
587}
void testHelper(const char *regex, const char *string, const int expected)
Testing helper function.
Definition mcnaughton_yamada_thompson.c:540
Here is the call graph for this function:

◆ testHelper()

void testHelper ( const char *  regex,
const char *  string,
const int  expected 
)

Testing helper function.

Parameters
regexthe regular expression to be used
stringthe string to match against
expectedexpected results
Returns
void
540 {
541 char* temp = preProcessing(regex);
542 struct ASTNode* node = buildAST(temp);
543
544 struct NFA* nfa = compileFromAST(node);
545 postProcessing(nfa);
546
547 // reallocates the outermost NFA's current states pool
548 // because it will actually be used to store all the states
549 nfa->currentStates = realloc(nfa->currentStates, sizeof(struct NFAState*) * 100);
550 // Starts the NFA by adding its starting state to the pool
551 nfa->currentStates[nfa->CSCount++] = nfa->statePool[0];
552
553 // feeds empty characters into the NFA before and after
554 // every normal character
555 for (size_t i = 0; i < strlen(string); ++i) {
556 transit(nfa, '\0');
557 transit(nfa, string[i]);
558 }
559 transit(nfa, '\0');
560
561 assert(isAccepting(nfa) == expected);
562
563 destroyNFA(nfa);
565 free(temp);
566}
int isAccepting(const struct NFA *nfa)
determines whether the NFA is currently in its accepting state
Definition mcnaughton_yamada_thompson.c:522
char * preProcessing(const char *input)
performs preprocessing on a regex string, making all implicit concatenations explicit
Definition mcnaughton_yamada_thompson.c:109
void transit(struct NFA *nfa, char input)
moves a NFA forward
Definition mcnaughton_yamada_thompson.c:465
Here is the call graph for this function:

◆ transit()

void transit ( struct NFA nfa,
char  input 
)

moves a NFA forward

Parameters
nfatarget NFA
inputthe character to be fed into the NFA
Returns
void
465 {
466 struct NFAState** newStates = malloc(sizeof(struct NFAState*) * 10);
467 int NSCount = 0;
468
469 if (input == '\0') {
470 // In case of empty character input, it's possible for
471 // a state to transit to another state that's more than
472 // one rule away, we need to take that into account
473 for (int i = nfa->CSCount - 1; i > -1; --i) {
474 struct NFAState *pState = nfa->currentStates[i];
475 nfa->CSCount--;
476
477 struct NFAState** states = malloc(sizeof(struct NFAState*) * 10);
478 int sc = 0;
479 findEmpty(pState, states, &sc);
480
481 for (int j = 0; j < sc; ++j) {
482 if(!contains(newStates,NSCount, states[j])) {
483 newStates[NSCount++] = states[j];
484 }
485 }
486 free(states);
487 }
488 } else {
489 // Iterates through all current states
490 for (int i = nfa->CSCount - 1; i > -1; --i) {
491 struct NFAState *pState = nfa->currentStates[i];
492 // Gradually empties the current states pool, so
493 // it can be refilled
494 nfa->CSCount--;
495
496 // Iterates through rules of this state
497 for (int j = 0; j < pState->ruleCount; ++j) {
498 const struct transRule *pRule = pState->rules[j];
499
500 if(pRule->cond == input) {
501 if(!contains(newStates, NSCount, pRule->target)) {
502 newStates[NSCount++] = pRule->target;
503 }
504 }
505 }
506 }
507 }
508
509 nfa->CSCount = NSCount;
510 for (int i = 0; i < NSCount; ++i) {
511 nfa->currentStates[i] = newStates[i];
512 }
513 free(newStates);
514}
Here is the call graph for this function: