TC_P_程序设计_C语言状态机FSM_函数指针实现方式

TC_P_程序设计_状态机FSM_函数指针实现方式 2010年5月10日

 1相关问题:

1.1自定义函数指针变量及其使用方法:

函数指针,顾名思义,它指向一个函数的入口地址,其定义及使用如下:  ()
  定义:returntype     (*ptr)               (typename   variable,......)   
            返回类型           指针名称         指向函数的参数表。  

 

代码
typedef  void (*StateTranFun)(Fsm_Param_t * me,Signal_t sig);
//StateTranFun是一个自定义的,指向函数的指针变量,或者说,它定义了一个函数集合,定义了一组相同的函数操作,
//这个函数指针变量指向这样一类函数A: A的返回参数为void,A的函数参数为Fsm_Param_t * me,Signal_t sig
//我们可以定义有关于这类函数的具体实现:比如:
Fsm_Param_t   fsm_paramA;
Signal_t sigA;
StateTranFun  funA;
 
*funA(fsm_paramA,sigA);
 

//

 

 

1.2 C语言运算符优先级:

见表格:(C语言运算符优先级 详细列表)可见得对于指针运算来说,->运算符的优先级是低于成员选择 .[],() 高于*,&这两个的.

举1个相关的例子:

假设我们自定义一个结构体:

Fsm_Param_t:如下

代码
//如下是一些查找代码段中,注释符号/**/ ,/,*出现次数的状态机的自定义变量和参数,
//其中,State_t是关于state的变量,共有CODE(包括普通字符),SLASH(/),STAR(*) COMMENT(/*)四种状态
//其中,Signal_t是关于event信号变量,包括输入Char信号,输入star信号,输入slash信号,另外,如果考虑entry和exit,还可自定义exit和entry两个枚举类型
typedef enum
{
  CODE
=0,  
  SLASH,
  COMMENT,
  STAR
}State_t;
typedef 
enum
{
  CHAR_SIG,
  STAR_SIG,
  SLASH_SIG,
  EXIT_SIG,
  ENTRY_SIG
}Signal_t;
/*--------------------------------------------*/
//typedef struct Fsm Fsm_t;
typedef struct Fsm_Param Fsm_Param_t;
typedef  void (
*StateTranFun)(Fsm_Param_t * me,Signal_t sig);
//函数指针变量
typedef struct Fsm
{
  StateTranFun  statetranfun;
}Fsm_t;
typedef 
struct Fsm_Param
{
  Fsm_t  tranfun;          
//结构体变量Fsm_t
  State_t currentstate; //状态变量State_t
  long commentctr;      //计数参数
}Fsm_Param_t,*P_Fsm_Param_t;

 

 

代码
Fsm_Param_t * me;
((
*((me)->tranfun).statefun)((me),sig))
/*
step 1 (me)// ()意义:在宏定义中,如果输入的me是一个复合结构的话,用()保证这个复合结构完整,避免出现没有预知到的,错误,比如如果me在宏运用中,代表&test,那么没有加上(),就可能使得(me)->tranfun整个意义变了
(&test)->tranfun 和&test->tranfun是有区别的
step2 (me)->tranfun
step3 ((me)->tranfun)
step4 (((me)->tranfun).statefun)
step5 *(((me)->tranfun).statefun)
step6 (*(((me)->tranfun).statefun))
step7 (*(((me)->tranfun).statefun))((me),sig)
step8 ((*(((me)->tranfun).statefun))((me),sig))
可见,宏是一个必须非常小心的东西,稍微偏差,都可能出错的

*/
(((me)->tranfun).statetranfun=(StateTranFun)(target))
//这个=操作就是让target这个参数先强制转换为(StateTranFun)类型的变量,
再将其赋值于((me)->tranfun).statetranfun这个变量

 

代码
/*
step1  (me)
step2  (me)->tranfun
step3  ((me)->tranfun).statetranfun
step4  ((me)->tranfun).statetranfun=(StateTranFun)(target)
step5  (((me)->tranfun).statetranfun=(StateTranFun)(target))
*/

 

 

 

 1.3 关于所谓的表驱动:

表驱动有一个非常好用的地方.那就是取代一部分基于switch和if语句架构的代码段,随着switch case语句的增加,整个switch代码框架的可读性和维护性在下降

而,表驱动能够很好解决这个问题

表驱动一个简单的实例:

 

代码
static void CParser4commentOnCHAR(CParser1_t *me) 
{
   printf(
"currentstate:COMMENT\n");
   
++me->commentctr;                              /* count the comment character */
}
static void CParser4commentOnSTAR(CParser1_t *me) 
{
   printf(
"currentstate:COMMENT  ");
   TRAN(me,CParser4star);                          
/* transition to "star"        */
}
static void CParser4commentOnSLASH(CParser1_t *me) 
{
   printf(
"currentstate:COMMENT\n");
   
++me->commentctr;                              /* count the comment character */
}
void CParser4comment(CParser1_t *me,Signal_t sig)
{
       
static const void(*lookup[])(CParser1_t *)=
       {
       CParser4commentOnCHAR,
       CParser4commentOnSTAR,
       CParser4commentOnSLASH
       };
       me
->currentstate=COMMENT;
       printf(
"currentstate:COMMENT ");
       (
*lookup[sig])(me);  
}
//在函数CParser4comment中,我们在静态变量区间上,定义了一个cosnt类型的数组,一个比较特别的数组,它存储着,不是一般的普通变量,而是一群类型相同的函//数,或者说是定义了一个函数指针数组,这个数值的索引是Signal_t sig这么一个变量,在这里也要注意到枚举类型变量Signal_t的成员的先后顺序和这个数组存储的变量的前后关系
使得lookup[CHAR_SIG]对应CParser4commentOnCHAR,等等

 

 1.4关于一个小小的问题scanf函数:

char name[30];

scanf("%s",name)

scanf函数有一个特点:在输入结束,会自动补上'\0'这个东西,字符串数组结束标志

这样的结果,有利也有弊,接下来的代码,我们就会看到它的好处,同时也是它的坏处.

 源代码:  在用状态机原理进行软件设计.pdf  如下代码有待修改整理,可能存在错误:

h文件:

 

代码
#ifndef _STATE_MECHINE_H_
#define _STATE_MECHINE_H_
typedef 
enum
{
  CODE
=0,
  SLASH,
  COMMENT,
  STAR
}State_t;

typedef 
enum
{
  CHAR_SIG,
  STAR_SIG,
  SLASH_SIG,
  EXIT_SIG,
  ENTRY_SIG
}Signal_t;
typedef 
struct CParser1 CParser1_t;
typedef 
struct Fsm Fsm_t;
#if 0
typedef 
void (*StateTranFun)(void * me,Signal_t sig);
#endif

#if 1
typedef 
void (*StateTranFun)(CParser1_t * me,Signal_t sig);//记住,StateTranFun是一个函数指针变量,
#endif

struct Fsm
{
   StateTranFun statetranfun;
};
typedef 
struct CParser1
{
  Fsm_t tranfun;
  State_t currentstate;
  
long commentctr;
}CParser1_t;
#define FsmDispatch(me,sig)  (*((me)->tranfun).statetranfun)((me),sig)
#define FsmInit(me)          (*((me)->tranfun).statetranfun)((me),0) 
#define TRAN(me,target)      (((me)->tranfun).statetranfun=(StateTranFun)(target)        
#define TRAN_EE(target) do{\
    
*((Fsm_t *)me)->state)(me,EXIT_SIG);   \
    ((Fsm_t 
*)me)->state=(State_t)(target);\
    
*((Fsm_t *)me)->state)(me,ENTRY_SIG);  \
}
while(0)
extern void CParser4code (CParser1_t *me,Signal_t sig);
extern void CParser4slash(CParser1_t *me,Signal_t sig);
extern void CParser4comment(CParser1_t *me,Signal_t sig);
extern void CParser4star (CParser1_t *me,Signal_t sig);
extern CParser1_t *CParser4Ctor(CParser1_t *me);
extern   Fsm_t * FsmCtor(Fsm_t *me,StateTranFun initial);
#endif

 

 

 c 文件:

 

 

代码
#include"state_mechine.h"
#include
"stdio.h"
void CParser4code (CParser1_t *me,Signal_t sig);
void CParser4slash(CParser1_t *me,Signal_t sig);
void CParser4comment(CParser1_t *me,Signal_t sig);
void CParser4star (CParser1_t *me,Signal_t sig);
/*------------------------------------------------*/
static void CParser4commentOnCHAR(CParser1_t *me) 
{
   printf(
"currentstate:COMMENT\n");
   
++me->commentctr;                              /* count the comment character */
}
static void CParser4commentOnSTAR(CParser1_t *me) 
{
   printf(
"currentstate:COMMENT  ");
   TRAN(me,CParser4star);                          
/* transition to "star"        */
}
static void CParser4commentOnSLASH(CParser1_t *me) 
{
   printf(
"currentstate:COMMENT\n");
   
++me->commentctr;                              /* count the comment character */
}

void CParser4Initial(CParser1_t *me,Signal_t sig)
{
  me
->commentctr=0;
  me
->currentstate=CODE;
  TRAN(me,CParser4code);
}
Fsm_t 
* FsmCtor(Fsm_t *me,StateTranFun initial)
{
  me
->statetranfun=initial;
  
return me;
}
CParser1_t 
*CParser4Ctor(CParser1_t *me)
{
   FsmCtor(
&(me->tranfun),((StateTranFun)CParser4Initial));
   
return me;
}
/*------------------------------------------------*/
void CParser4code (CParser1_t *me,Signal_t sig)
{
    me
->currentstate=CODE;
    printf(
"currentstate:CODE ");    
    
switch(sig)
    {
        
case SLASH_SIG:
             printf(
"nextstate:SlASH");
             TRAN(me,CParser4slash);
        
break;
        
    }
    printf(
"\n");
}
void CParser4slash(CParser1_t *me,Signal_t sig)
{
    me
->currentstate=SLASH;
    printf(
"currentstate:SLASH ");        
    
switch(sig)
    {
       
case STAR_SIG:
            me
->commentctr+=2;
            printf(
"nextstate:COMMENTn");
            TRAN(me,CParser4comment);
       
break;
       
case CHAR_SIG:
            printf(
"nextstate:CODE");
            TRAN(me,CParser4code);
       
break;

    }
    printf(
"\n");
}
void CParser4comment(CParser1_t *me,Signal_t sig)
{
    
static const void(*lookup[])(CParser1_t *)={
       CParser4commentOnCHAR,
       CParser4commentOnSTAR,
       CParser4commentOnSLASH
    };
    me
->currentstate=COMMENT;
    printf(
"currentstate:COMMENT ");
    (
*lookup[sig])(me);  
}
void CParser4star (CParser1_t *me,Signal_t sig)
{
    me
->currentstate=STAR;
    printf(
"currentstate:STAR ");
    
switch(sig)
    {
       
case STAR_SIG:
           
++me->commentctr; 
           
break;
       
case CHAR_SIG:
           me
->commentctr+=2;
           TRAN(me,CParser4comment);
            printf(
"nextstate:COMMENT");
           
break;
       
case SLASH_SIG:
           me
->commentctr+=2;
           TRAN(me,CParser4code);
            printf(
"nextstate:CODE");
           
break;
    }
    printf(
"\n");
}
/*------------------------------------------------*/

 

main文件:

 

代码
#include <stdlib.h>
#include 
<stdio.h>
#include
"state_mechine.h"
static CParser1_t cparser;
void main(void)
{
  
char name[60];
  
char *p;
  p
=name;
  scanf(
"%s",name);
  CParser4Ctor(
&cparser);           
  FsmInit(
&cparser); 
  
while (*p!='\0')
  {
     
int sig;
     
switch (*p) 
     {
       
case '/': sig = SLASH_SIG; break;
       
case '*': sig = STAR_SIG;  break;
       
default:  sig = CHAR_SIG;  break;
     }
     FsmDispatch(
&cparser,sig);           
     
++p; 
  }
}

 

附:UML图原理:

附:运行效果图

 

 

 

 

posted @ 2010-05-10 16:42  fleetwgx  阅读(1314)  评论(2编辑  收藏  举报