自己解析代码,我想我有点疯了。有了ANGELSCRIPT和TINYXML,还用得着自己再去写解析文本的代码吗?当然,做为一个能让大家使用的AVG引擎脚本,显然。。。。。。,可以让用户直接用ANGELSCRIPT用类C++的语句来写,也应该有一些简化一些的,可以让没学过编程的人也可以轻松使用的命令组,这样就需要自己定义文本的格式,并解析了。
一个建议:使用UNICODE字符。因为UNICODE字符所有字符的长度都是固定的,这样就不会出现将汉字的一半解析成某个特殊字符的极端情况了。
(1)文本解析的核心类:CTokenizer
作为文本解析代码的核心,这个类最重要的属性就是std::vector< CToken * > m_TokenList,而最重要的方法就是TokenizeString.其功能是将读入的一串字符解析为单独的Token(标记)并存入m_TokenList.
TokenizeString的原理是:定义一个int变量curPos,记录当前读取到的字符串位置。然后在curPos小于字符串长度时循环。
每次循环读取两个字符,是的是两个字符,不是一个字符(因为有一些标志由两个字符构成如“//”)。
在循环内使用了状态机的机制(当然是比较原始的一种实现状态机的方法),用switch语句。
while( curPos < 字符串长度 )
{
//读取两个字符
switch( curState )//curState是一个TOKSTATE变量,而TOKSTATE是一个ENUM类型,定义了几种状态,不同的状态有不同的处理字符的功能。
{
case 空格符状态://这一状态必须放在第一个
case 某种状态:
}
}
当循环完成,整个字符串,就被拆成了若干的字符串并转成CToken类的实例,存入了m_TokenList中。
那么状态有几种呢。定义一个枚举 enum TOKSTATE { TKS_INWHITE, TKS_INTEXT, TKS_INQUOTES, TKS_INSINGLECOMMENT, TKS_INMULTICOMMENT}
TKS_INWHITE//默认状态
TKS_INTEXT//文本状态
TKS_INQUOTES//引用状态即“‘’”
TKS_INSINGLECOMMENT//单行注释即“//”
TKS_INMULTICOMMENT//多行注释状态,即“/**/”
可以根据自己的需要扩充状态
TKS_INWHITE默认状态是第一次循环时第一个处理的状态,也是初始化时默认的状态,主要处理(按顺序):
(1)检查当前字符是否是默认的定界符(如“/n”,要自己设定一个定界符字符串),调用IsDelimiter方法(检查是否是默认的定界符,并进行一些操作)并返回重新循环
(2)检查当前字符是否是一个组合标记的一部份,如遇到“/”,则检查是否后面还有一个“/”。如果确认是组合标记,将状态置为该标志对应的状态(如上面的TKS_INSINGLECOMMENT单行注释状态)。并返回,重新循环
(3)检查是否一些特殊的标记,如果是,存入m_TokenList。并返回,重新循环。
(4)如果都不是,说明读入的当前字符是一个文本,则置当前状态为TKS_INTEXT。
TKS_INTEXT文本状态,主要处理文本(按顺序)
(1)检查当前字符是否是定界符或特殊字符(特殊字符包括“{”“}”等),如果是将终止TKS_INTEXT状态,并将字符串缓存中的字符串作为标记存入m_TokenList,将状态重置为TKS_INWHITE状态,变量curPos减1(该字符不放入字符串缓存)。同时返回,重新循环。
(2)如果不是定界符或特殊字符,则作为字符处理,将当前字符加入字符串缓存。
TKS_INQUOTES引用状态(找到一个引号):
(1)如果是引号,存入m_TokenList,如果不是,存入字符串缓存。置状态为TKS_INWHITE
TKS_INSINGLECOMMENT(单行注释符状态):
(1)检测当前字符是否是'/n',如果是,则表明已到单行注释的尾部,行计数器m_curLine加1。置状态为TKS_INWHITE
TKS_INMULTICOMMENT(多行注释符状态):
(1)检测当前字符是否是‘/’,且前一个字符是‘*’,如果是,则已到多行注释尾部,置状态为TKS_INWHITE
完整代码(摘自游戏编程精粹)
// Tokenize this String.
bool CTokenizer::TokenizeString( const char *strString, unsigned long ulLen, unsigned long ulFlags, const char *strDelims )
{
int iNumDelims = (int)strlen( strDelims );//计算定界行的长度
// Destroy any tokens that may have already existed.做了一些初始化的工作
DestroyTokens();
m_iCurrentToken = 0;
TOKSTATE CurrentState = TKS_INWHITE;
CToken *pTok = NULL;
int iCurPos = 0;
char strTempBuff[ 512 ] = { 0 };
int iTempBuffSize = 0;
char byCurChar;
char byNxtChar;
bool bSpecialChar = false;
/
while ( iCurPos < (int)ulLen )
{
byCurChar = strString[ iCurPos++ ];
byNxtChar = strString[ iCurPos ];
<