Show Changes Show Changes
Edit Edit
Print Print
Recent Changes Recent Changes
Subscriptions Subscriptions
Lost and Found Lost and Found
Find References Find References
Rename Rename
Administration Page Administration Page
Topic Locks Topic Locks

Search

History

9/4/2011 4:57:03 PM
-213.37.39.29
9/4/2011 4:56:24 PM
-213.37.39.29
9/4/2011 4:54:42 PM
-213.37.39.29
9/4/2011 4:53:41 PM
-213.37.39.29
9/4/2011 4:48:14 PM
-213.37.39.29
List all versions List all versions

RSS feed for the SquirrelWiki namespace

嵌入入门
.

Check out the formatting tips on the right for help formatting and making links.

Use the template below:

Summary

这个教程一步步解释了如何构建一个最小的Squirrel嵌入应用程序,载入和运行脚本。

首先,让我们看一下下面的脚本和C代码,等一下我会详细解释它们是干什么的。

Squirrel 代码

    function foo(i, f, s) 
    { 
        print("Called foo(), i = " + i + ", f = " + f + ", s = '" + s + "'"); 
    } 

还有这是 C 代码

C 代码

    #include <stdarg.h> 
    #include <stdio.h> 


    #include <squirrel.h> 
    #include <sqstdio.h> 
    #include <sqstdaux.h> 


    #ifdef _MSC_VER
    #pragma comment(lib, "squirrel.lib")
    #pragma comment(lib, "sqstdlib.lib")
    #endif


    #ifdef SQUNICODE 
    #define scvprintf vwprintf 
    #else 
    #define scvprintf vprintf 
    #endif 


    void printfunc(HSQUIRRELVM v, const SQChar *s, ...) 
    { 
        va_list arglist; 
        va_start(arglist, s); 
        scvprintf(s, arglist); 
        va_end(arglist); 
    } 


    void call_foo(HSQUIRRELVM v, int n, float f, const SQChar *s)
    {
        int top = sq_gettop(v);            // 在调用函数前保存栈大小
        sq_pushroottable(v);               // push全局表
        sq_pushstring(v, _SC("foo"), -1);
        if(SQ_SUCCEEDED(sq_get(v, -2)))    // 从全局表中获取'foo'
        { 
            sq_pushroottable(v);           // push 'this' (这里指的是全局表)
            sq_pushinteger(v, n); 
            sq_pushfloat(v, f);
            sq_pushstring(v, s, -1);
            sq_call(v, 4, 0, 0);           // 调用函数
        }


        sq_settop(v, top);                 // 恢复栈大小
    }


    int main(int argc, char* argv[]) 
    { 
        HSQUIRRELVM v; 
        v = sq_open(1024);                 // 创建一个 VM ,初始化栈大小为1024 


        sqstd_seterrorhandlers(v);


        sq_setprintfunc(v, printfunc, NULL); //设置打印函数


        sq_pushroottable(v);               //push根表(脚本将要存储的全局环境)
        if(SQ_SUCCEEDED(sqstd_dofile(v, _SC("test.nut"), 0, 1))) // 如果有,输出语法错误
        {
            call_foo(v, 1, 2.5, _SC("teststring"));
        }


        sq_pop(v,1);                       //pop根表
        sq_close(v); 


        return 0; 
    } 

初始化 Squirrel

你首先要做的就是创建一个虚拟机(VM)

    HSQUIRRELVM v = sq_open(1024);

1024 就是初始栈大小

Squirrel栈会自动增加,所以这个值只是一个给VM的参考值

Squirrel 允许你定义自己的错误处理函数,这个例子使用了标准IO库中预制的。

    sqstd_seterrorhandlers(v);

为了能够使用像 print() 这样的函数来输出一些文字,为VM提供一个打印函数是非常必要的。

    sq_setprintfunc(v, printfunc, NULL); //设置打印函数

而这里就是打印函数 printfunc 的定义

    void printfunc(HSQUIRRELVM v, const SQChar *s, ...) 
    { 
        va_list arglist; 
        va_start(arglist, s); 
        scvprintf(s, arglist); 
        va_end(arglist); 
    } 

第三个参数 NULL 告诉VM不需要任何自定错误处理函数。

运行脚本

Squirrel 提供了一个底层API来从任何媒体文件中编译和运行脚本。

无论如何,有90%的情况下,你想运行的脚本只是一个简单的文本文件,而且在编译后你就想马上运行它。

最简单的方法就是使用标准IO库(sqstdio.h)。

sqstd_dofile 编译并且运行一个脚本.

    sq_pushroottable(v);
    sqstd_dofile(v, "myscript.nut",0); 

在运行脚本期间, sqstd_dofile 将在栈顶对象(这里代表根表)作为 this 使用。

从 C++ 调用 Squirrel 函数

Squirrel脚本中,我们作为举例的函数叫 foo

为了调用这个函数,我们首先要检索到它并且将它放到栈中。

因为这个函数是在全局范围内声明的,所以是存放在根表中。

    void call_foo(HSQUIRRELVM v, int n, float f, const SQChar *s)
    {
        int top = sq_gettop(v);            // 在调用函数前保存栈大小
        sq_pushroottable(v);               // push全局表
        sq_pushstring(v, _SC("foo"), -1);
        if(SQ_SUCCEEDED(sq_get(v, -2)))    // 从全局表中获取'foo'
        { 
            sq_pushroottable(v);           // push 'this' (这里指的是全局表)
            sq_pushinteger(v, n); 
            sq_pushfloat(v, f);
            sq_pushstring(v, s, -1);
            sq_call(v, 4, 0, 0);           // 调用函数
        }


        sq_settop(v, top);                 // 恢复栈大小
    }

call_foo 调用函数 foo,并且传入一个integer, float 和 string 作为参数。

让我们一行一行来分析。

首先它记录了当前栈大小,这是为了在调用结束之后好清理。

        int top = sq_gettop(v);

放入根表,函数就是从这里获取的。

        sq_pushroottable(v);
负数索引 对象
-1 根表
... ...

栈内数据

将字符串 "foo" 放入,在这里代表我们将要调用的函数的slot名。

        sq_pushstring(v,_SC("foo"),-1);

参数-1指定VM将要自动计算字符串长度。

负数索引 对象
-1(顶) "foo"
-2 根表
... ...

栈内数据

然后获取函数

        if(SQ_SUCCEEDED(sq_get(v,-2)))

函数 sq_get 将会从栈中拿出(pop)一个对象(这里代表了字符串"foo")并且将它作为关键字从栈顶-2位

置(在这里代表根表)获取对象。如果sq_get成功,则将结果放入栈中(这里结果指的便是 foo 函数)。

负数索引 对象
-1(顶) function foo(){}
-2 根表
... ...

站内数据 在调用 sq_get 之后

现在向栈中放入函数的参数。根表被再一次放入,作为 this 参数使用。Squirrel函数总是有一个隐含参数 this

就像C++类成员一样)。

    sq_pushroottable(v);
    sq_pushinteger(v,n); 
    sq_pushfloat(v,f);
    sq_pushstring(v,s,-1);
负数索引 对象
-1(顶) string
-2 float
-3 integer
-4 根表
-5 function foo(){}
-6 根表
... ...

栈内数据

最后 sq_call 函数被调用了。它执行实际的调用。

    sq_call(v,4,0,0); 

4 表示被调用函数有四个参数(this, integer, float, string)。

Squirrel将会拿出4个参数然后连接。然后栈顶就变成了那个函数对象。

第三个参数0告诉Squirrel它将调用的那个函数无返回值。如果不是0的话将会让Squirrel将函数返回值放入栈顶。

第四个参数0告诉Squirrel当出现运行时错误时不要调用错误处理函数。

负数索引 对象
-1(顶) function foo(){}
-2 根表
... ...

栈内数据 调用 sq_call 之后

函数已经被执行了,所以我们现在重置栈大小到初始状态。

    sq_settop(v,top); //恢复初始栈状态

清理

之前我们放入了为了执行 sqstd_dofile 向栈中放入了根表,现在是时候把它删除了。

    sq_pop(v,1); 

在程序最后我们删除Squirrel VM。

    sq_close(v); 

这一步释放了所有先前分配空间。

Not logged in. Log in

squirrel's community wiki

This is FlexWiki, an open source wiki engine.

Change Style

Recent Topics