HiveBrain v1.2.0
Get Started
← Back to all entries
patterncMinor

Efficient data-driven finite state machine

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
finiteefficientstatemachinedatadriven

Problem

In creating this answer to a recent question, I thought I might write a fully worked example that implements a finite state machine in C.

The purpose is to implement the following function:


Given a const char *, search for a string conforming to the pattern WWWDD where WWW is one of { "Mon", "Tue", "Wed, "Thu", "Fri", "Sat", "Sun" } and DD is an integer in the range \$[1, 31]\$ (inclusive). If the pattern exists within the string, return the offset; otherwise return -1.

I implemented this state machine: using simple table structure. This is the code, which includes a simple driver with test vectors.

```
#include
#include
#include

static const struct fsmNode {
const char target;
const struct fsmNode *next;
} fsm[] = {
{ 'T' , &fsm[6] }, // 0
{ 'M' , &fsm[9] }, // 1
{ 'S' , &fsm[11] }, // 2
{ 'W' , &fsm[12] }, // 3
{ 'F' , &fsm[14] }, // 4
{ '\0' , NULL }, // 5
// second letter
{ 'h' , &fsm[18] }, // 6
{ 'u' , &fsm[20] }, // 7
{ '\0' , NULL }, // 8
{ 'o' , &fsm[22] }, // 9
{ '\0' , NULL }, // 10
{ 'a' , &fsm[24] }, // 11
{ 'u' , &fsm[22] }, // 12
{ '\0' , NULL }, // 13
{ 'e' , &fsm[26] }, // 14
{ '\0' , NULL }, // 15
{ 'r' , &fsm[27] }, // 16
{ '\0' , NULL }, // 17
// third letter
{ 'u' , &fsm[30] }, // 18
{ '\0' , NULL }, // 19
{ 'e' , &fsm[30] }, // 20
{ '\0' , NULL }, // 21
{ 'n' , &fsm[30] }, // 22
{ '\0' , NULL }, // 23
{ 't' , &fsm[30] }, // 24
{ '\0' , NULL }, // 25
{ 'd' , &fsm[30] }, // 26
{ '\0' , NULL }, // 27
{ 'i' , &fsm[30] }, // 28
{ '\0' , NULL }, // 29
// first digit
{ '0' , &fsm[36] }, // 30
{ '1' , &fsm[35] }, // 31
{ '2' , &fsm[35] }, // 32
{ '3' , &fsm[46] }, // 33
{ '\0' , NULL }, // 34
// second digit
{ '0' , NULL }, // 35
{ '1' , NULL },

Solution

Nice work.

-
On findWeekdayDate() return, I'd expect a value that is enumerated like fWD_SUCCESS, fWD_FAIL, fWD_SUCCESS_for_foo_reason, fWD_FAIL_for_bar_reason, etc. Rather than magic numbers -1,0,3,.... It could end up being a simple bool.

-
As fsm[] is const struct fsmNode, I see no value in making a field const like const char target. char target is simpler and sufficient. OTOH, if there is some value, then next should also be const as in const struct fsmNode * const next.

-
Delay/remove #includes.

#include   // Needed?
#include   // OK, for NULL
#include    // Needed?


-
Style inconsistency. Recommend empty for body to match other indentations.

// for ( ; state->target && *curr != state->target; ++state) 
//{ /* do nothing */ }
for ( ; state->target && *curr != state->target; ++state) {
  /* do nothing */
}


-
Use an auto formatter. The extra space betrays manual formatting as it is inconsistent with the rest of code. Life is too short for manual formatting.

//             v
for (curr = str ; *curr; ++curr) {


Suggest adding link to software used to create FSM.

Code Snippets

#include <string.h>  // Needed?
#include <stdlib.h>  // OK, for NULL
#include <ctype.h>   // Needed?
// for ( ; state->target && *curr != state->target; ++state) 
//{ /* do nothing */ }
for ( ; state->target && *curr != state->target; ++state) {
  /* do nothing */
}
//             v
for (curr = str ; *curr; ++curr) {

Context

StackExchange Code Review Q#150637, answer score: 4

Revisions (0)

No revisions yet.