nunnifsmgen-有限状态机程序代码自动生成器
这个是从同事那边知道的好东西, Nunni FSM Generator,它能自动根据你输入的配置文件产生状态机的程序代码,详细的数据请查阅软件的使用说明,但我要讲的重点在于它"自动产生的程序代码部份",因为自动产生的code封装得十分漂亮,所以我想对code做点介绍
以前写状态机的东西,不脱离if,else,case,switch…等这几种语法搭配,可是写出来的code"不 大容易读懂",比如说我今天有个状态机如下图,假设有一张桌子,上面只能摆一个瓶子,我如果拿走了这个瓶子,那我就不能从桌子上再拿走瓶子了,如果桌子上 已经摆了一个瓶子,那桌子上就再也不能多加瓶子上去
如果用if-else语法写写看,可能会像下面这样
-
#include
-
int bottles=1;
-
void GetBottleAPI()
-
{
-
if (bottles==1)
-
{
-
printf("You got bottle/n");
-
bottles--;
-
}
-
else printf("No bootle to get/n");
-
}
-
void PutBottleAPI()
-
{
-
if (bottles==0)
-
{
-
printf("You put a bottle/n");
-
bottles++;
-
}
-
else printf("Too much bootles/n");
-
}
-
int main()
-
{
-
GetBottleAPI();
-
GetBottleAPI();
-
PutBottleAPI();
-
PutBottleAPI();
-
GetBottleAPI();
-
}
用int bottles当global变量判断get or put的动作是否合法,这种写法如果用在小型的状态机还OK,如果状态机又多又大又复杂,可以想见程序代码会为这些状态多写好几个判断变量
试试看下面的程序代码,我只要定义好每个状态与外来动作的触发机制,就可以写出蛮漂亮的code
- #include
- struct TableState ;
- struct TableFSM
- {
- int (*GetBottleStatus)( struct TableFSM *fsm, void * o );
- int (*PutBottleStatus)( struct TableFSM *fsm, void * o );
- void (*changeState)( struct TableFSM *fsm, struct TableState *nextState );
- struct TableState *m_state;
- };
- struct TableState
- {
- int (*GetBottleStatus)( struct TableFSM *fsm, void * o );
- int (*PutBottleStatus)( struct TableFSM *fsm, void * o );
- };
- static struct TableState TableFull;
- static struct TableState TableEmpty;
- void GetBottle()
- {
- printf("You get a bottle/n");
- }
- void GiveBottle()
- {
- printf("You put bottle on the table/n");
- }
- void NoBottle()
- {
- printf("There is no bottle on the table/n");
- }
- void BottleFull()
- {
- printf("There is too much bottle on the table/n");
- }
- int FSMGetBottleStat( struct TableFSM *fsm, void * o )
- {
- return fsm->m_state->GetBottleStatus( fsm, o );
- }
- int FSMPutBottleStat( struct TableFSM *fsm, void * o )
- {
- return fsm->m_state->PutBottleStatus( fsm, o );
- }
- void FSMChangeState( struct TableFSM *fsm, struct BottleState *newState )
- {
- fsm->m_state = newState;
- }
- int GetBottleAPI( struct TableFSM *fsm, void * o )
- {
- GetBottle();
- fsm->changeState( fsm, &TableEmpty);
- }
- int GiveBottleAPI(struct TableFSM *fsm, void * o )
- {
- GiveBottle();
- fsm->changeState( fsm, &TableFull );
- }
- int TooFewBottleAPI(struct TableFSM *fsm, void * o )
- {
- NoBottle();
- fsm->changeState( fsm, &TableEmpty );
- }
- int TooMuchBottleAPI(struct TableFSM *fsm, void * o )
- {
- BottleFull();
- fsm->changeState( fsm, &TableFull );
- }
- int main()
- {
- static struct TableFSM bf;
- TableFull.GetBottleStatus = GetBottleAPI;
- TableFull.PutBottleStatus = TooMuchBottleAPI;
- TableEmpty.GetBottleStatus = TooFewBottleAPI;
- TableEmpty.PutBottleStatus = GiveBottleAPI;
- bf.GetBottleStatus=FSMGetBottleStat;
- bf.PutBottleStatus=FSMPutBottleStat;
- bf.changeState=FSMChangeState;
- bf.m_state=&TableFull;
- FSMGetBottleStat(&bf,0);
- FSMGetBottleStat(&bf,0);
- FSMPutBottleStat(&bf,0);
- FSMPutBottleStat(&bf,0);
- }
上面的程序代码相当简洁,当外部动作触发内部状态改变,会把FSM指定的函式指定到转入后的state callback,所以programmer可以完全专注在GetBottleAPI之类的函式实作,而不用考虑state转换的程序复杂度