有限状态机FSM详解及其实现

FSM的实现

• 使用状态转换图描述FSM
• 状态转换图中的结点对应不同的状态对象
• 每个状态对象通过一个输入字符转换到另一个状态上，或者保持原状态不变。

• 通过算法表示，即“可执行代码（Executable Code）”方式
• 通过一张映射表，即“被动数据（Passive Data）”方式

如下详细介绍这两种实现方式：

• 通过Executable Code 实现映射的FSM ：

State* State1::Transition(char c)
{
switch(c)
{
case 'A':
return &s2;
case 'B':
return &s3;
case 'C':
return &s4;
case 'D':
return &s5;
case '\0':
return NULL;
default:
return NULL;
}
}

// fsm_with_executable_code.h
#ifndef FSM_WITH_EXECUTABLE_CODE_H
#define FSM_WITH_EXECUTABLE_CODE_H

#include <string.h>

class State
{
public:
virtual State* Transition(char c) = 0;
};

class Fsm
{
public:
Fsm();
void Reset();            // move to start state
int EndState();
int DoomState();

private:
State* p_current;   // &s1, &s2, ..., &s6; NULL ==> doom
};

class State1 : public State
{
public:
State* Transition(char c);
};

class State2 : public State
{
public:
State* Transition(char c);
};

class State3 : public State
{
public:
State* Transition(char c);
};

class State4 : public State
{
public:
State* Transition(char c);
};

class State5 : public State
{
public:
State* Transition(char c);
};

class State6 : public State
{
public:
State* Transition(char c);
};

#endif // FSM_WITH_EXECUTABLE_CODE_H

// fsm_with_executable_code.cc
#include "fsm_with_executable_code.h"

State1 s1;
State2 s2;
State3 s3;
State4 s4;
State5 s5;
State6 s6;

Fsm::Fsm()
{
p_current = NULL;
}

void Fsm::Reset()
{
p_current = &s1;
}

{
if (p_current != NULL)
p_current = p_current->Transition(c);
}

int Fsm::EndState()
{
return p_current == &s6;
}

int Fsm::DoomState()
{
return p_current == NULL;
}
State* State1::Transition(char c)
{
switch(c)
{
case 'A':
return &s2;
case 'B':
return &s3;
case 'C':
return &s4;
case 'D':
return &s5;
case '\0':
return NULL;
default:
return NULL;
}
}

State* State2::Transition(char c)
{
switch(c)
{
case 'E':
return &s2;
case 'I':
return &s6;
case '\0':
return NULL;
default:
return NULL;
}
}

State* State3::Transition(char c)
{
switch(c)
{
case 'F':
return &s3;
case 'M':
return &s4;
case 'J':
return &s6;
case '\0':
return NULL;
default:
return NULL;
}
}

State* State4::Transition(char c)
{
switch(c)
{
case 'G':
return &s4;
case 'K':
return &s6;
case '\0':
return NULL;
default:
return NULL;
}
}

State* State5::Transition(char c)
{
switch(c)
{
case 'O':
return &s2;
case 'H':
return &s5;
case 'L':
return &s6;
case 'N':
return &s4;
case '\0':
return NULL;
default:
return NULL;
}
}

State* State6::Transition(char c)
{
return NULL;
}

// test_with_executable_code.cc
#include "fsm_with_executable_code.h"

#include "stdio.h"  // printf, scanf
#include "stdlib.h" // system

void test_fsm()
{
char input_string[80];
printf("Enter input expression: ");
scanf("%s", input_string);

Fsm fsm;
fsm.Reset();
int index = 0;

while (!fsm.EndState() && !fsm.DoomState())

if (fsm.EndState())
printf("\nValid input expression");
else
printf("\nInvalid input expression");
}

int main()
{
test_fsm();

system("pause");
}

•   通过Passive Data 实现映射的FSM ：

#include <limits.h>

class State
{
public:
State();
State* transition[range];
};

struct TransGraph   // use triple to describe map
{
int current_state;
char input_char;
int next_state;
};

// fsm_with_passive_data.h
#ifndef FSM_WITH_PASSIVE_DATA_H
#define FSM_WITH_PASSIVE_DATA_H

#include <string.h>
#include <limits.h>     // CHAR_MAX

const int range = CHAR_MAX + 1;

class State
{
public:
State();
State* transition[range];
};

struct TransGraph   // use triple to describe map
{
int current_state;
char input_char;
int next_state;
};

class Fsm
{
public:
Fsm();
void Reset();            // move to start state
int EndState();
int DoomState();

private:
State* p_current;   // &s1, &s2, ..., &s6; NULL ==> doom
State state[6];     // 6 states, state[0] is end state
};

#endif // FSM_WITH_PASSIVE_DATA_H

// fsm_with_passive_data.cc
#include "fsm_with_passive_data.h"

State::State()
{
for (int i = 0; i < range; ++i)
transition[i] = NULL;
}

Fsm::Fsm()
{
static TransGraph graph[] =
{
{1, 'A', 2}, {1, 'B', 3}, {1, 'C', 4}, {1, 'D', 5},
{2, 'E', 2}, {2, 'I', 0},
{3, 'F', 3}, {3, 'J', 0}, {3, 'M', 4},
{4, 'G', 4}, {4, 'K', 0},
{5, 'H', 5}, {5, 'L', 0}, {5, 'O', 2}, {5, 'N', 4},
{0, 0, 0}
};

for (TransGraph* p_tg = graph; p_tg->current_state != 0; ++p_tg)
state[p_tg->current_state].transition[p_tg->input_char] = &state[p_tg->next_state];

p_current = NULL;
}

void Fsm::Reset()
{
p_current = &state[1];
}

{
if (p_current != NULL)
p_current = p_current->transition[c];
}

int Fsm::EndState()
{
return p_current == &state[0];
}

int Fsm::DoomState()
{
return p_current == NULL;
}

// test_with_passive_data.cc
#include "fsm_with_passive_data.h"

#include "stdio.h"  // printf, scanf
#include "stdlib.h" // system

void test_fsm()
{
char input_string[80];
printf("Enter input expression: ");
scanf("%s", input_string);

Fsm fsm;
fsm.Reset();
int index = 0;

while (!fsm.EndState() && !fsm.DoomState())

if (fsm.EndState())
printf("\nValid input expression");
else
printf("\nInvalid input expression");
}

int main()
{
test_fsm();

system("pause");
}

通用FSM的设计

class Fsm
{
public:
Fsm(TransGraph* p_tg);
virtual ~Fsm();
void Reset();
int EndState();
int DoomState();

private:
State* p_current;
State* p_state;
};

Fsm::Fsm(TransGraph* p_tg)
{
int max_state = 0;  // size for dynamically allocated graph
for (TransGraph* p_temp = p_tg; p_temp->current_state != 0; ++p_temp)
{
if (p_temp->current_state > max_state)
max_state = p_temp->current_state;
if (p_temp->next_state > max_state)
max_state = p_temp->next_state;
}

p_state = new State[max_state + 1];
for (TransGraph* p_temp = p_tg; p_temp->current_state != 0; ++p_temp)
p_state[p_temp->current_state].transition[p_temp->input_char] = &p_state[p_temp->next_state];

p_current = NULL;
}

Fsm::~Fsm()
{
delete []p_state;
}

// fsm_with_generalization.h
#ifndef FSM_WITH_GENERALIZATION_H
#define FSM_WITH_GENERALIZATION_H

#include <string.h>
#include <limits.h>     // CHAR_MAX

const int range = CHAR_MAX + 1;

class State
{
public:
State();
State* transition[range];
};

struct TransGraph
{
int current_state;
char input_char;
int next_state;
};

class Fsm
{
public:
Fsm(TransGraph* p_tg);
virtual ~Fsm();
void Reset();
int EndState();
int DoomState();

private:
State* p_current;
State* p_state;
};

#endif // FSM_WITH_GENERALIZATION_H

// fsm_with_generalization.cc
#include "fsm_with_generalization.h"

State::State()
{
for (int i = 0; i < range; ++i)
transition[i] = NULL;
}

Fsm::Fsm(TransGraph* p_tg)
{
int max_state = 0;  // size for dynamically allocated graph
for (TransGraph* p_temp = p_tg; p_temp->current_state != 0; ++p_temp)
{
if (p_temp->current_state > max_state)
max_state = p_temp->current_state;
if (p_temp->next_state > max_state)
max_state = p_temp->next_state;
}

p_state = new State[max_state + 1];
for (TransGraph* p_temp = p_tg; p_temp->current_state != 0; ++p_temp)
p_state[p_temp->current_state].transition[p_temp->input_char] = &p_state[p_temp->next_state];

p_current = NULL;
}

Fsm::~Fsm()
{
delete []p_state;
}

void Fsm::Reset()
{
p_current = &p_state[1];
}

{
if (p_current != NULL)
p_current = p_current->transition[c];
}

int Fsm::EndState()
{
return p_current == &p_state[0];
}

int Fsm::DoomState()
{
return p_current == NULL;
}

// test_with_generalization.cc
#include "fsm_with_generalization.h"

#include "stdio.h"  // printf, scanf
#include "stdlib.h" // system

void test_fsm()
{
char input_string[80];
printf("Enter input expression: ");
scanf("%s", input_string);

TransGraph graph[] =
{
{1, 'A', 2}, {1, 'B', 3}, {1, 'C', 4}, {1, 'D', 5},
{2, 'E', 2}, {2, 'I', 0},
{3, 'F', 3}, {3, 'J', 0}, {3, 'M', 4},
{4, 'G', 4}, {4, 'K', 0},
{5, 'H', 5}, {5, 'L', 0}, {5, 'O', 2}, {5, 'N', 4},
{0, 0, 0}
};

Fsm fsm(graph);
fsm.Reset();
int index = 0;

while (!fsm.EndState() && !fsm.DoomState())

if (fsm.EndState())
printf("\nValid input expression");
else
printf("\nInvalid input expression");
}

int main()
{
test_fsm();

system("pause");
}