有限状态机

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 listsuch as string has format .... <xx>yyy<xx> ..., with single layerinsert 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("\r\n");
}// 创建新的存储空间, 拷贝字符串的子串
char* DupSubStr(char* str, int start, int end)
{char* newStr = NULL;// sub string len 开区间 计算子串长度int len = end - start + 1;// regarding ending zerolen++;newStr = (char*)malloc( sizeof(char)*len );if ( NULL == newStr ){return NULL;}newStr[len-1] = '\0';strncpy(newStr, str+start, len-1);return newStr;
}/* duplicates a string */
char *dupstr(const char *s)
{  char *p = malloc(strlen(s) + 1);  if (p)  strcpy(p, s);  return p;
}  void StopWithMsg(char* msg)
{puts(msg);assert(0);
}// 释放字符串指针
void FreeStrPoint(char** pszStr)
{char* szStr = *pszStr;if ( szStr ){free(szStr);}*pszStr = NULL;
}/* ------------------------------ 链表函数 --------------------------------- */
void FreeNode(PT_NODE* pptNode)
{PT_NODE ptNode = *pptNode;FreeStrPoint(&(ptNode->tagName));FreeStrPoint(&(ptNode->content));free(ptNode);*pptNode = NULL;
}void FreeList(PT_NODE ptHeadNode)
{PT_NODE ptCurNode = ptHeadNode->next;PT_NODE ptNextNode = NULL;while(ptCurNode){ptNextNode = ptCurNode->next;FreeNode(&ptCurNode);ptCurNode = ptNextNode;}
}E_BOOL_TYPE Insert2List(PT_NODE ptHeadNode, char* tagName, char* content)
{PT_NODE ptNode = NULL;PT_NODE ptFirst = NULL;ptNode = (PT_NODE) malloc(sizeof(T_NODE));if ( ptNode == NULL ){return FAIL;}ptNode->tagName = (char*)dupstr(tagName);if ( !ptNode->tagName ){FreeNode(&ptNode);return FAIL;}ptNode->content = (char*)dupstr(content);if ( !ptNode->content ){FreeNode(&ptNode);return FAIL;}ptFirst = ptHeadNode->next;ptHeadNode->next = ptNode;ptNode->next = ptFirst;return SUCCESS;
}void PrintList(PT_NODE ptHeadNode)
{PT_NODE ptCurNode = NULL;MyPrintf("---- list printing begin -----");ptCurNode = ptHeadNode->next;while(ptCurNode){MyPrintf("node tagname is %s", ptCurNode->tagName);MyPrintf("node content is %s", ptCurNode->content);ptCurNode = ptCurNode->next;}MyPrintf("---- list printing end -----");
}void AssertList(PT_NODE ptHeadNode, T_XML_NODE    xmlArr[]){int index = 0;PT_NODE ptCurNode = ptHeadNode->next;while(ptCurNode){if ( xmlArr[index].tagName == NULL ){StopWithMsg("xmlArr reach top, but list not over.");return;}if ( strcmp(ptCurNode->tagName, xmlArr[index].tagName) == 0&& strcmp(ptCurNode->content, xmlArr[index].content) == 0 ){//MyPrintf("List index[%d] str [%s] matched.", index, strArr[index]);index++;ptCurNode = ptCurNode->next;}else{StopWithMsg("List index xml don't matched.");return;}}if ( xmlArr[index].tagName != NULL ){StopWithMsg("AssertList failed.");return;}else{//MyPrintf("match all");
    }
}void TestList()
{T_NODE headNode = {NULL, NULL};Insert2List(&headNode, "first", "firstcontent");Insert2List(&headNode, "second", "secondcontent");PrintList(&headNode);T_XML_NODE xmlArr[] = {{"second", "secondcontent"},{"first", "firstcontent"},{NULL, NULL},};AssertList(&headNode, xmlArr);FreeList(&headNode);
}// list 链表操作测试用例
void TestListCase()
{TestList();
}/* ------------------------------ 普通字符串 -------------------------------- */
#define STRING_MEM_BACK_SIZE 516 // 字符串预留空间,以备后续添加字符// 初始化字符串对象
void InitStrObjStruct(PT_STRING_OBJ ptStrObj, char* szStr, E_BOOL_TYPE bIsMalloc)
{ptStrObj->iLen = strlen(szStr);ptStrObj->iIndex = 0;ptStrObj->bIsMalloc = bIsMalloc;if ( bIsMalloc ){ptStrObj->iMallocSize = ptStrObj->iLen+STRING_MEM_BACK_SIZE;ptStrObj->szStr = malloc(ptStrObj->iMallocSize);strncpy(ptStrObj->szStr, szStr, ptStrObj->iLen);ptStrObj->szStr[ptStrObj->iLen] = '\0';}else{ptStrObj->szStr = szStr;}
}void AddChar2StrObj(PT_STRING_OBJ ptStrObj, char cChar)
{if ( !ptStrObj->bIsMalloc ){return ;}if ( ptStrObj->iLen >= ptStrObj->iMallocSize-1 ){ptStrObj->szStr = realloc(ptStrObj->szStr, ptStrObj->iMallocSize+STRING_MEM_BACK_SIZE);if ( !ptStrObj->szStr ){StopWithMsg("realloc fail");return;}else{ptStrObj->iMallocSize = ptStrObj->iMallocSize+STRING_MEM_BACK_SIZE;}}ptStrObj->szStr[ptStrObj->iLen] = cChar;ptStrObj->iLen++;ptStrObj->szStr[ptStrObj->iLen] = '\0';
}void FreeStrObjMem(PT_STRING_OBJ ptStrObj)
{if ( ptStrObj->bIsMalloc ){FreeStrPoint(&(ptStrObj->szStr));}
}// 从字符串中获取当前一个字符,并将指针指向下一个字符
char GetCharFromStr(PT_STRING_OBJ ptStrObj)
{char retChar = '\0';if ( ptStrObj->iIndex >= ptStrObj->iLen ){// 已到尾部,无字符串可取return '\0';}// get current charretChar = ptStrObj->szStr[ptStrObj->iIndex];// navigate to next charptStrObj->iIndex++;return retChar;
}// 从字符串中获取当前一个字符,不执行指针指向下一个字符
char GetCharFromStr_purely(PT_STRING_OBJ ptStrObj)
{char retChar = '\0';if ( ptStrObj->iIndex >= ptStrObj->iLen ){// 已到尾部,无字符串可取return '\0';}// get current charretChar = ptStrObj->szStr[ptStrObj->iIndex];return retChar;
}//比较字符, 迁移str的index
E_BOOL_TYPE MatchCharInStr(char cChar, PT_STRING_OBJ ptStrObj)
{char cCurChar = GetCharFromStr(ptStrObj);if ( cCurChar == '\0' ){return FALSE;}if ( cChar == cCurChar ){return TRUE;}return FALSE;
}//只比较字符, 不迁移str的index
E_BOOL_TYPE MatchCharInStr_purely(char cChar, PT_STRING_OBJ ptStrObj)
{char cCurChar = GetCharFromStr_purely(ptStrObj);if ( cCurChar == '\0' ){return FALSE;}if ( cChar == cCurChar ){return TRUE;}return FALSE;
}//比较Optional字符, 比较成功迁移str的index
E_BOOL_TYPE MatchOptCharsInStr(char* szOptChars, PT_STRING_OBJ ptStrObj)
{char cCurChar = GetCharFromStr_purely(ptStrObj);if ( cCurChar == '\0' ){return FALSE;}// 字符串中含有字符if ( strchr(szOptChars, cCurChar) ){ptStrObj->iIndex++;return TRUE;}return FALSE;
}/* ------------------------------ single layer xml parsing --------------------------------- */// current is state null, begintag state can be triggered?
E_BOOL_TYPE IsEventTriggered_StateNull_Jump2StartTag(char cCurrentChar)
{if ( '<' == cCurrentChar ){return TRUE;}    return FALSE;
}// current is state null, begintag event is triggered, now do some action
E_RETURN_TYPE EventHandler_StateNull_Jump2StartTag(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead)
{// discard current char, do not revise state machine
}// current is state null, begintag state can not be triggered?
E_BOOL_TYPE IsEventTriggered_StateNull_KeepState(char cCurrentChar)
{if ( '<' != cCurrentChar ){return TRUE;}    return FALSE;
}// current is state null, begintag event is not triggered, now do some action
E_RETURN_TYPE EventHandler_StateNull_KeepState(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead)
{// discard current char, do not revise state machine
}// current is state start tag, can the event jumps to Content state be triggered?
E_BOOL_TYPE IsEventTriggered_StateStartTag_Jump2Content(char cCurrentChar)
{if ( '>' == cCurrentChar ){return TRUE;}    return FALSE;
}// current is state starttag, jump2Content event is triggered, now do some action
E_RETURN_TYPE EventHandler_StateStartTag_Jump2Content(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead)
{// discard current char, do not revise state machine
}// current is state start tag, can the event keeps this state be triggered?
E_BOOL_TYPE IsEventTriggered_StateStartTag_KeepState(char cCurrentChar)
{if ( '>' != cCurrentChar ){return TRUE;}    return FALSE;
}// current is state starttag, keepState event is triggered, now do some action
E_RETURN_TYPE EventHandler_StateStartTag_KeepState(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead)
{// save current char to state machineAddChar2StrObj(&ptStateMachine->tStartTag, cCurrentChar);
}// current is state start tag, can the event jumps to Content state be triggered?
E_BOOL_TYPE IsEventTriggered_StateContent_Jump2EndTag(char cCurrentChar)
{if ( '<' == cCurrentChar ){return TRUE;}    return FALSE;
}// current is state starttag, jump2Content event is triggered, now do some action
E_RETURN_TYPE EventHandler_StateContent_Jump2EndTag(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead)
{// discard current char, do not revise state machine
}// current is state start tag, can the event keeps this state be triggered?
E_BOOL_TYPE IsEventTriggered_StateContent_KeepState(char cCurrentChar)
{if ( '<' != cCurrentChar ){return TRUE;}    return FALSE;
}// current is state starttag, keepState event is triggered, now do some action
E_RETURN_TYPE EventHandler_StateContent_KeepState(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead)
{// save current char to state machineAddChar2StrObj(&ptStateMachine->tContent, cCurrentChar);
}// current is state start tag, can the event jumps to Content state be triggered?
E_BOOL_TYPE IsEventTriggered_StateEndTag_Jump2Null(char cCurrentChar)
{if ( '>' == cCurrentChar ){return TRUE;}    return FALSE;
}// current is state starttag, jump2Content event is triggered, now do some action
E_RETURN_TYPE EventHandler_StateEndTag_Jump2Null(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead)
{
MyPrintf("EventHandler_StateEndTag_Jump2Null enter");// discard current char, compare starttag with endtag// if starttag equals to endtag, add tagName-content into listif ( !strcmp(ptStateMachine->tStartTag.szStr, ptStateMachine->tEndTag.szStr) ){Insert2List(ptHead, ptStateMachine->tStartTag.szStr, ptStateMachine->tContent.szStr);}else{MyPrintf("start tag(%s) do not match end tag(%s), ", ptStateMachine->tStartTag.szStr, ptStateMachine->tEndTag.szStr);}FreeXMLParseStateMachine(ptStateMachine);InitXMLParseStateMachine(ptStateMachine);
}// current is state start tag, can the event keeps this state be triggered?
E_BOOL_TYPE IsEventTriggered_StateEndTag_KeepState(char cCurrentChar)
{if ( '>' != cCurrentChar ){return TRUE;}    return FALSE;
}// current is state starttag, keepState event is triggered, now do some action
E_RETURN_TYPE EventHandler_StateEndTag_KeepState(char cCurrentChar, PT_XML_PARSE_STATE_MACHINE ptStateMachine, PT_NODE ptHead)
{// save current char to state machineAddChar2StrObj(&ptStateMachine->tEndTag, cCurrentChar);
}void InitXMLParseStateMachine(PT_XML_PARSE_STATE_MACHINE ptXMLParseStateMachine)
{ptXMLParseStateMachine->eParseState = XML_PARSE_STATE_NULL;InitStrObjStruct(&(ptXMLParseStateMachine->tStartTag), "", TRUE);InitStrObjStruct(&(ptXMLParseStateMachine->tEndTag), "", TRUE);InitStrObjStruct(&(ptXMLParseStateMachine->tContent), "", TRUE);
}void FreeXMLParseStateMachine(PT_XML_PARSE_STATE_MACHINE ptXMLParseStateMachine)
{FreeStrObjMem(&(ptXMLParseStateMachine->tStartTag));FreeStrObjMem(&(ptXMLParseStateMachine->tEndTag));FreeStrObjMem(&(ptXMLParseStateMachine->tContent));
}int GetStateChangeRuleIndex(E_XML_PARSE_STATE eState, char cCurrentChar)
{int iIndex = 0;int iLen = sizeof(g_stateChangeTable)/sizeof(T_STATE_CHANGE_RULE); for ( iIndex=0; iIndex<iLen; iIndex++ ){if ( eState == g_stateChangeTable[iIndex].eCurrentState ){if ( g_stateChangeTable[iIndex].isEventTriggered(cCurrentChar) ){return iIndex;}}}return -1;
} // main function for xml parsing
void ParseXMLStr(char* szXMLStr, PT_NODE ptHead)
{T_STRING_OBJ tXmlStr;T_XML_PARSE_STATE_MACHINE tXmlMachine;PT_XML_PARSE_STATE_MACHINE ptXmlMachine = &tXmlMachine;int iIndex = 0;char cChar = '\0';InitStrObjStruct(&tXmlStr, szXMLStr, FALSE);InitXMLParseStateMachine(&tXmlMachine);while( (cChar = GetCharFromStr(&tXmlStr)) ){MyPrintf("current eParseState = %d", ptXmlMachine->eParseState);MyPrintf("input char = %c", cChar);iIndex = GetStateChangeRuleIndex(ptXmlMachine->eParseState, cChar);MyPrintf("machine rule iIndex=%d", iIndex);if ( -1 != iIndex ){ptXmlMachine->eParseState = g_stateChangeTable[iIndex].eTransferState;MyPrintf("changed eParseState = %d\n", ptXmlMachine->eParseState);g_stateChangeTable[iIndex].eventhandler(cChar, ptXmlMachine, ptHead);}else{StopWithMsg("state machine run encounter error!");}}FreeXMLParseStateMachine(ptXmlMachine);
}// test xml parsing result
void TestXMLPasring(char* szXMLStr, T_XML_NODE xmlArr[])
{T_NODE tHead = {NULL,NULL,NULL};ParseXMLStr(szXMLStr, &tHead);PrintList(&tHead);AssertList(&tHead, xmlArr);MyPrintf("szXMLStr(%s) test ok!-----------------\n\n", szXMLStr);
}void TestXMLParseCase()
{// test one node postive caseT_XML_NODE xmlArr[] = {{"xx","yy"},{NULL,NULL}};TestXMLPasring("<xx>yy<xx>", xmlArr);// test one node negative caseT_XML_NODE xmlArr1[] = {{NULL,NULL}};TestXMLPasring("<xx>yy<KKxx>", xmlArr1);}int main(){//TestListCase();
    TestXMLParseCase();return 0;
}

转载于:https://www.cnblogs.com/lightsong/p/4824602.html

有限状态机与应用一例相关推荐

  1. 北航计算机组成原理课程设计-2020秋 PreProject-Logisim-2^n mod 5问题

    北航计算机学院-计算机组成原理课程设计-2020秋 PreProject-Logisim-2^n mod 5问题 本系列所有博客,知识讲解.习题以及答案均由北航计算机学院计算机组成原理课程组创作,解析 ...

  2. 一个小兔子的大数据见解2

    Big Data 阿里的大数据解决方案 MAXCOMPUTE DATAWORKS QUICKBI 1.Vmware增强 2. 1.1.VMware 虚拟网络设备 1.1.1.虚拟网卡.虚拟交换机 虚拟 ...

  3. 《Java150道面试题全集》

    本文转载他人,自留作笔记用,请尊重原创作者. 1.面向对象的特征有哪些方面? 答:面向对象的特征主要有以下几个方面: - 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两 ...

  4. Python语言的有限状态机实现样例

    #!/usr/bin/env python3class Connection(object):def __init__(self):self.change_state(ClosedConnection ...

  5. 确定有限状态机和非确定有限状态机详解 包含Java实现源码(Nondeterministic finite automata)

    本文将讲解确定有限自动状态机和非确定有限自动状态机的特点和区别.将结合图片例子重点讲解什么是非确定有限自动状态机.最后讲解如何将非确定状态机转换为确定的状态机.多图预警!! 有限自动状态机可以分为确定 ...

  6. JavaScript与有限状态机

    有限状态机(Finite-state machine)是一个非常有用的模型,可以模拟世界上大部分事物. 简单说,它有三个特征: * 状态总数(state)是有限的. * 任一时刻,只处在一种状态之中. ...

  7. FPGA中有限状态机的状态编码采用格雷码还是独热码?

    今天看<从算法设计到硬件逻辑的实现>这本电子书时,遇到了一个问题,就是有限状态机的编写中,状态编码是采用格雷码还是独热码呢?究竟采用哪一种编码呢? 采用独热码为什么节省许多组合电路? 等等 ...

  8. 对时序逻辑电路采用不同描述方式,ISE综合出来的电路(RTL Schematic)比较(以模5计数器为例)

    目录 前言 行为级描述 Verilog HDL设计代码为: ISE综合 RTL Schematic Technology Schematic 状态机描述状态转移图 Verilog HDL代码 测试文件 ...

  9. C# 3.0下有限状态机的一种优雅的实现

    C# 3.0下有限状态机的一种优雅的实现 实现状态机有多种模式,其中最灵活而强大的方式是通过迁移表来实现,该方式的缺点之一是需要编写大量小块代码去支持迁移表.而在C#3.0中,可以以一种非常优雅的方式 ...

最新文章

  1. [zz]Apache Thrift学习小记
  2. JMeter学习(六)集合点
  3. P1971 [NOI2011]兔兔与蛋蛋游戏
  4. apache配置解析php
  5. 一张图解释什么是遗传算法_遗传算法简介及代码详解
  6. CSS每日学习笔记(0)
  7. 软件设计师 - 函数依赖 和 范式
  8. zookeeper和eureka的对比
  9. c++ 正态分布如何根据x求y_knn实战:如何对手写数字进行识别?
  10. linux系统添加中文字体后不生效
  11. 斐讯K2 A6版SZU校园网刷机方法
  12. 图像检索代码python_python-图像检索
  13. linux下安装字体
  14. 龙芯2f笔记本安装debian错误--bzcat
  15. java鼠标经过代码_一段眼睛跟着鼠标转动的跟踪眼代码
  16. 元宇宙,小荷才露尖尖角
  17. 基于Python的头脑王者脚本(纯娱乐)
  18. 视频教程-Project-规划项目(基本操作)-Office/WPS
  19. 最老程序员创业开发实训10---Android---注册登录功能实现1
  20. 学习前端,需要掌握的单词集汇总

热门文章

  1. python时间复杂度和空间复杂度是指_时间复杂度和空间复杂度
  2. pytorch —— transforms图像增强(一)
  3. MAC系统下解决Teamviewers检测出商业限时问题
  4. 高效的Java集合框架GNU Trove的使用
  5. toj 4615 Tetrahedrons and Spheres
  6. git base , 版本合并:git的分支与合并的两种方法 - 方法1:git merge
  7. python父亲节符号_菲菲用python编程绘制的父亲节礼物
  8. html个人主页_前端性能优化实践 之 百度App个人主页优化
  9. windows installer没有正确安装_电脑还可以这样禁止软件自动安装,后悔知道得太晚...
  10. Centos7.6环境Docker安装Oracle19c企业版