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

当脚本只是一系列简单命令序列的时候,一个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 下测试通过。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值