⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cftanalyser.cpp

📁 与游戏,网络,输入法相关
💻 CPP
字号:
// 自定义格式化文本代码
// 作者: Janhail Luo
// 最后整理: 2003-03-03
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "CFT.h"
#include "CFTAnalyser.h"

#define CFTIsSpace(v)    (v==' '||v==0||v==9||v==10||v==13)

// 构造函数
CCFTAnalyser::CCFTAnalyser()
{
    m_Root.iType = 0;
    m_Root.pData = 0;
}

// 析构函数
CCFTAnalyser::~CCFTAnalyser()
{
    this->Clear();
}

// 初始化,
// szString是一个以0结尾的字符串,里面保存的是需要分析的字符串
// szName是一个以0结尾的字符串,里面保存这次分析的名字
// 返回true表是分析正确,返回false表是分析错误。
bool CCFTAnalyser::Init(const char* szString, const char* szName)
{
    if (szString==0)
        return false;

    // 清除旧的分析数据
    this->Clear();

    // 设置名字
    m_Root.strName = szName;

    // 开始分析
    return Analyse(szString);
}

// 清除
void CCFTAnalyser::Clear()
{
    Visitor(0, 0);
    m_Root.iType = 0;
    m_Root.listNode.clear();
    m_Root.listParm.clear();
    m_Root.pData = 0;
    m_Root.strName = "";
}

// 访问所有的字节点
// iType传入一个用户定义的参数
// pParam也是传入一个用户自定义的一个指针
void CCFTAnalyser::Visitor(int iType, void* pParam)
{
    for (int i=0; i<m_Root.listNode.size(); i++)
    {
        this->VisitItem(iType, 1, m_Root.listNode[i], pParam);
    }
}

// 访问某一个节点
// iType 是用户自定义的参数
// iDepth 是这个节点在节点树中的层次,根节点的层次为0
// pItem 是当前访问的节点
// pParam 是用户自定义的一个指针
void CCFTAnalyser::VisitItem(int iType, int iDepth,
               CCFTAnalyser::SItem* pItem, void* pParam)
{
    // 在访问一个节点之前调用这个虚函数
    this->OnVisitBefore(iType, iDepth, pItem, pParam);

    // 如果这个节点是一个标记节点就说明它有子节点
    if (pItem->iType==0)
    {
        // 访问所有的子节点
        for (int i=0; i<pItem->listNode.size(); i++)
        {
            // 递归调用访问函数
            this->VisitItem(iType, iDepth+1,
                pItem->listNode[i], pParam);
        }
    }else
    {
        // 在访问一个节点的时候调用这个虚函数
        this->OnVisit(iType, iDepth, pItem, pParam);
    }
    // 在访问一个节点之后调用这个虚函数
    this->OnVisitAfter(iType, iDepth, pItem, pParam);
}

// 访问一个节点前,这是一个虚函数,用户可以自定义这个函数
// iType 是用户自定义的参数
// iDepth 是这个节点在节点树中的层次,根节点的层次为0
// pItem 是当前访问的节点
// pParam 是用户自定义的一个指针
void CCFTAnalyser::OnVisitBefore(int iType, int iDepth,
                 CCFTAnalyser::SItem* pItem, void* pParam)
{
    map<CString, CString>::iterator it;
    CString str;
    switch (iType)
    {
#ifdef  _DEBUG
    // 默认-1为Debug的输出
    case -1:
        if (pItem->iType==0)
        {
            str = "<" + pItem->strName;
            it = pItem->listParm.begin();
            while (it!=pItem->listParm.end())
            {
                str += " " + (*it).first + "=" + (*it).second;
                it ++;
            }
            str += ">\n";
        }else
        {
            str = pItem->strName + "\n";
        }
        OutputDebugString(str);
        break;
#endif
    // 默认 0 为清空节点内容
    case 0:
        break;
    }
}

// 访问一个节点,这是一个虚函数,用户可以自定义这个函数
// iType 是用户自定义的参数
// iDepth 是这个节点在节点树中的层次,根节点的层次为0
// pItem 是当前访问的节点
// pParam 是用户自定义的一个指针
void CCFTAnalyser::OnVisit(int iType, int iDepth,
               CCFTAnalyser::SItem* pItem, void* pParam)
{
}

// 访问一个节点后,这是一个虚函数,用户可以自定义这个函数
// iType 是用户自定义的参数
// iDepth 是这个节点在节点树中的层次,根节点的层次为0
// pItem 是当前访问的节点
// pParam 是用户自定义的一个指针
void CCFTAnalyser::OnVisitAfter(int iType, int iDepth,
               CCFTAnalyser::SItem* pItem, void* pParam)
{
    switch (iType)
    {
#ifdef  _DEBUG
    // 默认-1为Debug的输出
    case -1:
        if (pItem->iType==0)
        {
            CString str;
            str = "</" + pItem->strName + ">\n";
            OutputDebugString(str);
        }
        break;
#endif
    // 默认 0 为清空节点内容
    case 0:
        this->OnDestroyItem(pItem);
        delete pItem;
        break;
    }
}

// 当分析程序碰到一个标记时调用这个函数
// iState 当前分析状态
// szStart 指向标记开始部分的指针
// szEnd 指向标记结束部分的指针
bool CCFTAnalyser::DoTag(int iState, char* szStart, char* szEnd)
{
    SItem* pNewItem;
    CString str(szStart, szEnd-szStart);

    switch (iState)
    {
    case 1:
        if (str[0]=='/')
        {
            // 如果是一个结束标记,并且和前面的开始标记匹配
            if (strcmp(((const char*)str)+1,
                m_Stack.top()->strName)==0)
            {
                m_Stack.pop();
            }else
            {
                // error
                return false;
            }
        }else
        {
            // 如果是一个开始标记就创造一个新的标记节点
            pNewItem = new SItem;
            pNewItem->iType = 0;
            pNewItem->pData = 0;
            pNewItem->strName = str;
            this->OnCreateItem(pNewItem);
            m_Stack.top()->listNode.push_back(pNewItem);
            m_Stack.push(pNewItem);
        }
        break;
    case 3:
        m_Name = str;
        break;
    case 5:
        break;
    case 7:
        m_Stack.top()->listParm[m_Name] = str;
        break;
    }
    return true;
}

// 当分析程序碰到一个属性时调用这个函数
// iState 当前分析状态
// szStart 指向标记开始部分的指针
// szEnd 指向标记结束部分的指针
bool CCFTAnalyser::DoItem(int iState, char* szStart, char* szEnd)
{
    CString str(szStart, szEnd-szStart);
    str.TrimRight();

    // 创造一个新的节点
    SItem* pNewItem = new SItem;

    pNewItem->iType = 1;
    pNewItem->pData = 0;
    pNewItem->strName = str;
    this->OnCreateItem(pNewItem);
    m_Stack.top()->listNode.push_back(pNewItem);
    return true;
}

// 分析字符串szStr
// 如果分析成功完成就返回true
// 否则返回 false
bool CCFTAnalyser::Analyse(const char* szStr)
{
    int                 iState;     // 当前状态
                                    // 0 自由状态
                                    // 1 文字状态
                                    // 2 开始一个标记'<'
                                    // 3 一个标记中
    int                 iTagState;  // 标记状态
                                    // 0 自由状态
                                    // 1 名字状态
                                    // 2 名字结束状态
                                    // 3 属性名字状态
                                    // 4 属性名字结束状态
                                    // 5 赋值符号状态
                                    // 6 赋值符号结束状态
                                    // 7 属性值状态
    bool                bTagBegin;  // true  是开始标记
                                    // false 是结束标记
    char*               pCurChar;   // 当前字符串的位置
    char*               pWordBegin; // 当前一段文字的开始位置
    char*               pWordEnd;   // 当前一段文字的结束位置

    // 清空堆栈的内容
    while(m_Stack.size())   m_Stack.pop();

    // 清除旧的所有内容
    this->Clear();

    // 当前位置标志为开始
    pCurChar = (char*)szStr;

    // 当前状态为自由
    iState = 0;

    // 把根元素压入堆栈
    m_Stack.push(&m_Root);

    while (*pCurChar)
    {
        switch (iState)
        {
        case 0: // 自由状态
            if (*pCurChar=='<')
            {
                // 如果碰到标记开始符号'<'
                // 就设置当前状态到开始一个标记的状态
                iState = 2;
                // 假设为开始标记
                bTagBegin = true;
                // 一段文字在此开始
                pWordBegin = pCurChar;
                // 一段文字到此结束
                pWordEnd = pCurChar;

            }else if (!CFTIsSpace(*pCurChar))
            {
                // 如果碰到一个非空格的文字
                // 就表示进入文字输入状态
                iState = 1;
                // 一段文字在此开始
                pWordBegin = pCurChar;

            }
            break;

        case 1: // 文字状态
            if (*pCurChar=='<')
            {
                // 如果碰到标记开始符号'<'
                // 就设置当前状态到开始一个标记的状态
                iState = 2;
                // 假设为开始标记
                bTagBegin = true;
                // 一段文字到此结束
                pWordEnd = pCurChar;

                if (pWordEnd>pWordBegin)
                {
                    this->DoItem(iState, pWordBegin, pWordEnd);
                }
            }

            break;

        case 2: // 开始一个标记'<'
            if (*pCurChar=='/')
            {
                // 设置当前标记是一个结束标记
                bTagBegin = false;
                // 表示进入标记输入状态
                iState = 3;
                // 设置标志状态为输入标记名字状态
                iTagState = 1;
                // 一段文字在此开始
                pWordBegin = pCurChar;

            }else if (!CFTIsSpace(*pCurChar))
            {
                // 如果碰到一个非空格的文字
                // 就表示进入标记输入状态
                iState = 3;
                // 设置标志状态为输入标记名字状态
                iTagState = 1;
                // 一段文字在此开始
                pWordBegin = pCurChar;

            }
            break;

        case 3: // 一个标记中
            if (iTagState<10)
            {
                if (*pCurChar=='<')
                {
                    // 如果碰到标记开始符号'<'
                    // 就说明文档格式出错
                    return false;

                }else if (*pCurChar=='>')
                {
                    // 如果碰到标记结束符号'>'
                    // 就说明这个标记结束
                    // 跳到结束标记状态
                    iState = 0;
                    // 一段文字到此结束
                    pWordEnd = pCurChar;

                    if (pWordEnd>pWordBegin)
                    {
                        DoTag(iTagState, pWordBegin, pWordEnd);
                    }

                }else if (*pCurChar=='=')
                {
                    if (iTagState==3 || iTagState==4)
                    {
                        // 一段文字到此结束
                        pWordEnd = pCurChar;
                        if (iTagState==3 && pWordEnd>pWordBegin)
                        {
                            DoTag(iTagState, pWordBegin, pWordEnd);
                        }
                        pWordBegin = pCurChar;
                        iTagState = 5;
                        continue;

                    }else if (iTagState==5)
                    {
                        iTagState = 6;
                        pWordBegin = pCurChar;

                    }else
                    {
                        // 其他状态出现'='都是错误
                        return false;

                    }

                }else if (CFTIsSpace(*pCurChar))
                {
                    if (iTagState==1 || iTagState==3
                        || iTagState==5 || iTagState==7)
                    {
                        // 一段文字到此结束
                        pWordEnd = pCurChar;
                        if (pWordEnd>pWordBegin)
                        {
                            DoTag(iTagState, pWordBegin, pWordEnd);
                        }
                        iTagState ++;
                        if (iTagState==8)
                            iTagState = 2;
                        continue;
                    }

                }else
                {
                    if (iTagState==0 || iTagState==2
                        || iTagState==4 || iTagState==6)
                    {
                        // 状态变化
                        iTagState += 1;
                        if (*pCurChar=='"')
                        {
                            // 转换到引号内状态
                            iTagState += 10;
                            pWordBegin = pCurChar+1;
                        }else
                        {
                            pWordBegin = pCurChar;
                            continue;
                        }
                    }

                }
            }else
            {
                if (*pCurChar=='"')
                {
                    // 如果在双引号中
                    if (pCurChar[1]=='"')
                    {
                        // 如果下一个字符也是双引号
                        // 说明这个是转意字符
                        pCurChar ++;
                    }else
                    {
                        iTagState -= 10;
                        pWordEnd = pCurChar;
                        if (pWordEnd>pWordBegin)
                        {
                            DoTag(iTagState, pWordBegin, pWordEnd);
                        }
                        // 转换到引号外状态
                        iTagState ++;
                        if (iTagState==8)
                            iTagState = 2;
                    }
                }
            }

            if (*pCurChar=='>')
            {
                // 一段文字在此开始
                pWordBegin = pCurChar;
            }
            break;
        }
        pCurChar ++;
    }
#ifdef _DEBUG
    Visitor(-1, 0);
#endif
    return true;
}

// 当创建一个新的节点的时候就会调用这个函数
// pItem 当前创建的节点的指针
void CCFTAnalyser::OnCreateItem(CCFTAnalyser::SItem* pItem)
{
}

// 当销毁一个节点的时候就会调用这个函数
// pItem 当前销毁的节点的指针
void CCFTAnalyser::OnDestroyItem(CCFTAnalyser::SItem* pItem)
{
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -