如果你是一个程序员,对状态机应该有一定的了解,甚至会经常使用。

使用状态机的时候,一般都是自己设计程序去实现状态机,但,当要维护代码时,就会显得不方便,特别是比较复杂的时候。

我幻想着有一个软件,能在图形界面上设计状态图,然后自动生成C\C++代码。生成的代码实现了状态机本身,和状态转换的逻辑关系,程序员与生成的代码之间的接口就是:定义动作、向状态机提交事件。很简单。没错,低耦合高内聚就是代码努力的方向。我们都不想全局变量满天飞。。。

经过我一段时间的努力,终于把这个软件做出来了,取名为“HEART-BLUE”。以下就是界面:

这是一个很简单的三个状态之间的转换。输入事件evGo,驱动状态机发生跳转,于是会执行相应的动作AcEntryA,AcEntryB,AcEntryC。程序输出:

还有复杂一点的状态机。一个电子小时钟,用2个按键,实现调节日期,时间和计时的功能。

用VC2005实现:

时钟VC2005工程资源地址:

http://download.csdn.net/detail/my_jeff/6412633

HEART-BLUE资源地址:

http://download.csdn.net/detail/my_jeff/6408985 ……

状态机生成的3个C++代码文件(simpleABC):

/
//VERSION: 1.0.0.1
//AUTHOR:  JEFF
//TIME:    2013-10-15 22:12:57
//DESCRIPTION: Generate if not exist.
/
#ifndef _SIMPLEABC_C_DEF_H_
#define _SIMPLEABC_C_DEF_H_
//DEFINITION
#define SS_VOID        void
#define SS_BOOL        unsigned char
#define SS_TRUE        1
#define SS_FALSE       0
#define SS_BYTE        unsigned char
#define SS_WORD        unsigned short
#define SS_LONG        unsigned long
//
//User
#define SS_ARR_EVENT_INNER_AUTO                //
#define SS_STATE_CLASS                       CMyState
#ifdef SS_ARR_EVENT_INNER_AUTO //Inner queue size ...
#else
#define SS_ARR_EVENT_INNER_SIZE        20
#endif
#define DO_SOMETHING_WHEN_INNER_QUEUE_OVER_FLOW \
ss_var_01 = ss_var_02;  //Make queue empty.
/
#endif  //#ifndef _SIMPLEABC_C_DEF_H_
/
//VERSION: 1.0.0.1
//AUTHOR:  JEFF
//TIME:    2013-10-15 22:12:57
//DESCRIPTION: Edited by HEART-BLUE. Don't modify it.
/
#ifndef _SIMPLEABC_CP_H_
#define _SIMPLEABC_CP_H_
#include "simpleABC_cp_def.h"
/
#define SS_DATA_TYPE SS_BYTE
#define st000 8
#define st_C 14
#define st_B 22
#define st_A 30
#define evGo 1
#define SS_INFO_00 1
#define SS_INFO_01 4
#define SS_INFO_02 2
#ifdef SS_ARR_EVENT_INNER_AUTO
#define SS_INNER_QUEUE_SIZE 20
#else
#define SS_INNER_QUEUE_SIZE SS_ARR_EVENT_INNER_SIZE
#endif
/
class SS_STATE_CLASS
{
protected:
virtual SS_VOID AcEntryA(SS_VOID) = 0;
virtual SS_VOID AcEntryB(SS_VOID) = 0;
virtual SS_VOID AcEntryC(SS_VOID) = 0;
typedef SS_BOOL (SS_STATE_CLASS::*SS_CONDITION) (SS_VOID);
typedef SS_VOID (SS_STATE_CLASS::*SS_ACTION)    (SS_VOID);
private:
static SS_CONDITION const ss_arr_00[];
static SS_ACTION    const ss_arr_01[];
static SS_DATA_TYPE const ss_arr_02[];
static SS_DATA_TYPE const ss_arr_03[];
SS_DATA_TYPE ss_var_01;
SS_DATA_TYPE ss_var_02;
SS_DATA_TYPE ss_arr_04[SS_INFO_00 + 1];
SS_DATA_TYPE ss_arr_05[SS_INFO_02 + 1];
SS_DATA_TYPE ss_arr_06[SS_INNER_QUEUE_SIZE];
SS_VOID SS_Func_00     (SS_DATA_TYPE ss_v_00);
SS_DATA_TYPE SS_Func_01(SS_VOID);
SS_DATA_TYPE SS_Func_02(SS_DATA_TYPE ss_v_02);
SS_VOID SS_Func_03     (SS_DATA_TYPE ss_v_00);
virtual SS_VOID OnInnerQueueOverFlow(SS_WORD p);
public:
/
///User Interface
SS_BOOL GetIsInState(SS_DATA_TYPE stID);  //Check whether in state.
SS_VOID InitStates(SS_VOID); //Init.
SS_VOID ProcEvent(SS_DATA_TYPE evID); //Process event.
};
typedef SS_BOOL (SS_STATE_CLASS::*SS_CONDITION) (SS_VOID);
typedef SS_VOID (SS_STATE_CLASS::*SS_ACTION) (SS_VOID);
#endif  //#ifndef _SIMPLEABC_CP_H_
/
//VERSION: 1.0.0.1
//AUTHOR:  JEFF
//TIME:    2013-10-15 22:12:57
//DESCRIPTION: Edited by HEART-BLUE. Don't modify it.
/
#include "simpleABC_cp.h"
/
SS_CONDITION const SS_STATE_CLASS::ss_arr_00[] =
{
0,
};
SS_ACTION const SS_STATE_CLASS::ss_arr_01[] =
{
0,
&SS_STATE_CLASS::AcEntryA,
&SS_STATE_CLASS::AcEntryB,
&SS_STATE_CLASS::AcEntryC,
};
SS_DATA_TYPE const SS_STATE_CLASS::ss_arr_02[] =
{
0x00, 0x0E, 0x07, 0x00, 0x1E, 0x00, 0x00, 0x16,   0x0D, 0x00, 0x0E, 0x00, 0x00, 0x1E, 0x00, 0x00,
0x16, 0x00, 0x00,
};
SS_DATA_TYPE const SS_STATE_CLASS::ss_arr_03[] =
{
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08,   0x26, 0x01, 0x00, 0x1E, 0x00, 0x00, 0x16, 0x01,
0x08, 0x00, 0x14, 0x00, 0x03, 0x00, 0x1E, 0x01,   0x08, 0x00, 0x1C, 0x00, 0x02, 0x00, 0x26, 0x01,
0x08, 0x00, 0x24, 0x00, 0x01, 0x00,
};
SS_VOID SS_STATE_CLASS::SS_Func_00(SS_DATA_TYPE ss_v_00)
{
SS_DATA_TYPE ss_v_01 = ss_var_02;
if(ss_var_02 > 0)
ss_var_02--;
else
ss_var_02 = SS_INNER_QUEUE_SIZE - 1;
if(ss_var_02 == ss_var_01)
{
ss_var_02 = ss_v_01;
OnInnerQueueOverFlow(ss_v_00);
return;
}
else
ss_arr_06[ss_v_01] = ss_v_00;
}
SS_DATA_TYPE SS_STATE_CLASS::SS_Func_01(SS_VOID)
{
if(ss_var_02 == ss_var_01)
return 0;
else
{
SS_DATA_TYPE ss_v_00 = ss_arr_06[ss_var_01];
if(ss_var_01 > 0)
ss_var_01--;
else
ss_var_01 = SS_INNER_QUEUE_SIZE - 1;
return ss_v_00;
}
}
SS_DATA_TYPE SS_STATE_CLASS::SS_Func_02(SS_DATA_TYPE ss_v_02)
{
SS_DATA_TYPE ss_v_00 = 0;
const SS_DATA_TYPE * ss_v_01 = 0;
ss_v_00 = ss_arr_03[ss_v_02 + 4];
if(0 != ss_v_00)
{
ss_v_01 = ss_arr_03 + ss_v_00;
while(0 != (*ss_v_01))
{
if((*ss_v_01) >= SS_INFO_01)
SS_Func_00((*ss_v_01) - SS_INFO_01);
else
(this->*ss_arr_01[(*ss_v_01)])();
ss_v_01++;
}
}
ss_v_00 = ss_arr_03[ss_v_02 + 3];
if(0 != ss_v_00)
return SS_Func_02(ss_v_00);
else
return ss_v_02;
}
SS_VOID SS_STATE_CLASS::SS_Func_03(SS_DATA_TYPE ss_v_00)
{
const SS_DATA_TYPE * ss_p_00 = ss_arr_02 + ss_v_00;
while(0 != (*ss_p_00))
{
SS_DATA_TYPE ss_v_01;
SS_DATA_TYPE ss_v_02;
SS_DATA_TYPE ss_v_03;
SS_DATA_TYPE ss_v_04;
SS_DATA_TYPE ss_v_05;
ss_v_01 = (*ss_p_00);
ss_p_00++;
ss_v_02 = ss_arr_03[ss_v_01 + 1];
ss_v_03 = ss_arr_04[ss_v_02];
ss_v_04 = (*ss_p_00);
ss_p_00++;
ss_v_05 = (*ss_p_00);
ss_p_00++;
if(ss_v_03 >= ss_v_01 && ss_v_03 < ss_arr_03[ss_v_01])//In range
{
SS_DATA_TYPE ss_v_06;
SS_DATA_TYPE ss_v_07;
ss_v_07 = (*ss_p_00);
ss_p_00++;
if(0 != (*ss_p_00))
if(! (this->*ss_arr_00[(*ss_p_00)])())
goto PO_00;
ss_p_00++;
if(0 != ss_v_07)
{
SS_DATA_TYPE ss_v_08;
SS_DATA_TYPE ss_v_09;
if(ss_v_07 == ss_v_01)
{
ss_v_09 = ss_arr_03[ss_v_01 + 2];
ss_arr_05[0] = ss_v_01;
ss_v_08 = 1;
}
else
{
ss_v_06 = ss_v_07;
ss_v_08 = 0;
while(ss_v_01 < ss_v_06 || ss_v_01 >= ss_arr_03[ss_v_06])
{
ss_arr_05[ss_v_08] = ss_v_06;
ss_v_08++;
ss_v_06 = ss_arr_03[ss_v_06 + 2];
}
ss_v_09 = ss_v_06;
}
ss_v_06 = ss_v_03;
while(ss_v_06 != ss_v_09)
{
const SS_DATA_TYPE * ss_v_10 = ss_arr_03 + ss_v_06 + 5;
if(0 != (*ss_v_10))
{
ss_v_10 = ss_arr_03 + (*ss_v_10);
while(0 != (*ss_v_10))
{
if((*ss_v_10) >= SS_INFO_01)
SS_Func_00((*ss_v_10) - SS_INFO_01);
else
(this->*ss_arr_01[(*ss_v_10)])();
ss_v_10++;
}
}
ss_v_06 = ss_arr_03[ss_v_06 + 2];
}
while(0 != (*ss_p_00))
{
if((*ss_p_00) >= SS_INFO_01)
SS_Func_00((*ss_p_00) - SS_INFO_01);
else
(this->*ss_arr_01[(*ss_p_00)])();
ss_p_00++;
}
while(ss_v_08 > 0)
{
const SS_DATA_TYPE * ss_v_10;
ss_v_08--;
ss_v_10 = ss_arr_03 + ss_arr_05[ss_v_08] + 4;
if(0 != (*ss_v_10))
{
ss_v_10 = ss_arr_03 + (*ss_v_10);
while(0 != (*ss_v_10))
{
if((*ss_v_10) >= SS_INFO_01)
SS_Func_00((*ss_v_10) - SS_INFO_01);
else
(this->*ss_arr_01[(*ss_v_10)])();
ss_v_10++;
}
}
}
if(0 != ss_arr_03[ss_v_07 + 3])
ss_arr_04[ss_v_02] = SS_Func_02(ss_arr_03[ss_v_07 + 3]);
else
ss_arr_04[ss_v_02] = ss_v_07;
ss_v_06 = ss_v_05;
while(ss_arr_02[ss_v_06] == ss_v_02)
ss_v_06 = ss_arr_02[ss_v_06 + 2];
ss_v_05 = ss_v_06;
}
else
{
while(0 != (*ss_p_00))
{
if((*ss_p_00) >= SS_INFO_01)
SS_Func_00((*ss_p_00) - SS_INFO_01);
else
(this->*ss_arr_01[(*ss_p_00)])();
ss_p_00++;
}
}
PO_00:
ss_p_00 = ss_arr_02 + ss_v_05;
}
else
ss_p_00 = ss_arr_02 + ss_v_04;
}
}
SS_VOID SS_STATE_CLASS::OnInnerQueueOverFlow(SS_WORD p)
{
DO_SOMETHING_WHEN_INNER_QUEUE_OVER_FLOW
}
SS_BOOL SS_STATE_CLASS::GetIsInState(SS_DATA_TYPE stID)
{
SS_DATA_TYPE ss_v_00 = ss_arr_04[ss_arr_03[stID + 1]];
if(ss_v_00 >= stID && ss_v_00 < ss_arr_03[stID])
return SS_TRUE;
else
return SS_FALSE;
}
SS_VOID SS_STATE_CLASS::InitStates(SS_VOID)
{
SS_DATA_TYPE ss_v_00 = 0;
ss_var_01 = 0;
ss_var_02 = 0;
for(ss_v_00 = 1; ss_v_00 <= SS_INFO_00; ss_v_00++)
ss_arr_04[ss_v_00] = SS_Func_02(ss_arr_03[ss_v_00 + 6]);
while(ss_var_01 != ss_var_02)
SS_Func_03(SS_Func_01());
}
SS_VOID SS_STATE_CLASS::ProcEvent(SS_DATA_TYPE evID)
{
SS_Func_00(evID);
while(ss_var_01 != ss_var_02)
{
SS_Func_03(SS_Func_01());
}
}

在main函数中实现和调用:


#include #include "simpleABC_cp.h"
class A : public SS_STATE_CLASS
{
virtual SS_VOID AcEntryA(SS_VOID){printf("Entry A\n");};
virtual SS_VOID AcEntryB(SS_VOID){printf("Entry B\n");};
virtual SS_VOID AcEntryC(SS_VOID){printf("Entry C\n");};
};
int main()
{
A a;
a.InitStates();
while(getchar())
{
a.ProcEvent(evGo);
}
return 0;
}

一个自动将状态机生成代码的软件相关推荐

  1. python代码大全o-Python实现的一个自动售饮料程序代码分享

    写这个程序的时候,我已学习Python将近有一百个小时,在CSDN上看到有人求助使用Python如何写一个自动售饮料的程序,我一想,试试写一个实用的售货程序.当然,只是实现基本功能,欢迎高手指点,新手 ...

  2. Simulink自动代码生成:生成代码的基本设置

      Simulink自动代码生成也被称作基于模型开发(BMD),相比于传统的手写代码方式能够尽量减少人为错误.模型本身可以用于仿真,单元测试等,更便于提前发现逻辑错误.同时只要约定好模型接口,就可以多 ...

  3. python饮料购买_Python实现的一个自动售饮料程序代码分享

    写这个程序的时候,我已学习Python将近有一百个小时,在CSDN上看到有人求助使用Python如何写一个自动售饮料的程序,我一想,试试写一个实用的售货程序.当然,只是实现基本功能,欢迎高手指点,新手 ...

  4. java类可视化doxygen_安装doxygen(一个自动文档生成工具)+Graphviz图形可视化软件...

    参考文章: 1 Doxygen简介 1.1 What to do? 使用Doxygen生成文档,主要是两件事: 写一个配置文件(Doxyfile),一般用Doxywizard生成后,再手工修改[不建议 ...

  5. mybatis 代码生成器_spring Boot手把手教学(4): mybatis-plus 代码生成器,自动帮你生成代码

    1.前言 2.安装依赖 3.配置 4.生成器代码 5.代码展示 6.代码测试 6.1 添加工作 6.2 其余操作 1.前言 俗话说:工欲善其事,必先利其器. 我们在使用springBoot开发项目的, ...

  6. sparrow-js开源低代码场景化工作台,自动给你生成代码

    介绍 sparrow-js 是场景化低代码(LowCode)搭建工作台,通过操作场景化编辑器生成源代码,侧重于支持日常业务需求开发的效率提示,核心目标仅有一条"提生研发效率",目前 ...

  7. qq邮件太多如何一键删除?发一个自动删邮件的代码

    到qq邮箱,收件箱,打开f12 粘贴代码就可以了 async function delmail(){ document.querySelector("#mainFrame").co ...

  8. 能自动生成标注的html的软件,UI标注最高---PxCook3.0 设计师自动标注软件,点击生成代码。智能高效的设计开发工具...

    " 这世上哪有什么天才,有些人只是把大家设计标注.写前端的时间拿来喝咖啡,和思考罢了 PxCook,支持 Win & Mac,支持PS和Sketch的全平台工具."拖拽即用 ...

  9. Mybatis逆向工程自动生成代码文件

    一般来说都会新建另外一个项目,用于生成代码文件,然后拷贝到需要的项目中.新建maven项目用于生成代码文件,项目目录如下所示: pom.xml内容如下: <project xmlns=" ...

最新文章

  1. oracle, group by, having, where
  2. 批处理taskkill运行结束不掉程序以及停留问题
  3. 小米手机 DELETE_FAILED_INTERNAL_ERROR Error while Installing APKs
  4. 【BZOJ 4555】[Tjoi2016Heoi2016]求和 多项式求逆/NTT+第二类斯特林数
  5. java时钟面板clock
  6. NOIP模拟测试34「次芝麻·呵呵呵·长寿花」
  7. leetcode 1720. 解码异或后的数组(位运算)
  8. ExtJs之Ext.data.Store
  9. Ubuntu vi命令
  10. RPM 打包指南系列 一
  11. hbase中为何不能向表中插入数据_MySQL数据库中表记录的增、删和改操作
  12. vue 为全局变量赋值_在vue项目中 如何定义全局变量 全局函数
  13. Flutter 项目实战 网络请求MD5+时间戳+验证签名 十一
  14. 【免费抢票】6月9日杭州,产品经理会议
  15. 微信支付:appid 与 openId 不配
  16. 英语思维导图大全 介词(七)
  17. MDS(多维尺度变换)
  18. ilm 和dlm差异_ILM是什么意思
  19. Codeforces Round #672 (Div. 2) C2 - Pokémon Army (hard version)(贪心,维护变化值)
  20. Verilog永无止境

热门文章

  1. macbarcode软件_条形码生成器 for mac-条形码生成器 mac版下载V17.0__西西软件下载
  2. 【Linux8系统学习】使用RAID与LVM磁盘陈列技术(一)
  3. raid技术基本原理
  4. 抖音小店无货源的回款周期是多久?怎么加快小店的回款周期?
  5. [黑马IOS自学第十篇]OC语言基础,面向对象概念,类学习
  6. ArcGIS支持实时地理信息系统
  7. Kubernetes安装
  8. RH358管理DHCP和IP地址分配--配置分配IPv6地址
  9. 3.Containerd容器运行时的配置浅析与知识扩充实践
  10. macbook使用指南