如何嵌入脚本语言到你的系统中-Squirrel语言

为什么要嵌入脚本语言

        脚本编程速度更快.为什么?因为诸如内存自动管理和溢出检查等性能问题可以不用考虑。在更低级或非脚本语言中,内存及变量管理和数据结构等耗费人工,为解决一个给定问题需要大量代码,脚本语言的缺点是什么呢?脚本通常是解释执行的,速度相对慢,且运行时更耗内存。但是,它所带来的编写优势就远远超过了运行时的劣势,尤其是在当前程序员工资趋高和硬件成本趋低时。

介绍Squirrel语言

        Squirrel 是一种高级的命令式、 面向对象的编程语言,旨在成为一种轻量级脚本。Squirrel的作者是意大利人Alberto Demichelis,而SQUIRREL语法与C/C++很相似,因此Squirrel更适合C/C++ 程序员.

Squirrel在设计上就是要做到嵌入C/C++程序,因此,Squirrel虚拟机可以与C/C++工作在一个进程/线程当中,通过虚拟机的接口,C/C++的数据可以被嵌入的Squirrel代码访问,反之Squirrel的代码和数据也可以被C/C++完全控制。

如何嵌入Squirrel

        如下几个步骤:

                初始化

        例程中函数没有标注的为Squirrel的标准库函数,在Squirrel函数说明会介绍

Init_Script()
   {
     HSQUIRRELVM sqvm;//定义一个SQ虚拟机变量	
    sqvm = sq_open(1024); // 创建一个虚拟机VM,堆栈大小为1024
	sq_setprintfunc(sqvm, printfunc, errorfunc);	//设置打印函数,就是脚本中执行print函数,调用printfunc,errorfunc的C函数库.																											
	sq_pushroottable(sqvm); //将虚拟机根表压入堆栈

	sqstd_register_bloblib(sqvm);		//在给定的VM中初始化并注册blob库																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																																		
	sqstd_register_iolib(sqvm);	        //在给定的VM中初始化并注册io库																									
	sqstd_register_systemlib(sqvm);
	sqstd_register_mathlib(sqvm);
	sqstd_register_stringlib(sqvm);
	
	Register_Script_Func(SQ_Func, "Func");//注册C函数,脚本对应的函数名为Func 此为C函数
}

Register_Script_Func(SQFUNCTION f, const char *fname)	//f:为C函数指针	fname:脚本中对应的函数名字符串																																																																																																																																																																																		
{																																																																																																																																											
    sq_pushroottable(sqvm);    //虚拟机压入根表
    sq_pushstring(sqvm,fname,-1);		//压入把文件名压入字符串																																																																																						
    sq_newclosure(sqvm,f,0);            //将C函数f传递给它;新的Squirrel函数将被压入栈。
    sq_createslot(sqvm,-3);            //创建一个槽
    sq_pop(sqvm,1); //pops the root table  //弹出根表
    return 1;
}

SQ_Func(HSQUIRRELVM vm)
{
	DWORD data = 2;
	sq_pushinteger(vm, data); //函数的返回值压入堆栈
	return 1;
}

                装载脚本

装载脚本,编译.


SQInteger LoadScript(const char *sScript)
{
    int iR;
    if(*sScript)
    {
        sq_pushroottable(sqvm);//将当前根表压入到栈中
        sq_setcompilererrorhandler( sqvm,  CompileErrorHandle);//设置编译器错误处理函数CompileErrorHandle 为错误处理函数指针
        sq_newclosure(m_sqvm,RuntimeErrorHandle,0);//创建一个新的本机闭包,弹出n值将它们设置为新闭包的自由变量,并在栈中压入新闭包。
        sq_seterrorhandler(m_sqvm);//从栈弹出一个闭包或本机闭包,并将其设置为运行时错误处理程序。

        iR = sq_compilebuffer(m_sqvm,sScript,strlen(sScript),sScript,1);//从内存缓冲区编译一个脚本程序; 如果成功,则将编译后的脚本作为函数压入到栈中。
        if(iR>0)
        {
            iR = 0;
        }
        if(SQ_SUCCEEDED(iR))
	    {
            sq_push(sqvm,-2);//把当前虚拟机压入栈
            if(SQ_SUCCEEDED(sq_call(m_sqvm,1,SQFalse,SQTrue)))//调用闭包或原生闭包。
            {
                sq_remove(m_sqvm,SQFalse?-2:-1); //从栈中的任意位置移除元素-闭包
                sq_pop(m_sqvm,1);//弹出虚拟机
                return 1;
            }
        }
        sq_pop(m_sqvm,1); //弹出虚拟机
    }
    return 0;
}

                执行脚本

脚本已经加载,哪个函数是启动函数,还是要告诉虚拟机.

void  excuteFunc(char *sFunc)
{
    HSQUIRRELVM v = sqvm;
    SQInteger top = sq_gettop(v); //保存栈顶部索引
    sq_pushroottable(v); //压入根表
	sq_pushstring(v, _SC(sFunc), -1);//压入函数名称

    if(SQ_SUCCEEDED(sq_get(v,-2)))//从栈中弹出一个键,并对栈中位置idx处的对象执行get操作,并将结果压入到栈中。从全局表中获取字段'sFunc'
    {
        sq_pushroottable(v); //压入根表
        sq_call(v,1,SQFalse,SQTrue); //执行这个函数
    }
    sq_settop(v,top); /恢复原始堆栈位置
    return ;
}

                卸载脚本

sq_close(sqvm); 

相关的Squirrel函数说明

HSQUIRRELVM sq_open(SQInteger initialstacksize)
Parameters:    •initialstacksize (SQInteger) –堆栈中栈的大小(对象数)
Returns:    一个 squirrel 虚拟机句柄
Remarks:    返回的VM必须与sq_releasevm一起释放
创建一个包含在新执行栈中的squirrel VM的新实例。

void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc, SQPRINTFUNCTION errorfunc)
Parameters:    
    •v (HSQUIRRELVM) – 目标 VM
    •printfunc (SQPRINTFUNCTION) –指向print func的指针或NULL以禁用输出。
    •errorfunc (SQPRINTFUNCTION) –指向错误func的指针或NULL以禁用输出。
Remarks:    print func具有以下原型:
void printfunc(HSQUIRRELVM v,const SQChar *s,...)
设置虚拟机的打印功能。 内置函数':: print()'使用此函数输出文本。

void sq_pushroottable(HSQUIRRELVM v)
Parameters:v (HSQUIRRELVM) – 目标 VM
将当前根表压入到栈中

void sq_pushstring(HSQUIRRELVM v, const SQChar * s, SQInteger len)
Parameters:    
    •v (HSQUIRRELVM) –目标 VM
    •SQChar * s (const) –指向要压入的字符串的指针
    •len (SQInteger) – 字符串的长度
Remarks:    如果参数len小于0,VM将使用strlen(s)计算长度
在栈中压入一个字符串

void sq_newclosure(HSQUIRRELVM v, HSQFUNCTION func, SQInteger nfreevars)
Parameters:    
    •v (HSQUIRRELVM) – 目标 VM
    •func (HSQFUNCTION) – 指向本机函数的指针
    •nfreevars (SQInteger) – 自由变量数(可以是0)
创建一个新的本机闭包,弹出n值将它们设置为新闭包的自由变量,并在栈中压入新闭包。

SQRESULT sq_createslot(HSQUIRRELVM v, SQInteger idx)
Parameters:    
    •v (HSQUIRRELVM) – 目标 VM
    •idx (SQInteger) – 栈中目标表的索引
Returns:    SQRESULT
Remarks:    在表委托中调用_newslot元方法。 它只适用于table。
从栈中弹出一个键和一个值,并对栈中位置idx的表或类执行set操作,如果插槽不存在则将创建它

void sq_pop(HSQUIRRELVM v, SQInteger nelementstopop)
Parameters:    
    •v (HSQUIRRELVM) – 目标VM
    •nelementstopop (SQInteger) – 要弹出的元素数量
弹出栈中的n个元素

void sq_pushinteger(HSQUIRRELVM v, SQInteger n)
Parameters:    
    •v (HSQUIRRELVM) –目标 VM
    •n (SQInteger) –要压入的整数
将一个integer压入栈

void sq_setcompilererrorhandler(HSQUIRRELVM v, SQCOMPILERERROR f)
Parameters:    
        •v (HSQUIRRELVM) –  目标 VM
        •f (SQCOMPILERERROR) – 指向错误处理函数的指针
Remarks:如果参数f为NULL,则在编译器错误发生时不会调用函数。 编译器错误处理程序在友元VM之间共享.
设置编译器错误处理函数

void sq_seterrorhandler(HSQUIRRELVM v)
Parameters:    
    •v (HSQUIRRELVM) – 目标 VM
Remarks:错误处理程序由友元VM共享
从栈弹出一个闭包或本机闭包,并将其设置为运行时错误处理程序。

SQRESULT sq_compilebuffer(HSQUIRRELVM v, const SQChar* s, SQInteger size, const SQChar * sourcename, SQBool raiseerror)
Parameters:    
•v (HSQUIRRELVM) –  目标 VM
•SQChar* s (const) – 指向要编译的缓冲区的指针。
•size (SQInteger) – 在参数's'中传递的缓冲区的字符大小。
Returns:返回SQRESULT。 如果sq_compile失败,则不会在栈中压入任何内容。
Remarks:如果出现错误,该函数将调用sq_setcompilererrorhandler()设置的函数。
从内存缓冲区编译一个松鼠程序; 如果成功,则将编译后的脚本作为函数压入到栈中。

void sq_push(HSQUIRRELVM v, SQInteger idx)
Parameters:
    v (HSQUIRRELVM) – 目标 VM
    idx (SQInteger) – 栈中的索引要压入的值
将索引idx中的值压入栈

SQRESULT sq_call(HSQUIRRELVM v, SQInteger params, SQBool retval, SQBool raiseerror)
Parameters:    
    •v (HSQUIRRELVM) – 目标 VM
    •params (SQInteger) – 函数的参数数量
    •retval (SQBool) –如果为true,则该函数的返回值将压入栈中raiseerror (SQBool) –如果为true,如果在执行调用期间发生运行时错误,则vm将调用错误处理程序。
Returns:SQRESULT
Remarks:该函数弹出所有参数并将闭包留在栈中; 如果retval为true,则压入闭包的返回值。 如果通过sq_suspendvm()暂停执行该函数,则不会自动从栈中弹出闭包和参数。
调用闭包或原生闭包。

void sq_remove(HSQUIRRELVM v, SQInteger idx)
Parameters:
    v (HSQUIRRELVM) – 目标 VM
    idx (SQInteger) – 要删除的元素的索引
从栈中的任意位置移除元素

sSQInteger sq_gettop(HSQUIRRELVM v)
Parameters:v (HSQUIRRELVM) – 目标 VM
Returns:一个整数,表示栈顶部的索引
返回栈顶部的索引

void sq_settop(HSQUIRRELVM v, SQInteger v)
Parameters:    
    •v (SQInteger) – 目标 VM
    •v – 新栈顶的索引
调整栈大小,如果new top更大,那么当前顶部函数将压入空值。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值