有限状态机
http://www.ibm.com/developerworks/cn/linux/l-fsmachine/index.html
有限状态机是一种用来进行对象行为建模的工具,其作用主要是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。在面向对象的软件系统中,一个对象无论多么简单或者多么复杂,都必然会经历一个从开始创建到最终消亡的完整过程,这通常被称为对象的生命周期。
http://kb.cnblogs.com/page/528972/
有限状态机的工作原理如图1所示,发生事件(event)后,根据当前状态(cur_state) ,决定执行的动作(action),并设置下一个状态号(nxt_state)。
图2为一个状态机实例的状态转移图,它的含义是:
- 在s0状态,如果发生e0事件,那么就执行a0动作,并保持状态不变;
- 如果发生e1事件,那么就执行a1动作,并将状态转移到s1态;
- 如果发生e2事件,那么就执行a2动作,并将状态转移到s2态;
- 在s1状态,如果发生e2事件,那么就执行a2动作,并将状态转移到s2态;
- 在s2状态,如果发生e0事件,那么就执行a0动作,并将状态转移到s0态。
类xml标签匹配应用
应用例子:
通过状态机解析一个类xml结构的单层字符串,有如下结构:
... <xx>yyy<xx> ...
解析出结果放到链表中。
分析此对象类xml解析器对象, 对象随着处理输入(单层,类xml字符串), 会改变自己的状态,
分析状态包括以下几个:
NULL状态 -- 此状态为解析器的初始状态,或者结束状态,即 在未解析到 第一个<字符之前, 或者解析完最后一个 > 之后;
START_TAG状态 -- 解析开始标签状态, 即第一个<xx>
CONTENT状态 -- 解析标签内容状态
END_TAG状态 -- 解析结束标签状态, 即第二个<xx>
状态变迁的顺序为 NULL –> START_TAG –> CONTENT –> END_TAG –> NULL
事件为 当前输入的类xml字符串中的字符
动作为 对输入字符串的处理, 是存储还是丢弃, 是否starttag 等于 endtag, 保存tag和content。
给出完整的状态转移图:
C Code implementation
https://github.com/fanqingsong/code-snippet/tree/master/C/tagContentParsing
实现思路是, 构造识别循环, 根据 当前状态 和 输入字符, 决定迁移状态, 和执行动作。
将当前状态 和 输入字符, 决定迁移状态, 和执行动作 作为四元组, 构造成一个表,
输入字符后, 查表得到 迁移状态,和 执行动作, 得到迁移状态后修改状态机状态, 并执行动作。
这种表的处理方式, 对应设计模式为职责链模式。
/****************************************************************************** Description: parsing xml tag content into list such as string has format .... <xx>yyy<xx> ..., with single layer insert xx-yyy into a list ******************************************************************************/ #include <stdio.h> #include <string.h> #include <assert.h> #include <malloc.h> #include <stdarg.h> /* ------------------------------ 声明区域 --------------------------------- */ // list node typedef struct node{ char* tagName; char* content; struct node* next; } T_NODE, *PT_NODE; typedef enum returnType { FAIL = 0, SUCCESS, } E_RETURN_TYPE; typedef enum boolType { FALSE = 0, TRUE, } E_BOOL_TYPE; typedef struct stringObj{ char* szStr; int iLen; int iIndex; E_BOOL_TYPE bIsMalloc; int iMallocSize; } T_STRING_OBJ, *PT_STRING_OBJ; void MyPrintf(char* fmt, ...); char* DupSubStr(char* str, int start, int end); void StopWithMsg(char* msg); typedef enum xmlParseMachineState { XML_PARSE_STATE_NULL = 0, XML_PARSE_STATE_STARTTAG, XML_PARSE_STATE_CONTENT, XML_PARSE_STATE_ENDTAG, } E_XML_PARSE_STATE; typedef struct xmlParseStateMachine{ E_XML_PARSE_STATE eParseState; T_STRING_OBJ tStartTag; T_STRING_OBJ tEndTag; T_STRING_OBJ tContent; } T_XML_PARSE_STATE_MACHINE, *PT_XML_PARSE_STATE_MACHINE; // rule function definition typedef E_BOOL_TYPE (*IsEventTriggered)(char cCurrentChar); typedef E_RETURN_TYPE (*EventHandler)(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead); // state change rule: parse state -> event -> target state -> doaction typedef struct stateChangeRule { E_XML_PARSE_STATE eCurrentState; IsEventTriggered isEventTriggered; E_XML_PARSE_STATE eTransferState; EventHandler eventhandler; } T_STATE_CHANGE_RULE, *PT_STATE_CHANGE_RULE; void InitXMLParseStateMachine(PT_XML_PARSE_STATE_MACHINE ptXMLParseStateMachine); void FreeXMLParseStateMachine(PT_XML_PARSE_STATE_MACHINE ptXMLParseStateMachine); typedef struct xmlNode{ char* tagName; char* content; } T_XML_NODE, *PT_XML_NODE; E_BOOL_TYPE IsEventTriggered_StateNull_Jump2StartTag(char cCurrentChar); E_RETURN_TYPE EventHandler_StateNull_Jump2StartTag(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead); E_BOOL_TYPE IsEventTriggered_StateNull_KeepState(char cCurrentChar); E_RETURN_TYPE EventHandler_StateNull_KeepState(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead); E_BOOL_TYPE IsEventTriggered_StateStartTag_Jump2Content(char cCurrentChar); E_RETURN_TYPE EventHandler_StateStartTag_Jump2Content(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead); E_BOOL_TYPE IsEventTriggered_StateStartTag_KeepState(char cCurrentChar); E_RETURN_TYPE EventHandler_StateStartTag_KeepState(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead); E_BOOL_TYPE IsEventTriggered_StateContent_Jump2EndTag(char cCurrentChar); E_RETURN_TYPE EventHandler_StateContent_Jump2EndTag(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead); E_BOOL_TYPE IsEventTriggered_StateContent_KeepState(char cCurrentChar); E_RETURN_TYPE EventHandler_StateContent_KeepState(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead); E_BOOL_TYPE IsEventTriggered_StateEndTag_Jump2Null(char cCurrentChar); E_RETURN_TYPE EventHandler_StateEndTag_Jump2Null(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead); E_BOOL_TYPE IsEventTriggered_StateEndTag_KeepState(char cCurrentChar); E_RETURN_TYPE EventHandler_StateEndTag_KeepState(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead); /* ------------------------------ 全局变量 --------------------------------- */ T_STATE_CHANGE_RULE g_stateChangeTable[] = { { XML_PARSE_STATE_NULL, IsEventTriggered_StateNull_Jump2StartTag, XML_PARSE_STATE_STARTTAG, EventHandler_StateNull_Jump2StartTag }, { XML_PARSE_STATE_NULL, IsEventTriggered_StateNull_KeepState, XML_PARSE_STATE_NULL, EventHandler_StateNull_KeepState }, { XML_PARSE_STATE_STARTTAG, IsEventTriggered_StateStartTag_Jump2Content, XML_PARSE_STATE_CONTENT, EventHandler_StateStartTag_Jump2Content }, { XML_PARSE_STATE_STARTTAG, IsEventTriggered_StateStartTag_KeepState, XML_PARSE_STATE_STARTTAG, EventHandler_StateStartTag_KeepState }, { XML_PARSE_STATE_CONTENT, IsEventTriggered_StateContent_Jump2EndTag, XML_PARSE_STATE_ENDTAG, EventHandler_StateContent_Jump2EndTag }, { XML_PARSE_STATE_CONTENT, IsEventTriggered_StateContent_KeepState, XML_PARSE_STATE_CONTENT, EventHandler_StateContent_KeepState }, { XML_PARSE_STATE_ENDTAG, IsEventTriggered_StateEndTag_Jump2Null, XML_PARSE_STATE_NULL, EventHandler_StateEndTag_Jump2Null }, { XML_PARSE_STATE_ENDTAG, IsEventTriggered_StateEndTag_KeepState, XML_PARSE_STATE_ENDTAG, EventHandler_StateEndTag_KeepState } }; /* ------------------------------ 公共函数 --------------------------------- */ // MyPrintf == puts + format args void MyPrintf(char* fmt, ...) { va_list args; va_start(args, fmt); vprintf(fmt, args); va_end(args); printf(" "); } // 创建新的存储空间, 拷贝字符串的子串 char* DupSubStr(char* str, int start, int end) { char* newStr = NULL; // sub string len 开区间 计算子串长度 int len = end - start + 1; // regarding ending zero len++; newStr = (char*)malloc( sizeof(char)*len ); if ( NULL == newStr ) { return NULL; } newStr[len-1] = '