init(); // a top level initial transition dispatch(); // dispatch an event to the state machine tran(); // make a state change
CParser FSM (undocked)
enum Signal // enumeration for CParser signals
{
CHAR_SIG, STAR_SIG, SLASH_SIG
};
enum State // enumeration for CParser states
{
CODE, SLASH, COMMENT, STAR
};
class CParser1
{
private:
State myState; // the scalar state-variable
long myCommentCtr; // comment character counter
/* ... */ // other CParser1 attributes
public:
void init()
{
myCommentCtr = 0; tran(CODE); // default transiton
}
void dispatch(Signal sig);
void tran(State target)
{
myState = target;
}
long getCommentCtr() const
{
return myCommentCtr;
}
};
void CParser1::dispatch(Signal sig)
{
switch (myState)
{
case CODE:
switch (sig)
{
case SLASH_SIG:
tran(SLASH); // transition to SLASH
break;
}
break;
case SLASH:
switch (sig)
{
case STAR_SIG:
myCommentCtr += 2; // SLASH-STAR count as comment
tran(COMMENT); // transition to COMMENT
break;
case CHAR_SIG:
case SLASH_SIG:
tran(CODE); // go back to CODE
break;
}
break;
case COMMENT:
switch (sig)
{
case STAR_SIG:
tran(STAR); // transition to STAR
break;
case CHAR_SIG:
case SLASH_SIG:
++myCommentCtr; // count the comment char
break;
}
break;
case STAR:
switch (sig)
{
case STAR_SIG:
++myCommentCtr; // count STAR as comment
break;
case SLASH_SIG:
myCommentCtr += 2; // count STAR-SLASH as comment
tran(CODE); // transition to CODE
break;
case CHAR_SIG:
myCommentCtr += 2; // count STAR-? as comment
tran(COMMENT); // go back to COMMENT
break;
}
break;
}
}
| C Comment Parser State Transition Table (FSM Model) | |||
| Events | |||
| States | CHAR_SIG | STAR_SIG | SLASH_SIG |
| CODE | doNothing(); tran(SLASH); |
||
| SLASH | doNothing(); tran(CODE); |
a2(); tran(COMMENT); |
doNothing(); tran(CODE); |
| COMMENT | a1(); tran(COMMENT)); |
doNothing(); tran(STAR); |
a1(); tran(COMMENT); |
| STAR | a2(); tran(COMMENT); |
a1(); tran(STAR); |
a2(); tran(CODE); |
// generic "event processor" ...
class StateTable
{
public:
typedef void (StateTable::*Action)();
// defines type Action as pointer-to-method in StateTable
struct Tran // defines table element as pair<pointer-to-member, unsigned>
{
Action action;
unsigned nextState;
};
StateTable(Tran const *table, unsigned nStates, unsigned nSignals)
: myTable(table), myNsignals(nSignals), myNstates(nStates)
myTable contains address of 2-d table of Tran supplied by client
{}
virtual ~StateTable() // virtual xctor
{}
void dispatch(unsigned sig)
{
register Tran const * t = myTable + myState*myNsignals + sig;
// table lookup: Tran * t = myTable[myState,sig];
(this->*(t->action))(); // call action sequence
myState = t->nextState; // "tran()"
}
void doNothing()
{}
protected:
unsigned myState;
private:
Tran const *myTable;
unsigned myNsignals;
unsigned myNstates;
};
// specific Comment Parser state machine ...
enum Event // enumeration for CParser events
{
CHAR_SIG, STAR_SIG, SLASH_SIG, MAX_SIG
};
enum State // enumeration for CParser states
{
CODE, SLASH, COMMENT, STAR, MAX_STATE
};
class CParser2 : public StateTable // CParser2 state machine
{
public:
CParser2() : StateTable(&myTable[0][0], MAX_STATE, MAX_SIG)
{}
void init() // initial transition
{
myCommentCtr = 0; myState = CODE;
}
long getCommentCtr() const
{
return myCommentCtr;
}
private:
void a1() // action method
{
myCommentCtr += 1;
}
void a2() // action method
{
myCommentCtr += 2;
}
static StateTable::Tran const myTable[MAX_STATE][MAX_SIG];
long myCommentCtr; // comment character counter
};
// initialize the "table", a 2-D array of unsigned int ("romable")
StateTable::Tran const CParser2::myTable[MAX_STATE][MAX_SIG] =
{
{
{&StateTable::doNothing, CODE },
{&StateTable::doNothing, CODE },
{&StateTable::doNothing, SLASH}
},
{
{&StateTable::doNothing, CODE },
{static_cast<StateTable::Action>(&CParser2::a2), COMMENT },
{&StateTable::doNothing, CODE }
},
{
{static_cast<StateTable::Action>(&CParser2::a1), COMMENT },
{&StateTable::doNothing,STAR },
{static_cast<StateTable::Action>(&CParser2::a1), COMMENT }
},
{
{static_cast<StateTable::Action>(&CParser2::a2), COMMENT },
{static_cast<StateTable::Action>(&CParser2::a1), STAR },
{static_cast<StateTable::Action>(&CParser2::a2), CODE }
}
};


class CParser3; // Context class
class CParserState // abstract State
// not abstract class: defines inheritable "doNothing" actions
{
public:
virtual void onCHAR(CParser3 *context, char ch)
{}
virtual void onSTAR(CParser3 *context)
{}
virtual void onSLASH(CParser3 *context)
{}
};
class CodeState : public CParserState // concrete State "Code"
{
public:
virtual void onSLASH(CParser3 *context);
};
class SlashState : public CParserState // concrete State "Slash"
{
public:
virtual void onCHAR(CParser3 *context, char ch);
virtual void onSTAR(CParser3 *context);
};
class CommentState : public CParserState //concrete State "Comment"
{
public:
virtual void onCHAR(CParser3 *context, char ch);
virtual void onSTAR(CParser3 *context);
virtual void onSLASH(CParser3 *context);
};
class StarState : public CParserState // concrete State "Star"
{
public:
virtual void onCHAR(CParser3 *context, char ch);
virtual void onSTAR(CParser3 *context);
virtual void onSLASH(CParser3 *context);
};
class CParser3 // Context class
{
friend class CodeState;
friend class SlashState;
friend class CommentState;
friend class StarState;
private:
static CodeState myCodeState;
static SlashState mySlashState;
static CommentState myCommentState;
static StarState myStarState;
CParserState *myState;
long myCommentCtr;
public:
void init()
{
myCommentCtr = 0; tran(&myCodeState);
}
void tran(CParserState *target)
{
myState = target;
}
long getCommentCtr() const
{
return myCommentCtr;
}
void onCHAR(char ch)
{
myState->onCHAR(this, ch);
}
void onSTAR()
{
myState->onSTAR(this);
}
void onSLASH()
{
myState->onSLASH(this);
}
};
CodeState CParser3::myCodeState;
SlashState CParser3::mySlashState;
CommentState CParser3::myCommentState;
StarState CParser3::myStarState;
void CodeState::onSLASH(CParser3 *context)
{
context->tran(&CParser3::mySlashState);
}
void SlashState::onCHAR(CParser3 *context, char ch)
{
context->tran(&CParser3::myCodeState);
}
void SlashState::onSTAR(CParser3 *context)
{
context->myCommentCtr += 2;
context->tran(&CParser3::myCommentState);
}
void CommentState::onCHAR(CParser3 *context, char c)
{
context->myCommentCtr++;
}
void CommentState::onSTAR(CParser3 *context)
{
context->tran(&CParser3::myStarState);
}
void CommentState::onSLASH(CParser3 *context)
{
context->myCommentCtr++;
}
void StarState::onCHAR(CParser3 *context, char ch)
{
context->myCommentCtr += 2;
context->tran(&CParser3::myCommentState);
}
void StarState::onSTAR(CParser3 *context)
{
context->myCommentCtr++;
}
void StarState::onSLASH(CParser3 *context)
{
context->myCommentCtr += 2;
context->tran(&CParser3::myCodeState);
}
Design Pattern
|
![]() |
Simplified Design Pattern
|
![]() |
|
![]() |
class Fsm
{
public:
typedef void // return value
(Fsm::* // class the function pointer is a member of
State) // pointer-to-member name
(unsigned sig); // argument list
Fsm(State initial) : myState(initial) // ctor
{}
virtual ~Fsm() // virtual xtor
{}
void init() // initial transition
{
(this->*myState)(0);
}
void dispatch(unsigned sig)
{
(this->*myState)(sig);
}
protected:
void tran(State target)
{
myState = target;
}
#define TRAN(target_) tran(static_cast<State>(target_))
State myState;
};
enum Event // enumeration for CParser events
{
CHAR_SIG, STAR_SIG, SLASH_SIG
};
class CParser4 : public Fsm
{
public:
CParser4() : Fsm((State)initial) {} // ctor
long getCommentCtr() const { return myCommentCtr; }
private:
long myCommentCtr; // comment character counter
void initial(unsigned); // state-handler
void code(unsigned sig); // state-handler
void slash(unsigned sig); // state-handler
void comment(unsigned sig); // state-handler
void star(unsigned sig); // state-handler
};
void CParser4::initial(unsigned) // initial pseudostate
{
myCommentCtr = 0;
TRAN(&CParser4::code); // take the default transition
}
void CParser4::code(unsigned sig)
{
switch (sig)
{
case SLASH_SIG:
TRAN(&CParser4::slash); // transition to "slash"
break;
}
}
void CParser4::slash(unsigned sig)
{
switch (sig)
{
case STAR_SIG:
myCommentCtr += 2; // SLASH-STAR characters count as comment
TRAN(&CParser4::comment); // transition to "comment"
break;
case CHAR_SIG:
TRAN(&CParser4::code); // go back to "code"
break;
}
}
void CParser4::comment(unsigned sig)
{
switch (sig)
{
case STAR_SIG:
TRAN(&CParser4::star); // transition to "star"
break;
case CHAR_SIG:
case SLASH_SIG:
++myCommentCtr; // count the comment character
break;
}
}
void CParser4::star(unsigned sig)
{
switch (sig)
{
case STAR_SIG:
++myCommentCtr; // count '*' as comment character
break;
case CHAR_SIG:
myCommentCtr += 2; // count STAR-? as comment
TRAN(&CParser4::comment); // go back to "comment"
break;
case SLASH_SIG:
myCommentCtr += 2; // count STAR-SLASH as comment
TRAN(&CParser4::code); // transition to "code"
break;
}
}
|
![]() |
|
|
if (guard())
{
action();
}
if (guard1())
{
action1();
}
else if (guard2())
{
action2();
}
// optional default case:
else
{
actionN();
}
Note the control over action order when guards are not mutually exclusive.if (dynamic_condition())
{
if (guard1())
{
action1();
}
else if (guard2())
{
action2();
}
// optional default case:
else
{
actionN();
}
}
enum
{
INIT_SIG = 1, EXIT_SIG, ENTRY_SIG, USER_SIG
}
enum mySignals
{
SIG1 = USER_SIG, SIG2, SIG3, ...
}
// old
void tran(State target)
{
myState = target;
}
// new
void tran(State target)
{
(this -> *myState)(EXIT_SIG);
myState = target;
(this -> *myState)(ENTRY_SIG);
}
void CParser4a::slash(unsigned sig)
{
switch (sig)
{
case ENTRY_SIG:
// entry_action
break;
case EXIT_SIG:
// exit_action
break;
case STAR_SIG:
myCommentCtr += 2; // SLASH-STAR characters count as comment
TRAN(&CParser4::comment); // transition to "comment"
break;
case CHAR_SIG:
TRAN(&CParser4::code); // go back to "code"
break;
}
}