现在的位置: 首页 > 综合 > 正文

在Lua中实现汇编中的跳转语句Goto

2013年08月11日 ⁄ 综合 ⁄ 共 4131字 ⁄ 字号 评论关闭

当脚本只是一系列简单命令序列的时候,一个Goto语句用起来会非常方便,比如可以这样写

 

--开始

Print("这是1");

Print("这是2");

Goto("开始");

 

这是个无限循环,可以随时跳转,很方便,看起来也很清晰。

 

我基于LuaPlus实现了一个,代码如下:

 

/*
 *    /file    CmdScript.h
 *    /brief    基于命令式的Lua脚本对象
 *    /author    cloud
 *    /date    2010-3-15
 */
#ifndef _CLOUD_CMD_SCRIPT_H_
#define _CLOUD_CMD_SCRIPT_H_

#include <LuaPlus.h>
#include <iostream>
#include <string>
#include <map>
#include <windows.h>

using namespace LuaPlus;

class CCmdScript
{
public:
    CCmdScript();

    ~CCmdScript();

    /*
     *    /brief 在此成员内向Lua注册函数,重载此方法,注册自己的函数
     *    /return 出错返回false
     */
    virtual bool Register();

    /*
     *    /brief 解析指定的脚本文件,读取每一行,并做映射
     *    /return 返回此脚本文件的行数,小于0,解析失败
     */
    int ParseFile(std::string strFile);

    /*
     *    /brief 执行一个指定的字符串
     *    /return 返回错误消息,未出错,返回空字符串
     */
    std::string DoLineByIndex(int index);

    /*
     *    /brief 将导出的脚本函数,跳转到指定行
     */
    int Lua_Goto(LuaState* state);

    int GetNextLineIndex();

    /*
     *    /brief 获取当前脚本文件总共的行数
     */
    int GetSumLine();

    bool RunFile(std::string strFile);

    /*LuaPlus State对象*/
    LuaStateOwner                m_state;
   
private:
    /*行号和脚本命令的映射*/
    std::map<int,std::string>    m_mapLine;

    /*当前脚本行的指针*/
    int                            m_iCurrLine;

    std::string                    m_strFile;

    HANDLE                        m_hThread;
};

#endif

 

 

/*
 *    /file    CmdScript.cpp
 *    /author    cloud
 *    /date    2010-3-15
 */

#include "CmdScript.h"
#include <fstream>

UINT WINAPI ScriptThread(void* p);

int Lua_Print(LuaState* state)
{
    LuaStack args(state);
    const char* szmsg = args[1].GetString();

    printf("%s/n",szmsg);
    ::Sleep(1000);
    return 0;
}

CCmdScript::CCmdScript():m_iCurrLine(1)
{
    Register();
}

CCmdScript::~CCmdScript()
{
    ::TerminateProcess(m_hThread,-1);
    ::CloseHandle(m_hThread);

    LuaState::Destroy(m_state);   
}

bool CCmdScript::Register()
{
    m_state->GetGlobals().Register("Goto",*this,&CCmdScript::Lua_Goto);
    m_state->GetGlobals().Register("Print",Lua_Print);

    return true;
}

int CCmdScript::ParseFile(std::string strFile)
{
    m_strFile = strFile;
    std::ifstream file;
    file.open(m_strFile.c_str(),std::ios_base::in);

    if(!file) return false;

    int indexLine = 1;

    while(file){
        std::string strLine;
        std::getline(file,strLine);
        m_mapLine[indexLine] = strLine;

        indexLine ++;
    }
    file.close();

    return m_mapLine.size();
}

std::string CCmdScript::DoLineByIndex(int index)
{
    std::string strRet;

    std::map<int,std::string>::iterator it = m_mapLine.find(index);

    //未找到指定的行
    if(it == m_mapLine.end()) return strRet;

    std::string strLine = it->second;

    int iRet = m_state->DoString(strLine.c_str());

    m_iCurrLine ++;

    return strRet;
}

int CCmdScript::Lua_Goto(LuaState* state)
{
    //printf("This is CCmdScript::Lua_Goto! this=0x%X/n",this);
    LuaStack    args(state);
    std::string strMark = args[1].GetString();
    strMark = "--"+strMark;
   
    bool bFound = false;

    //遍历map,找到匹配的行
    for(std::map<int,std::string>::iterator it = m_mapLine.begin();it != m_mapLine.end();it++){
        if(it->second == strMark){
            //修改对象当前行号
            m_iCurrLine = it->first;
            bFound = true;
            break;
        }
    }
    //找到,就返回1,否则,返回0
    state->PushInteger((int)bFound);

    return 1;
}

int CCmdScript::GetNextLineIndex()
{
    return m_iCurrLine;
}

int CCmdScript::GetSumLine()
{
    return m_mapLine.size();
}

bool CCmdScript::RunFile(std::string strFile)
{
    ParseFile(strFile);

    m_hThread = ::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ScriptThread,(void*)this,0,0);
    if(m_hThread == NULL) return false;
    return true;
}

/*
 *    /brief 脚本线程
 */
UINT WINAPI ScriptThread(void* p)
{
    CCmdScript* pScript = (CCmdScript*)p;

    while(1){
        //先检查脚本是否结束了
        int iNext = pScript->GetNextLineIndex();
        int iMax = pScript->GetSumLine();
        if(iNext>iMax) return 0;

        pScript->DoLineByIndex(iNext);
    }
    return 0;
}

 

写个测试程序,

 

#include "CmdScript.h"

#pragma comment(lib,"LuaPlusLib_1100.lib")

class MyScript : public CCmdScript
{
public:
    MyScript(){Register();}
    ~MyScript(){}

    virtual bool Register();
};

int MyAdd(int a,int b)
{
    printf("This is MyAdd/n");
    return 0;
}

bool MyScript::Register()
{
    m_state->GetGlobals().RegisterDirect("MyAdd",MyAdd);
   
    return true;
}

int main(int argc,char** argv)
{
    MyScript script;
   
    script.RunFile("test.lua");

    system("pause");
    return 0;
}

 

现在执行上面写的脚本

 

--开始

Print("这是1");

Print("这是2");

Goto("开始");

 

这是个无限循环,VS2005 XP SP3 下测试通过。

抱歉!评论已关闭.