请问实现自动状态机编程问题~!分不够再加!

danmao 2003-04-03 06:24:02
状态机的实现编程有多种实现方法,但是我希望在编译成程序以后,程序还可以根据配置文件来决定状态:定义状态个数、一个状态转入下一个状态的条件都在配置文件中给出。这样的功能该怎样设计?
...全文
391 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
danmao 2003-04-24
  • 打赏
  • 举报
回复
有点意思了,跟我想的接近,但是不能解决运行时决定操作,除非事先定义好状态!
xiaocha 2003-04-17
  • 打赏
  • 举报
回复
生成一棵树就行了,树的节点有输入、动作等内容,根节点表示初始状态
自动贩卖机可以表示成:(有动作的节点,完成动作后,自动回到root)
root
1 买水
2 无动作
1 买橙汁
2 买西瓜汁
树的规模不大时,可以在内存实现,规模大时,可以用数据库实现
danmao 2003-04-14
  • 打赏
  • 举报
回复
zhaoao5958(不会游泳的鱼) ,
“动态地生成状态转换表。”请稍微说明得详细点好吗?因为我认为状态转换表对于自定义操作作用不大。


mars22(三月瓜)兄,你可以把那个文章发我一份看看吗?这样我比较好和你讨论, :)
maodan520◎hotmail.com,谢谢。
mars22 2003-04-12
  • 打赏
  • 举报
回复
danmao,
我明白了,所以没有贴下去,那文章还有几章的.
如果要动态的话,需要把mirage修改一下.
每次触发事件后就去读数据库,把代码生成改为直接执行好了.

不过IO部分是要人工填写好的,大家想想怎么link过去吧.
zhaoao 2003-04-11
  • 打赏
  • 举报
回复
动态地生成状态转换表。
danmao 2003-04-10
  • 打赏
  • 举报
回复
mars22(三月瓜) 兄,你可能误会我了,我并不是求FSM实现,我是想要将状态定义和操作定义从程序中间解放出来。比如说,我有一台自动贩卖机(程序实现)。现在我希望在文件中定义:

按1,买水。
按2,然后按1,买橙汁。
按2,然后按2,买西瓜汁。
……

程序就可以按照这个文件定义来执行(也可能我不定义按1这个状态,则自动贩卖机不会给出响应)。
FishCrazy 2003-04-09
  • 打赏
  • 举报
回复
prolog通常是用于人工智能,其实它的本质还是同字符串的搜索

在这个方面,它比其他语言是有优势的。

danmao 2003-04-09
  • 打赏
  • 举报
回复
用PROLOG?你是做人工智能啊!我要用C++

Chrisma(Chrisma),非常感谢!虽然不是很合适,但是给了我很好的启发,暂时不能结贴。分一定给!

还有好的建议没有啊?
FishCrazy 2003-04-09
  • 打赏
  • 举报
回复
用c语言的话,我觉得似乎很难呢,不过如果使用Prolog,那么就相当简单了

如果搂主想要的话,我可以写给你

现在用PROLOG的人似乎不是很多啊........
Chrisma 2003-04-09
  • 打赏
  • 举报
回复
参见华中科技大学出版的《C++程序设计实践教程》,马光志编
使用有限自动机编程解决如下问题:有一个人带着狼、羊和草来到河的左岸,左岸
只有一条无人摆渡的船。这个人要从左岸过河到右岸,可是这条船最多只能装一个人和
其他三者之一,否则便会沉没。如果没有人看管,狼会吃掉羊,或者羊吃掉草。问如何
过河才能保证羊和草的安全。
提示:作为有限状态自动机的输入,人单独过河用字符m表示,人带狼过河用字符w
表示,人带羊过河用字符s表示,人带草过河用字符g表示,声明有限自动机的start、
stop以及error状态对象,如果start.start("smwsgms")=&stop,则过河成功,否则,
如果start.start("smwsgms") ==&error,则过河失败。


#include <string.h>
#include <iostream.h>
class STATE;
class LIST{
LIST *next;
char input;
STATE *output;
LIST(char in, STATE *out); //私有,仅供STATE使用
~LIST( );
friend STATE;
};
LIST::LIST(char in, STATE *out){
input=in;
output=out;
next=0;
}
LIST::~LIST( ){
if(this->next){ delete this->next;}
}
class STATE{
char *name; //状态名
LIST *list; //输入及输出列表
static STATE*error;
public:
void enlist(char in, STATE *out);//插入list
const STATE *next(char in)const; //输入in转移到下一个状态
const STATE *start(char *)const; //启动有限自动机
STATE(char *name);
~STATE( );
};
STATE *STATE::error=0;
STATE::STATE(char *name):name(0),list(0){
if(name==0){ error=this; return; }
STATE::name=new char[strlen(name)+1];
strcpy(STATE::name, name);
}
void STATE::enlist(char in, STATE *out){ //插入list
LIST *temp;
if(list==0){
list=new LIST(in, out);
return;
}
temp=new LIST(in, out);
temp->next=list;
list=temp;
}
const STATE *STATE::next(char in)const{ //输入in转移到下一个状态
LIST *temp=list;
if(this==error) return error;
while(temp)
if(temp->input==in) return temp->output;
else temp=temp->next;
return error;
}
const STATE *STATE::start(char *s)const{ //启动有限自动机
const STATE *temp=this;
while(*s) temp=temp->next(*s++);
return temp;
}
STATE::~STATE( ){
if(name) {cout<<name<<"\n"; delete name; name=0; }
if(list) {delete list; list=0; }
}
void main( ){
STATE start("WSGM_");
STATE stop("_WSGM");
STATE error(0);
STATE WG_SM("WG_SM");
STATE WGM_S("WGM_S");
STATE G_WSM("G_WSM");
STATE SGM_W("SGM_W");
STATE W_SGM("W_SGM");
STATE WSM_G("WSM_G");
STATE S_WGM("S_WGM");
STATE SM_WG("SM_WG");
start.enlist('S', &WG_SM);
WG_SM.enlist('S', &start);
WG_SM.enlist('M', &WGM_S);
WGM_S.enlist('M', &WG_SM);
WGM_S.enlist('W', &G_WSM);
WGM_S.enlist('G', &W_SGM);
G_WSM.enlist('W', &WGM_S);
W_SGM.enlist('G', &WGM_S);
G_WSM.enlist('S', &SGM_W);
SGM_W.enlist('S', &G_WSM);
SGM_W.enlist('G', &S_WGM);
S_WGM.enlist('G', &SGM_W);
W_SGM.enlist('S', &WSM_G);
WSM_G.enlist('S', &W_SGM);
WSM_G.enlist('W', &S_WGM);
S_WGM.enlist('W', &WSM_G);
S_WGM.enlist('M', &SM_WG);
SM_WG.enlist('M', &S_WGM);
SM_WG.enlist('S', &stop);
stop.enlist('S', &SM_WG);
if(start.start("SMWSGMSSS")==&stop) cout<<"OK";
}

有限自动机也可以解决三个修道士与三个野人的过河问题,假定船最多只能载两个
修道士或者野人,野人服从修道士的指挥。无论何时,只要野人多于修道士,野人就会
吃掉修道士。以有限自动机为基础,编程解决三个修道士与三个野人的过河问题。
Chrisma 2003-04-09
  • 打赏
  • 举报
回复
我有一个,只差根据配置文件生成转移表。不过该程序很容易修改成支持的.
mars22 2003-04-09
  • 打赏
  • 举报
回复

下面是System的代码规范:
1.system主体
和FSM的实现非常类似,只是没有S集合而已,每个SI成员从0开始定义.
它的主体函数也是一个swtich分发而已,不同的SI链接到不同的地方去,简单的函数调用,也就是FSM的分发函数加以相应输入作为参数.
2.system输出头文件
每个SO成员定义一个0开始的整数,每个输出函数的声明也放在这里,很简单.
3.system输出函数
system的输出,或者操作,是需要开发者改动的代码(其它的mirage自动生成),这里只是一些函数框架,这套规范保证这些输出函数将在适当的时候被调用.
源代码是最好的语言,来看例子吧:
--------------------------------------system头文件--------------------------------------
// This file is created by Mirage.
// Mirage is a freeware under the GNU General Public License.
// http://sourceforge.net/projects/mirages/
// mirages-developer@lists.sourceforge.net


#ifndef MIRAGE_SYSTEST_H
#define MIRAGE_SYSTEST_H

//define SysTest input
#define SYSTEST_I_SI1 0 //System Input NO.1
#define SYSTEST_I_SI2 1 //System Input No.2


//define SysTest machine
void SysTest(int nSysInput) ;

#endif //MIRAGE_SYSTEST_H

--------------------------------------system的C文件--------------------------------------
// This file is created by Mirage.
// Mirage is a freeware under the GNU General Public License.
// http://sourceforge.net/projects/mirages/
// mirages-developer@lists.sourceforge.net


#include "SysTest.h"
#include "SysTest_O.h"
#include "Auto1.h"
#include "Auto2.h"


void SysTest(int nSysInput)
{
switch(nSysInput)
{
case SYSTEST_I_SI1:
Auto1(AUTO1_I_A1I1) ;
break ;
case SYSTEST_I_SI2:
Auto2(AUTO2_I_A2I1) ;
break ;

default:
break ;
}//switch

return ;
}

--------------------------------------system输出头文件--------------------------------------
// This file is created by Mirage.
// Mirage is a freeware under the GNU General Public License.
// http://sourceforge.net/projects/mirages/
// mirages-developer@lists.sourceforge.net


#ifndef MIRGAE_SYS_O_H
#define MIRGAE_SYS_O_H

//define System output
#define SYSTEST_O_SO1 0 //System Output No.1
#define SYSTEST_O_SO2 1 //System Output No.2

//define system output function
void SysTest_SO1() ; //System Output No.1
void SysTest_SO2() ; //System Output No.2

#endif // MIRGAE_SYS_O_H

--------------------------------------system输出C文件--------------------------------------
// This file is created by Mirage.
// Mirage is a freeware under the GNU General Public License.
// http://sourceforge.net/projects/mirages/
// mirages-developer@lists.sourceforge.net


#include "SysTest_O.h"

//System Output No.1
void SysTest_SO1()
{
//add your code here.
return ;
}

//System Output No.2
void SysTest_SO2()
{
//add your code here.
return ;
}
--------------------------------------结束--------------------------------------
mars22 2003-04-09
  • 打赏
  • 举报
回复
三.代码规范
当我们在系统的分析和设计阶段使用FSM之后,随后的问题就是如何实现它.(各位可曾注意到,我们祖国各地的火车站是多么相似吗?)下面我们介绍可行的编码规范,它们将使用FSM定义中所有因素,并且原汁原味地实现了FSM的定义,大大提高了代码的质量,至少提高了可读性.
面向对象的编码规范和工具,可以参考:
http://www.objectmentor.com/resources/downloads/bin/smc.zip
http://www.objectmentor.com/resources/downloads/bin/smcJava.zip
在嵌入式软件的开发中,我们往往无法使用C++或者Java等面相对象语言,所以下面我介绍一下C语言和汇编的实现规范.

C语言:
每个FSM的实现代码分以下几步:
1.头文件
我们需要把S,FI,FO的所有成员使用#define定义到一个整数上.为了调用方便,规定FI和FO从0开始逐个定义,S则从0开始,以SI的成员数量作为间隔定义.例如FI集合有15个成员,它们分别定义为0~14,而集合S有4个成员,它们将是0,15,30,45.
另外,还要定义S-FI组合,有了上面的规定大家可以看到,只要简单的把它们相加就是连续的整数了.
2.分发机制
很简单,就是一个switch语句,根据S-FI组合进入不同的case分句中,每个分句通常由状态变更语句和输出语句组成,由于我们将为每个输出编写一个单独的函数,而前者是一个赋值语句,大家可以想见每个case是很清爽的.
3.输出函数
每个输出一个函数,根据System的定义它必然链接到FSM输入或者System的输出上,它们也都是一个函数调用而已.
当然了,分发函数和状态变量的声明,头文件中还是需要有的.
下面是一个例子,它是由mirage生成的,熟悉C语言的读者可以很容易地读懂它们:
--------------------------------------h文件--------------------------------------
// This file is created by Mirage.
// Mirage is a freeware under the GNU General Public License.
// http://sourceforge.net/projects/mirages/
// mirages-developer@lists.sourceforge.net


#ifndef MIRAGE_AUTO1_H
#define MIRAGE_AUTO1_H

//define Auto1 state
#define AUTO1_S_A1S1 0 //Auto1 State No.1
#define AUTO1_S_A1S2 2 //Auto1 State No.2

//define Auto1 input
#define AUTO1_I_A1I1 0 //Auto1 Input No.1
#define AUTO1_I_A1I2 1 //Auto1 Input2

//define Auto1 output
#define AUTO1_O_A1O1 0 //Auto1 Output1

//define Auto1 State-Input peer
#define AUTO1_A1S1_A1I1 0 //Auto1 State No.1-Auto1 Input No.1
#define AUTO1_A1S1_A1I2 1 //Auto1 State No.1-Auto1 Input No.1
#define AUTO1_A1S2_A1I1 2 //Auto1 State No.2-Auto1 Input2
#define AUTO1_A1S2_A1I2 3 //Auto1 State No.2-Auto1 Input2

extern int nAuto1CurState ;

void Auto1(int nAuto1Input) ; //Finite State Machine Auto1

#endif //MIRAGE_AUTO1_H

--------------------------------------C文件--------------------------------------
// This file is created by Mirage.
// Mirage is a freeware under the GNU General Public License.
// http://sourceforge.net/projects/mirages/
// mirages-developer@lists.sourceforge.net


#include "SysTest_O.h"
#include "Auto1.h"
#include "Auto2.h"


int nAuto1CurState = 0 ;

void Auto1_A1O1()
{

return ;
}


void Auto1(int nAuto1Input)
{
int nNextState = nAuto1CurState ;

switch(nAuto1CurState+nAuto1Input)
{
case AUTO1_A1S1_A1I1:
nNextState = AUTO1_S_A1S2 ;
Auto1_A1O1() ;
break ;
case AUTO1_A1S1_A1I2:
nNextState = AUTO1_S_A1S1 ;
Auto1_A1O1() ;
nNextState = AUTO1_S_A1S2 ;
Auto1_A1O1() ;
break ;
case AUTO1_A1S2_A1I1:
nNextState = AUTO1_S_A1S2 ;
Auto1_A1O1() ;
break ;
case AUTO1_A1S2_A1I2:
nNextState = AUTO1_S_A1S2 ;
Auto1_A1O1() ;
break ;

default:
break ;
}//switch

nAuto1CurState = nNextState ;

return ;
}
--------------------------------------结束--------------------------------------
mars22 2003-04-09
  • 打赏
  • 举报
回复
mirage简介

关键词:代码生成,嵌入式软件,有限状态机.

一.前言
最近的一年多,我一直在从事嵌入式软件设计与开发,本文将简述期间的一些经验,以及针对一些问题开发的小工具.
首先介绍一下"火车站"模型,观察铁路系统可以得出这样的结论,系统由少量的集散点(火车站),以及大量的简单轨道组成.简单轨道也涉及少量的切换控制,但是绝大部分的轨道网络和控制部分,是集中在火车站附近的.这类系统的特征是:
.主要的控制集中在少数中心点.
.中心点之间的轨道情况比较简单.
相应的,火车站及其配套设施的设计,与简单轨道的设计是不一样的:
.中心点设计攻关,更多考虑质量.
.专门的设计模式,套路.
.选择环境,改造环境,减少环境干扰以确保设计质量.
.中心点之间根据情况设计,更多考虑成本.
软件开发中也大量存在类似的情况,这里我们也可以考虑对中心点使用专门的方法,以保证质量为第一目标.而对简单的,近似顺序执行的部分则更注重实现的成本.

后面我会介绍有限状态机(FSM:Finited State Machine)的概念,作为分析中心模块的基础,学习过离散数学和计算理论的读者可以略过.下一节介绍一套基于FSM的C和汇编语言编码规范,为前面的分析提供一个具体有效的实现途径.第四节我介绍根据这套编码规范开发的工具mirage的操作指南.最后提出一些有待讨论的改进方案,希望各位读者能够参与mirage的改进.

二.有限状态机FSM
FSM是一种数学模型,是对实际世界的一种表示方法,目前已有很多资料介绍,这里只简单提及需要用到的基本概念.
FSM的种类有:
确定的:后续状态和输出,由初始状态和输入唯一确定.
不确定的:对于特定的初始状态和输入,存在多和合法的后续状态和输出.
带输出的
不带输出的
基于映射的:输出由初始状态和输入确定.
基于状态的:输出由后续状态确定.
我们这里所讨论的,是确定的,带输出的,基于映射的FSM,后面不再特别列这堆定语了.
FSM的定义由五部分组成:
状态集合S
输入集合FI
输出集合FO
映射关系集合f(S,FI)->(S,FO)
初始状态s0
它们的含意很明确,不解释了.

一个系统中通常会包含多个FSM,为此我定义了系统System:
输入集合SI
输出集合SO
链接集合g:(有四种链接情况)
1.SI->FI
2.SI->SO
3.FO->FI
4.FO->SO
大家已经看到,这里给出的定义是有一定局限的,不能很好的描述所有系统,这是个取舍问题,它能够覆盖我实际工作中遇到的所有系统.
FishCrazy 2003-04-09
  • 打赏
  • 举报
回复
举个例子:比如一种自动售货机,只接受10元和5元的硬币,每投入15元便可以获得一瓶水

输入:5元、10元

输出:5元和水、水

初始状态--5-->状态(5)--10-->初始状态===>水
| | /|\
10 5 |
| | |
\|/ | |
状态(10)<-----| |
| |
|-----10----->初始状态==>水+5元 |
| |
|------5------------------------|

搂主就是想完成这样的转换吧?
FishCrazy 2003-04-09
  • 打赏
  • 举报
回复
举个例子:比如一种自动售货机,只接受10元和5元的硬币,每投入15元便可以获得一瓶水

输入:5元、10元

输出:5元和水、水

初始状态--5-->状态(5)--10-->初始状态===>水
| | /|\
10 5 |
| | |
\|/ | |
状态(10)<-----| |
| |
|-----10----->初始状态==>水+5元 |
| |
|------5------------------------|

搂主就是想完成这样的转换吧?
BlueSky2008 2003-04-09
  • 打赏
  • 举报
回复
我觉得很好改,从编程角度将只要将程序中所有指示State,Event,Operator的变量,函数换成指针,而指针指向处的值,由你动态修改.如果State,Event,Operator的数量也不确定的话,则应建立链表,动态添加,删除.
flyfash 2003-04-07
  • 打赏
  • 举报
回复
up
danmao 2003-04-07
  • 打赏
  • 举报
回复
算法基本按照design patterns 中的State pattern。
我们定义一些术语吧,这样好讨论。

State:状态
Event:触发事件
Operator:操作
StateMachine:状态机

你有没有看State模式?
一般来说Event传入一个Current State,如果这个State能够响应这个Event调用它的Operators(注意:可能有多个)。

现在需要在运行时确定的就是:
1、State的个数
2、State所包含的Operator

我是这样想的。各位有什么好建议?
diabloqin 2003-04-07
  • 打赏
  • 举报
回复
up
加载更多回复(10)

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧